diff --git a/patterns/index.md b/patterns/index.md index e104a63..f8c0c86 100644 --- a/patterns/index.md +++ b/patterns/index.md @@ -21,7 +21,7 @@ Simple roadmap for patterns to document; Communication Patterns -- [ ] Request-Reply +- [X] [Request-Reply](./request-and-reply.md) - [ ] point-to-point - [ ] event streaming - [ ] Publish-Subscribe pattern diff --git a/patterns/request-and-reply.md b/patterns/request-and-reply.md new file mode 100644 index 0000000..2dc1f5f --- /dev/null +++ b/patterns/request-and-reply.md @@ -0,0 +1,330 @@ +--- +title: Request and Reply +description: +--- + +# Request and Reply + +Request and Reply is one of the most used messaging pattern and offers a two-way communication pattern to exchange messages. The most known form being REST and HTTP where you make synchronous requests over a single channel/path. + +In the event driven world it can quickly become complex as often there are no single channel and can be more dynamic. + +In request and reply there are always two parties, the requester, making the request and the replier, in charge of delivering the response to the request according to how it's expected. + + +
| Requester | +Replier | +
|---|---|
| + +```json +{ + "asyncapi": "3.0.0", + "info": { + "title": "Payment service", + "description": "The requester", + "version": "1.0.0" + }, + "channels": { + "StartShipping": { + "address": "shipping/start", + "messages": { + "StartShippingRequest": { + "$ref": "#/components/messages/StartShippingRequest" + }, + "StartShippingResponse": { + "$ref": "#/components/messages/StartShippingResponse" + } + } + } + }, + "operations": { + "StartShippingRequest": { + "action": "send", + "channel": { + "$ref": "#/channels/StartShipping" + }, + "messages": [ + { + "$ref": "#/channels/ping/messages/StartShippingRequest" + } + ], + "reply": { + "channel": { + "$ref": "#/channels/StartShipping" + }, + "messages": [ + { + "$ref": "#/channels/ping/messages/StartShippingResponse" + } + ] + } + } + }, + ... +} +``` + | + ++ +```json +{ + "asyncapi": "3.0.0", + "info": { + "title": "Shipping service", + "description": "The replier", + "version": "1.0.0" + }, + "channels": { + "StartShipping": { + ... + } + }, + "operations": { + "StartShippingReply": { + "action": "receive", + "channel": { + "$ref": "#/channels/StartShipping" + }, + "messages": [ + { + "$ref": "#/channels/ping/messages/StartShippingRequest" + } + ], + "reply": { + "channel": { + "$ref": "#/channels/StartShipping" + }, + "messages": [ + { + "$ref": "#/channels/ping/messages/StartShippingResponse" + } + ] + } + } + }, + ... +} +``` + + | +
| Payload | +Headers | +
|---|---|
| + +```json +{ + "asyncapi": "3.0.0", + "info": { + "title": "Payment service", + "version": "1.0.0" + }, + "channels": { + "StartShippingRequest": { + "address": "shipping/start", + "messages": { + "StartShippingRequest": { + "$ref": "#/components/messages/StartShippingRequest" + }, + } + }, + "StartShippingReply": { + "address": null, + "messages": { + "StartShippingResponse": { + "$ref": "#/components/messages/StartShippingResponse" + } + } + } + }, + "operations": { + "StartShippingRequest": { + "action": "send", + "channel": { + "$ref": "#/channels/StartShippingRequest" + }, + "reply": { + "address": { + "description": "The reply address is dynamically determined + based on the request header `replyTo`", + "location": "$message.payload#/replyTo" + }, + "channel": { + "$ref": "#/channels/StartShippingReply" + } + } + } + }, + "components": { + "messages": { + "StartShippingRequest": { + "payload": { + "type": "object", + "properties": { + "replyTo": { + "type": "string" + } + } + } + } + } + } + ... +} +``` + | + ++ +```json +{ + "asyncapi": "3.0.0", + "info": { + "title": "Payment service", + "version": "1.0.0" + }, + "channels": { + "StartShippingRequest": { + "address": "shipping/start", + "messages": { + "StartShippingRequest": { + "$ref": "#/components/messages/StartShippingRequest" + }, + } + }, + "StartShippingReply": { + "address": null, + "messages": { + "StartShippingResponse": { + "$ref": "#/components/messages/StartShippingResponse" + } + } + } + }, + "operations": { + "StartShippingRequest": { + "action": "send", + "channel": { + "$ref": "#/channels/StartShippingRequest" + }, + "reply": { + "address": { + "description": "The reply address is dynamically determined + based on the request header `replyTo`", + "location": "$message.header#/replyTo" + }, + "channel": { + "$ref": "#/channels/StartShippingReply" + } + } + } + }, + "components": { + "messages": { + "StartShippingRequest": { + "headers": { + "type": "object", + "properties": { + "replyTo": { + "type": "string" + } + } + } + } + } + } +} +``` + | +
| WebSocket | +
|---|
| + +> Simulating a request and reply scenario, where we expect a specific message results in another over the same connection. + +```json +{ + "asyncapi": "3.0.0", + "info": { + "title": "WebSocket request/reply example", + "version": "1.0.0" + }, + "channels": { + "rootChannel": { + "address": "/", + "messages": { + "StartShippingRequest": { + "$ref": "#/components/messages/StartShippingRequest" + }, + "StartShippingResponse": { + "$ref": "#/components/messages/StartShippingResponse" + } + } + } + }, + "operations": { + "StartShippingRequest": { + "action": "send", + "channel": { + "$ref": "#/channels/rootChannel" + }, + "messages": [ + { + "$ref": "/components/messages/StartShippingRequest" + } + ], + "reply": { + "messages": [ + { + "$ref": "/components/messages/StartShippingResponse" + } + ], + "channel": { + "$ref": "#/channels/rootChannel" + } + } + } + } +} +``` + | +