From 9edc579bfe3fee8bd7b1f603806712963472ed71 Mon Sep 17 00:00:00 2001 From: masiton Date: Sat, 5 Jul 2025 00:54:59 +0200 Subject: [PATCH] Documentation. --- README.md | 52 ++- postman/endpoints.postman_collection.json | 383 ++++++++++++++++++ ...ngerapi-localhost.postman_environment.json | 57 +++ 3 files changed, 488 insertions(+), 4 deletions(-) create mode 100644 postman/endpoints.postman_collection.json create mode 100644 postman/messengerapi-localhost.postman_environment.json diff --git a/README.md b/README.md index 2f84c3f..0437acd 100644 --- a/README.md +++ b/README.md @@ -83,20 +83,23 @@ Tunnel on port `80` to send traffic. Consume HTTP endpoints: ### `POST /send` -Sends message and returns it's ID. Minimal message body where `user2` sends a text message to `user1`, and since `user2` can only message to `user1` and nobody else, they don't even have to specify recipient, the system infers it automatically: +Sends message and returns it's ID. Minimal message body where `user2` sends a text message to `user1`, and since `user2` can only message to `user1` and nobody else, they don't even have to specify recipient, the system infers it automatically. + +Request: http /send (post) header: Authorization: Bearer f480568f-8884-47e5-a6d7-82480f1ffb3b { "payload": "This is a message." } -Response +Response: http (json): "5f33b4bd-dc2a-4ace-947a-1aadc6045995" -Optionally, messages can be complex. Here is a message from `user1` to `user3`, both `payload` and `payloadType` are `nvarchar` fields and their content can be whatever: +Optionally, messages can be complex. Here is a message from `user1` to `user3`, both `payload` and `payloadType` are `nvarchar` fields and their content can be whatever. +Request: http /send (post) header: Authorization: Bearer 81ccf737-d424-4f83-929c-92d20491abfa { "payloadType": "STATUS", @@ -105,13 +108,21 @@ Optionally, messages can be complex. Here is a message from `user1` to `user3`, "lifespanInSeconds": "3600" } +Response: + + http (json): + "5f33b4bd-dc2a-4ace-947a-1aadc6045995" + + ### `GET /receive` Receives all waiting messages. +Request: + http /receive (get) header: Authorization: Bearer 81ccf737-d424-4f83-929c-92d20491abfa -Response +Response: http (json): "messages": [ @@ -124,6 +135,39 @@ Response } ] +### `POST /ack` + +Acknowledges delivered message. The client that received the message is the only party able to acknowledge. + +Request: + + http /ack (post) header: Authorization: Bearer 81ccf737-d424-4f83-929c-92d20491abfa + { + "messageId": "5f33b4bd-dc2a-4ace-947a-1aadc6045995" + } + +Response: + + http (json) 200 OK: + (empty) + +### `GET /verify` + +Sender can call this to get delivery status of message that has been sent earlier: + +Request: + + http /verify?messageId=5f33b4bd-dc2a-4ace-947a-1aadc6045995 (get) header: Authorization: Bearer 81ccf737-d424-4f83-929c-92d20491abfa + +Response: + + http (json) 200 OK: + { + "isDelivered": true, + "isAcknowledged": true + } + + ## Testing See postman collection to generate code for your desired language or test the API instance. The collection also works as test suite, just fill out the environment variables for URL and api keys of your users and it will run and test all endpoints, with expected outputs. \ No newline at end of file diff --git a/postman/endpoints.postman_collection.json b/postman/endpoints.postman_collection.json new file mode 100644 index 0000000..2941c24 --- /dev/null +++ b/postman/endpoints.postman_collection.json @@ -0,0 +1,383 @@ +{ + "info": { + "_postman_id": "b8400b20-a16f-4c2a-a8ec-0eec25611319", + "name": "endpoints", + "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json", + "_exporter_id": "248257" + }, + "item": [ + { + "name": "cors/send", + "request": { + "method": "OPTIONS", + "header": [ + { + "key": "Access-Control-Request-Method", + "value": "POST", + "type": "text" + }, + { + "key": "Access-Control-Request-Headers", + "value": "content-type", + "type": "text" + }, + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "Origin", + "value": "{{FrontEndUrl}}", + "type": "text" + }, + { + "key": "Referer", + "value": "{{FrontEndUrl}}", + "type": "text" + } + ], + "url": { + "raw": "{{Url}}/send", + "host": [ + "{{Url}}" + ], + "path": [ + "send" + ] + } + }, + "response": [] + }, + { + "name": "yellowpages", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "let response = pm.response.json();\r", + "pm.environment.set(\"User2IdFromYellowpages\", response.users[0].id);\r", + "\r", + "pm.test(\"User2 address returned should match our expectation.\", function () {\r", + " const u2id = pm.environment.get(\"User2Id\");\r", + " const u2idFromResponse = pm.environment.get(\"User2IdFromYellowpages\");\r", + " pm.expect(u2id, `Expected returned value (${u2idFromResponse}) to equal expected value (${u2id})`).to.eql(u2idFromResponse);\r", + "});" + ], + "type": "text/javascript", + "packages": {} + } + } + ], + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "{{User1ApiKey}}", + "type": "string" + } + ] + }, + "method": "GET", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "Origin", + "value": "www.google.com", + "type": "text" + } + ], + "url": { + "raw": "{{Url}}/yellowpages", + "host": [ + "{{Url}}" + ], + "path": [ + "yellowpages" + ] + } + }, + "response": [] + }, + { + "name": "send", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "let response = pm.response.json();\r", + "pm.environment.set(\"MessageId\", response);" + ], + "type": "text/javascript", + "packages": {} + } + } + ], + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "{{User1ApiKey}}", + "type": "string" + } + ] + }, + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"payloadType\": \"Whatever\",\r\n \"payload\": \"This is a message.\",\r\n \"toUserId\": \"{{User2Id}}\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{Url}}/send", + "host": [ + "{{Url}}" + ], + "path": [ + "send" + ] + } + }, + "response": [] + }, + { + "name": "verify", + "protocolProfileBehavior": { + "disableBodyPruning": true + }, + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "{{User1ApiKey}}", + "type": "string" + } + ] + }, + "method": "GET", + "header": [], + "body": { + "mode": "raw", + "raw": "", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{Url}}/verify?messageId={{MessageId}}", + "host": [ + "{{Url}}" + ], + "path": [ + "verify" + ], + "query": [ + { + "key": "messageId", + "value": "{{MessageId}}" + } + ] + } + }, + "response": [] + }, + { + "name": "peek", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"We have expected 1 message during call.\", function () {\r", + " const count = parseInt(pm.response.text(), 10);\r", + " const expectedCount = 1;\r", + " pm.expect(count, `Expected returned value (${count}) to equal expected value (${expectedCount})`).to.eql(expectedCount);\r", + "});\r", + "\r", + "pm.test(\"Response status is 200 OK\", function () {\r", + " pm.response.to.have.status(200);\r", + "});" + ], + "type": "text/javascript", + "packages": {} + } + } + ], + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "{{User2ApiKey}}", + "type": "string" + } + ] + }, + "method": "GET", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + } + ], + "url": { + "raw": "{{Url}}/peek", + "host": [ + "{{Url}}" + ], + "path": [ + "peek" + ] + } + }, + "response": [] + }, + { + "name": "receive", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "let response = pm.response.json();\r", + "\r", + "pm.test(\"MessageId returned should match MessageId from Send call.\", function () {\r", + " const idFromCall = response.messages[0].id;\r", + " const idFromSend = pm.environment.get(\"MessageId\");\r", + " pm.expect(idFromCall, `Expected returned value (${idFromCall}) to equal expected value (${idFromSend})`).to.eql(idFromSend);\r", + "});" + ], + "type": "text/javascript", + "packages": {} + } + } + ], + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "{{User2ApiKey}}", + "type": "string" + } + ] + }, + "method": "GET", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + } + ], + "url": { + "raw": "{{Url}}/receive", + "host": [ + "{{Url}}" + ], + "path": [ + "receive" + ] + } + }, + "response": [] + }, + { + "name": "ack", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Response status is 200 OK\", function () {\r", + " pm.response.to.have.status(200);\r", + "});" + ], + "type": "text/javascript", + "packages": {} + } + } + ], + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "{{User2ApiKey}}", + "type": "string" + } + ] + }, + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"messageId\": \"{{MessageId}}\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{Url}}/ack", + "host": [ + "{{Url}}" + ], + "path": [ + "ack" + ] + } + }, + "response": [] + } + ], + "auth": { + "type": "bearer" + }, + "event": [ + { + "listen": "prerequest", + "script": { + "type": "text/javascript", + "packages": {}, + "exec": [ + "" + ] + } + }, + { + "listen": "test", + "script": { + "type": "text/javascript", + "packages": {}, + "exec": [ + "" + ] + } + } + ] +} \ No newline at end of file diff --git a/postman/messengerapi-localhost.postman_environment.json b/postman/messengerapi-localhost.postman_environment.json new file mode 100644 index 0000000..07c3ec7 --- /dev/null +++ b/postman/messengerapi-localhost.postman_environment.json @@ -0,0 +1,57 @@ +{ + "id": "15acfd9e-f24e-479b-82fa-2c022f726558", + "name": "messengerapi-localhost", + "values": [ + { + "key": "User1ApiKey", + "value": "aab8f7e9-ad13-4bf8-bb2e-0cd93d81adc0", + "type": "secret", + "enabled": true + }, + { + "key": "User1Id", + "value": "f696442b-e8dc-4074-b34f-94bcece8e74b", + "type": "default", + "enabled": true + }, + { + "key": "User2ApiKey", + "value": "8f73f683-7cb3-40df-998e-6e604aef0e53", + "type": "secret", + "enabled": true + }, + { + "key": "User2Id", + "value": "15d97720-f5b7-47aa-9c1a-71f98b0b9248", + "type": "any", + "enabled": true + }, + { + "key": "Url", + "value": "http://localhost:5259", + "type": "default", + "enabled": true + }, + { + "key": "MessageId", + "value": "", + "type": "any", + "enabled": true + }, + { + "key": "FrontEndUrl", + "value": "https://example.com", + "type": "default", + "enabled": true + }, + { + "key": "User2IdFromYellowpages", + "value": "", + "type": "any", + "enabled": true + } + ], + "_postman_variable_scope": "environment", + "_postman_exported_at": "2025-07-04T22:53:28.963Z", + "_postman_exported_using": "Postman/11.52.6" +} \ No newline at end of file