16 KiB
RabbitMQ Barong Event API
Overview of RabbitMQ details
Barong submits all events into three exchanges depending on event category (read next).
The exchange name consists of three parts:
-
application name (typically
barong) -
fixed keyword
events. -
category of event, like
system(generic system event),model(the attributes of some record were updated)
The routing key looks like user.password.reset.token, user.created.
The event name matches the routing key but with event category appended at the beginning, like system.user.password.reset.token, market.user.created.
Overview of RabbitMQ message
Each produced message in Event API is JWT (complete format).
This is very similar to Management API.
The example below demonstrates both generation and verification of JWT:
require "jwt-multisig"
require "securerandom"
jwt_payload = {
iss: 'barong',
jti: SecureRandom.uuid,
iat: Time.now.to_i,
exp: Time.now.to_i + 60,
event: event_payload
}
private_key = OpenSSL::PKey.read(Base64.urlsafe_decode64(private_key)
algorithm = 'RS256'
jwt = JWT::Multisig.generate_jwt jwt_payload, \
{ barong: private_key },
{ barong: algorithm }
Kernel.puts "GENERATED JWT", jwt.to_json, "\n"
verification_result = JWT::Multisig.verify_jwt jwt.deep_stringify_keys, \
{ barong: public_key }, { verify_iss: true, iss: "barong", verify_jti: true }
decoded_jwt_payload = verification_result[:payload]
Kernel.puts "MATCH AFTER VERIFICATION: #{jwt_payload == decoded_jwt_payload}."
The RabbitMQ message is stored in JWT field called event.
Overview of Event API message
The typical event looks like (JSON):
event: {
record: {
foo: "ID30DD0DD986",
bar: "example@barong.io",
baz: "member",
qux: 0
},
name: "model.user.created"
}
The field event[:name] contains event name (same as routing key).
The fields foo, bar, baz, qux (example) are fields which carry useful information.
Barong Event API messages
Format of model.user.created event
event: {
record: {
uid: "ID30DD0DD986",
email: "example@barong.io",
role: "member",
level: 0,
otp: false,
state: "pending",
created_at: "2019-01-28T08:35:29Z",
updated_at: "2019-01-28T08:35:29Z"
},
name: "model.user.created"
}
| Field | Description |
|---|---|
record |
Created user up-to-date attributes. |
Format of model.user.updated event
event: {
record: {
uid: "ID30DD0DD986",
email: "example@barong.io",
role: "member",
level: 1,
otp: false,
state: "pending",
created_at: "2019-01-28T08:35:29Z",
updated_at: "2019-01-28T08:35:29Z"
},
changes: {
level: 0
}
name: "model.user.updated"
}
| Field | Description |
|---|---|
record |
Created user up-to-date attributes. |
changes |
The changed user attributes and their values. |
Format of model.user.created event
event: {
record: {
address:"Illinois",
city:"New Garfieldbury",
country:"COD",
dob:"1984-05-22",
first_name:"Irina",
last_name:"Heathcote",
postcode:"10029",
created_at:"2019-10-02T08:14:20Z",
updated_at:"2019-10-02T08:14:20Z",
user: {
email: "clarisa_larkin@sawayn.info",
level: 0,
otp: false,
referral_uid: nil,
role: "member",
state: "pending",
uid: "IDEA819FB3F1",
updated_at: "2019-10-02T08:14:20Z"
created_at: "2019-10-02T08:14:20Z"
}
},
name: "model.profile.created"
}
| Field | Description |
|---|---|
record |
Created profile up-to-date attributes. |
Format of model.user.updated event
event: {
record: {
address:"Illinois",
city:"New Garfieldbury",
country:"COD",
created_at:"2019-10-02T08:14:20Z",
dob:"1984-05-22",
first_name:"Irina",
last_name:"Heathcote",
postcode:"10029",
updated_at:"2019-10-02T08:14:20Z",
user: {
email: "clarisa_larkin@sawayn.info",
level: 0,
otp: false,
referral_uid: nil,
role: "member",
state: "pending",
uid: "IDEA819FB3F1",
updated_at: "2019-10-02T08:14:20Z"
created_at: "2019-10-02T08:14:20Z"
}
},
changes: {
first_name: "Vernell"
},
name: "model.profile.updated"
}
| Field | Description |
|---|---|
record |
Profile up-to-date attributes. |
changes |
The changed profile attributes and their values. |
Format of model.label.created event
event: {
record: {
id: 1,
key: "email",
value: "verified",
user: {
uid: "ID30DD0DD986",
email: "example@barong.io",
role: "member",
level: 2,
otp: false,
state: "active",
created_at: "2019-01-28T08:35:29Z",
updated_at: "2019-01-28T08:35:29Z"
}
},
name: "model.label.created"
}
| Field | Description |
|---|---|
record |
Created label up-to-date attributes. |
Format of model.label.updated event
event: {
record: {
id: 1,
key: "new_key",
value: "verified",
user: {
uid: "ID30DD0DD986",
email: "example@barong.io",
role: "member",
level: 2,
otp: false,
state: "active",
created_at: "2019-01-28T08:35:29Z",
updated_at: "2019-01-28T08:35:29Z"
}
},
changes: {
key: "old_key"
}
name: "model.label.updated"
}
| Field | Description |
|---|---|
record |
Created label up-to-date attributes. |
changes |
The changed label attributes and their values. |
Format of model.document.created event
event: {
record: {
doc_type: 'Passport',
doc_expire: '3020-01-22',
doc_number: 'AA1234BB',
upload: [],
updated_at:"2019-01-28T08:35:29Z",
created_at:"2019-01-28T08:35:29ZZ",
user: {
uid: "ID30DD0DD986",
email: "example@barong.io",
role: "member",
level: 2,
otp: false,
state: "active",
created_at: "2019-01-28T08:35:29Z",
updated_at: "2019-01-28T08:35:29Z"
}
}
name: "model.document.created"
}
| Field | Description |
|---|---|
user |
The up-to-date user attributes. |
doc_type |
Document type. |
doc_expire |
Experation time for document. |
doc_number |
Document number. |
upload |
Array of updaded objects |
updated_at |
Time of document object creation |
created_at |
Time of last document update |
Format of system.user.email.confirmation.token event
event: {
record: {
user: {
uid: "ID739065AFD3",
email: "example@barong.io",
role: "member",
level: 0,
otp: false,
state: "pending",
created_at: "2019-01-28T09:03:50Z",
updated_at: "2019-01-28T09:03:50Z"
},
language: "EN",
domain: "www.barong.io",
token: "eyJhbGciOiJSUzI1NiJ9.eyJpYXQiOjE1NDg2NjYyMzAsImV4cCI6MTU0ODY3MjIzMCwic3ViIjoiY29uZmlybWF0aW9uIiwiaXNzIjoiYmFyb25nIiwiYXVkIjpbInBlYXRpbyIsImJhcm9uZyJdLCJqdGkiOiI5OWJkNzFkMjU2NTdlMmI1YzI1MCIsImVtYWlsIjoiYWRtaW4xMjNAYmFyb25nLmlvIiwidWlkIjoiSUQ3MzkwNjVBRkQzIn0.OI5tL9kV6cA1JBAy7G5iqd3WplxcB-waHYKFjm83koMEpx2Hlw9fksq5lip5cIHTjR8i3ambFL40OaCwDNc1jAiDsHwuv2nLswgi88_M1G8KVFylboQdtgmH_cZiz-Y-51Fq2oqEID5QyJnsSMSJbfspb6A0JGT_V-SPK4WFZw43F_RKhlZBCrxojljMwd20rGqFPYirMgUpsfiW0_-mESXzQ7UK1eA8mYO7Id4y6JR2Yoo-JTloEnBL1M189tOz6LqmmQB0M_QjTiHG3y9I97Med3StgVziYo9qog9kJXyPuXbboddg__5WEhMcWbaToohoiT5UvpVJHKfgxEVaDg"
},
name: "system.user.email.confirmation.token"
}
| Field | Description |
|---|---|
user |
The up-to-date user attributes. |
language |
The language. |
domain |
The domain name of barong. |
token |
Valid confirm-acc jwt token (mandatory param for user confirmation endpoint) /identity/users/email/confirm_code. |
Format of system.user.email.confirmed event
event: {
record: {
user: {
uid: "IDB1629BFE9E",
email: "example@barong.io",
role: "member",
level: 0,
otp: false,
state: "active",
created_at: "2019-01-28T10:17:27Z",
updated_at: "2019-01-28T10:17:45Z"
},
language: "EN",
domain: "www.barong.io"
},
name: "system.user.email.confirmed"
}
| Field | Description |
|---|---|
user |
The up-to-date user attributes. |
language |
The language. |
domain |
The domain name of barong. |
Format of system.user.password.reset.token event
event: {
record: {
user: {
uid: "ID30DD0DD986",
email: "example@barong.io",
role: "member",
level: 0,
otp: false,
state: "pending",
created_at: "2019-01-28T08:35:29Z",
updated_at: "2019-01-28T08:35:29Z"
},
language: "EN",
domain: "www.barong.io",
token: "eyJhbGciOiJSUzI1NiJ9.eyJpYXQiOjE1NDg2NjQ1OTUsImV4cCI6MTU0ODY3MDU5NSwic3ViIjoicmVzZXQiLCJpc3MiOiJiYXJvbmciLCJhdWQiOlsicGVhdGlvIiwiYmFyb25nIl0sImp0aSI6IjRhY2IzM2IzYmE2NDc0ZjY1YTI5IiwiZW1haWwiOiJhZG1pbjEyQGJhcm9uZy5pbyIsInVpZCI6IklEMzBERDBERDk4NiJ9.Rie4LCbkV0jVBbhMoceYx8a9uDA-ea9D1v790zlIqP_EY8Iue_OOKXYWiC1Y-55MPicFbknBILjZlPewvAF8ZrhqIt04ROsgBdDGEUGY_SnLWhXzqSx9-v_o_w2MVjLOUxvRBm6sD0RvL-_5LmOcLqhYtf7ZPUnPDwsvhDedqDfbXPEvI7OK2SZ-1uPAOg1IMOX1k7xaDt5I1Wp-Knr2DmEgwNYbIjaXraComYcMdtVSuYVJAufgA0kTADMeT3cV3jzGy9dNfs8heMCtf5tr72IbL0_N0VeUQj9uaPDUr4ntsYk7gOPmA3RSVrSismtYdBXA9oLA0b0YfOctiY9dqg"
},
name: "system.user.password.reset.token"
}
| Field | Description |
|---|---|
user |
The up-to-date user attributes. |
language |
The language. |
domain |
The domain name of barong. |
token |
Valid reset-pass jwt token (mandatory param for password reset endpoint) /identity/users/password/confirm_code. |
Format of system.user.account.deleted event
event: {
record: {
user: {
uid: "IDB1629BFE9E",
email: "example@barong.io",
role: "member",
level: 1,
otp: false,
state: "deleted",
created_at: "2019-01-28T10:17:27Z",
updated_at: "2019-01-28T10:17:45Z",
}
},
name: "system.user.account.deleted"
}
| Field | Description |
|---|---|
user |
The up-to-date user attributes. |
Format of system.user.password.reset event
event: {
record: {
user: {
uid: "ID30DD0DD986",
email: "example@barong.io",
role: "member",
level: 0,
otp: false,
state: "pending",
created_at: "2019-01-28T08:35:29Z",
updated_at: "2019-01-28T09:42:36Z"
}
},
name: "system.user.password.reset"
}
| Field | Description |
|---|---|
user |
The up-to-date user attributes. |
Format of system.user.password.change event
event: {
record: {
user: {
uid: "IDC554ED1D0F",
email: "example@barong.io",
role: "member",
level: 0,
otp: false,
state: "active",
created_at: "2019-01-09T15:54:56Z",
updated_at: "2019-01-28T09:59:03Z"
}
},
name: "system.user.password.change"
}
| Field | Description |
|---|---|
user |
The up-to-date user attributes. |
Format of system.document.verified event
event: {
record: {
user: {
uid: "IDC554ED1D0F",
email: "example@barong.io",
role: "member",
level: 0,
otp: false,
state: "active",
created_at: "2019-01-09T15:54:56Z",
updated_at: "2019-01-28T09:59:03Z"
},
id: 1,
key: "something",
value: "verified"
},
name: "system.document.verified"
}
| Field | Description |
|---|---|
user |
The up-to-date user attributes. |
Format of system.document.rejected event
event: {
record: {
user: {
uid: "IDC554ED1D0F",
email: "example@barong.io",
role: "member",
level: 0,
otp: false,
state: "active",
created_at: "2019-01-09T15:54:56Z",
updated_at: "2019-01-28T09:59:03Z"
},
id: 1,
key: "something",
value: "rejected"
},
name: "system.document.rejected"
}
| Field | Description |
|---|---|
user |
The up-to-date user attributes. |
Format of system.session.create event
event: {
record: {
user: {
uid: "ID30DD0DD986",
email: "example@barong.io",
role: "member",
level: 0,
otp: false,
state: "pending",
created_at: "2019-01-28T08:35:29Z",
updated_at: "2019-01-28T08:35:29Z"
},
user_ip: "127.0.0.1",
user_agent: "Chrome"
},
name: "system.session.create"
}
Producing events using Ruby
require "bunny"
def generate_jwt(jwt_payload)
Kernel.abort "Please, see «Overview of RabbitMQ message» for implementation guide."
end
Bunny.run host: "localhost", port: 5672, username: "guest", password: "guest" do |session|
channel = session.channel
exchange = channel.direct("barong.events.model")
jwt_payload = {
iss: "barong",
jti: SecureRandom.uuid,
iat: Time.now.to_i,
exp: Time.now.to_i + 60,
event: {
record: {
uid: "ID30DD0DD986",
email: "example@barong.io",
role: "member",
level: 0,
otp: false,
state: "pending",
created_at: "2019-01-28T08:35:29Z",
updated_at: "2019-01-28T08:35:29Z"
},
name: "model.user.created"
}
}
exchange.publish(generate_jwt(jwt_payload), routing_key: "user.created")
end
IMPORTANT: Don't forget to implement the logic for JWT exception handling!
Producing events using rabbitmqadmin
rabbitmqadmin publish routing_key=user.created payload=JWT exchange=barong.events.model
Don't forget to pass environment variable JWT.
Consuming events using Ruby
require "bunny"
def verify_jwt(jwt_payload)
Kernel.abort "Please, see «Overview of RabbitMQ message» for implementation guide."
end
Bunny.run host: "localhost", port: 5672, username: "guest", password: "guest" do |session|
channel = session.channel
exchange = channel.direct("barong.events.model")
queue = channel.queue("", auto_delete: true, durable: true, exclusive: true)
.bind(exchange, routing_key: "user.created")
queue.subscribe manual_ack: true, block: true do |delivery_info, metadata, payload|
Kernel.puts verify_jwt(JSON.parse(payload)).fetch(:event)
channel.ack(delivery_info.delivery_tag)
rescue => e
channel.nack(delivery_info.delivery_tag, false, true)
end
end
IMPORTANT: Don't forget to implement the logic for JWT exception handling!