# HG changeset patch # User Kim Alvefur # Date 1614536745 -3600 # Node ID 8df6cc6489637a87e80f13ba1e5ab6ec28512889 # Parent 125279f4a5b888ed626de3aade4c888d9b7f1a2f mod_rest: Add more REST-looking way to send stanzas Example: POST /rest/message/chat/juliet@example.net { body: "Hello" } Becomes equivalent to POST /rest { kind: "message", type: "chat", to: "juliet@example.net", body: "Hello" } Sending messages as plain/text also becomes more convenient. IQ stazas are still weird, but we'll do something special for those. diff -r 125279f4a5b8 -r 8df6cc648963 mod_rest/README.markdown --- a/mod_rest/README.markdown Sun Feb 28 18:55:18 2021 +0100 +++ b/mod_rest/README.markdown Sun Feb 28 19:25:45 2021 +0100 @@ -70,6 +70,18 @@ The `Content-Type` header is important! +### Parameters in path + +New alternative format with the parameters `kind`, `type`, and `to` +embedded in the path: + +``` +curl https://prosody.example:5281/rest/message/chat/john@example.com \ + --oauth2-bearer dmVyeSBzZWNyZXQgdG9rZW4K \ + -H 'Content-Type: text/plain' \ + --data-binary 'Hello John!' +``` + ### Replies A POST containing an `` stanza automatically wait for the reply, diff -r 125279f4a5b8 -r 8df6cc648963 mod_rest/mod_rest.lua --- a/mod_rest/mod_rest.lua Sun Feb 28 18:55:18 2021 +0100 +++ b/mod_rest/mod_rest.lua Sun Feb 28 19:25:45 2021 +0100 @@ -59,7 +59,19 @@ return nil; end -local function parse(mimetype, data) +-- (table, string) -> table +local function amend_from_path(data, path) + local st_kind, st_type, st_to = path:match("^([mpi]%w+)/(%w+)/(.*)$"); + if not st_kind then return; end + data.kind = st_kind; + data.type = st_type; + if st_to and st_to ~= "" then + data.to = st_to; + end + return data; +end + +local function parse(mimetype, data, path) --> Stanza, error enum mimetype = mimetype and mimetype:match("^[^; ]*"); if mimetype == "application/xmpp+xml" then return xml.parse(data); @@ -68,6 +80,7 @@ if not parsed then return parsed, err; end + if path and not amend_from_path(parsed, path) then return nil, "invalid-path"; end return jsonmap.json2st(parsed); elseif mimetype == "application/cbor" and have_cbor then local parsed, err = cbor.decode(data); @@ -83,9 +96,22 @@ for i = #parsed, 1, -1 do parsed[i] = nil; end + if path and not amend_from_path(parsed, path) then return nil, "invalid-path"; end return jsonmap.json2st(parsed); elseif mimetype == "text/plain" then - return st.message({ type = "chat" }, data); + if not path then + return st.message({ type = "chat" }, data); + end + local parsed = {}; + if not amend_from_path(parsed, path) then return nil, "invalid-path"; end + if parsed.kind == "message" then + parsed.body = data; + elseif parsed.kind == "presence" then + parsed.show = data; + else + return nil, "invalid-path"; + end + return jsonmap.json2st(parsed); end return nil, "unknown-payload-type"; end @@ -162,7 +188,7 @@ mediatype = { code = 415, condition = "bad-format", text = "Unsupported media type" }, }); -local function handle_post(event) +local function handle_post(event, path) local request, response = event.request, event.response; local from; local origin; @@ -177,7 +203,7 @@ end from = jid.join(origin.username, origin.host, origin.resource); end - local payload, err = parse(request.headers.content_type, request.body); + local payload, err = parse(request.headers.content_type, request.body, path); if not payload then -- parse fail local ctx = { error = err, type = request.headers.content_type, data = request.body, }; @@ -267,6 +293,7 @@ module:provides("http", { route = { POST = handle_post; + ["POST /*"] = handle_post; }; }); diff -r 125279f4a5b8 -r 8df6cc648963 mod_rest/openapi.yaml --- a/mod_rest/openapi.yaml Sun Feb 28 18:55:18 2021 +0100 +++ b/mod_rest/openapi.yaml Sun Feb 28 19:25:45 2021 +0100 @@ -62,6 +62,31 @@ payload. 415: description: Unsupported mediatype. + /rest/{kind}/{type}/{to}: + post: + responses: + 200: + description: Okay + security: + - basic: [] + - token: [] + summary: Even more RESTful mapping. + parameters: + - name: kind + in: path + required: true + schema: + $ref: '#/components/schemas/kind' + - name: type + in: path + required: true + schema: + $ref: '#/components/schemas/type' + - name: to + in: path + required: true + schema: + $ref: '#/components/schemas/to' components: schemas: stanza: