andymatuschak / orbit

Experimental spaced repetition platform for exploring ideas in memory augmentation and programmable attention
https://withorbit.com
Other
1.71k stars 54 forks source link

Add validation to the /taskData endpoint #212

Closed kirkbyo closed 3 years ago

kirkbyo commented 3 years ago

Relates to https://github.com/andymatuschak/orbit/issues/184

Move the /taskData to be validated. I figured this work deserved its own PR since there were a couple weird quirks. Hopefully the next endpoints will be a lot smoother and will be done all in one PR.

How was this tested?: I setup a collection of HTTP requests using a Postman collection. Works great! I also went ahead and migrated the test cases I used for the /actionLogs endpoint to make sure there are no regressions as I implement changes. It would be nice to eventually integrate postman into CI or have our own HTTP runner.

Test cases ```json { "info":{ "_postman_id":"1f3abda8-add9-49b9-a79b-47570da6c37c", "name":"/taskData", "schema":"https://schema.getpostman.com/json/collection/v2.1.0/collection.json" }, "item":[ { "name":"it allows array of ids", "event":[ { "listen":"test", "script":{ "exec":[ "pm.test(\"it succeeds\", function() {", " pm.response.to.not.have.status(400);", "})" ], "type":"text/javascript" } } ], "request":{ "method":"GET", "header":[ ], "url":{ "raw":"{{HOST}}/api/taskData?ids=someIdAp&ids=someIdB", "host":[ "{{HOST}}" ], "path":[ "api", "taskData" ], "query":[ { "key":"ids", "value":"someIdA" }, { "key":"ids", "value":"someIdB" } ] } }, "response":[ ] }, { "name":"it allows single id", "event":[ { "listen":"test", "script":{ "exec":[ "pm.test(\"it succeeds\", function() {", " pm.response.to.not.have.status(400);", "})" ], "type":"text/javascript" } } ], "request":{ "method":"GET", "header":[ ], "url":{ "raw":"{{HOST}}/api/taskData?ids=someIdA", "host":[ "{{HOST}}" ], "path":[ "api", "taskData" ], "query":[ { "key":"ids", "value":"someIdA" } ] } }, "response":[ ] }, { "name":"it fails when body is not provided", "event":[ { "listen":"test", "script":{ "exec":[ "pm.test(\"it fails with body should be array\", function() {", " pm.response.to.have.status(400);", " const expected = [", " { \"message\": \"body must be array\" }", " ];", " const json = pm.response.json();", " pm.expect(json.errors).to.deep.eq(expected);", "})" ], "type":"text/javascript" } } ], "request":{ "method":"PATCH", "header":[ ], "url":{ "raw":"{{HOST}}/api/taskData", "host":[ "{{HOST}}" ], "path":[ "api", "taskData" ] } }, "response":[ ] }, { "name":"it fails when prompt is not provided", "event":[ { "listen":"test", "script":{ "exec":[ "pm.test(\"it fails with required property data\", function() {", " pm.response.to.have.status(400);", " const expected = [", " { \"message\": \"body/0 must have required property 'data'\" }", " ];", " const json = pm.response.json();", " pm.expect(json.errors).to.deep.eq(expected);", "})" ], "type":"text/javascript" } } ], "request":{ "method":"PATCH", "header":[ ], "body":{ "mode":"raw", "raw":"[\n {\n \"id\": \"a\"\n }\n]", "options":{ "raw":{ "language":"json" } } }, "url":{ "raw":"{{HOST}}/api/taskData", "host":[ "{{HOST}}" ], "path":[ "api", "taskData" ] } }, "response":[ ] }, { "name":"it fails when id is not provided", "event":[ { "listen":"test", "script":{ "exec":[ "pm.test(\"it fails with property id required\", function() {", " pm.response.to.have.status(400);", " const expected = [", " { \"message\": \"body/0 must have required property 'id'\" }", " ];", " const json = pm.response.json();", " pm.expect(json.errors).to.deep.eq(expected);", "})" ], "type":"text/javascript" } } ], "request":{ "method":"PATCH", "header":[ ], "body":{ "mode":"raw", "raw":"[\n { \n \"data\": {\n \"promptType\": \"clozePrompt\",\n \"body\": { \"contents\": \"test\", \"attachments\": [] }\n }\n }\n]", "options":{ "raw":{ "language":"json" } } }, "url":{ "raw":"{{HOST}}/api/taskData", "host":[ "{{HOST}}" ], "path":[ "api", "taskData" ] } }, "response":[ ] }, { "name":"it fails when prompt type is invalid", "event":[ { "listen":"test", "script":{ "exec":[ "pm.test(\"it fails with no additionalProperties\", function() {", " pm.response.to.have.status(400);", " const expected = [", " { \"message\": \"body/0/data must have required property 'answer'\" },", " { \"message\": \"body/0/data must have required property 'variants'\" },", " { \"message\": \"body/0/data/promptType must be equal to one of the allowed values\" },", " { \"message\": \"body/0/data must match a schema in anyOf\" }", " ];", " const json = pm.response.json();", " pm.expect(json.errors).to.deep.eq(expected);", "})" ], "type":"text/javascript" } } ], "request":{ "method":"PATCH", "header":[ ], "body":{ "mode":"raw", "raw":"[\n {\n \"id\": \"someId\",\n \"data\": {\n \"promptType\": \"unknownPromptType\",\n \"body\": { \"contents\": \"hello world\", \"attachments\": [] }\n }\n }\n]", "options":{ "raw":{ "language":"json" } } }, "url":{ "raw":"{{HOST}}/api/taskData", "host":[ "{{HOST}}" ], "path":[ "api", "taskData" ] } }, "response":[ ] }, { "name":"it succeeds when body is empty", "event":[ { "listen":"test", "script":{ "exec":[ "pm.test(\"it succeeds\", function() {", " pm.response.to.have.status(401);", "})" ], "type":"text/javascript" } } ], "request":{ "method":"PATCH", "header":[ ], "body":{ "mode":"raw", "raw":"[]", "options":{ "raw":{ "language":"json" } } }, "url":{ "raw":"{{HOST}}/api/taskData", "host":[ "{{HOST}}" ], "path":[ "api", "taskData" ] } }, "response":[ ] }, { "name":"it succeeds when body has an item", "event":[ { "listen":"test", "script":{ "exec":[ "pm.test(\"it fails with no additionalProperties\", function() {", " pm.response.to.have.status(401);", "})" ], "type":"text/javascript" } } ], "request":{ "method":"PATCH", "header":[ ], "body":{ "mode":"raw", "raw":"[\n {\n \"id\": \"hello\",\n \"data\": {\n \"promptType\": \"clozePrompt\",\n \"body\": { \"contents\": \"hello\", \"attachments\": [] }\n }\n }\n]", "options":{ "raw":{ "language":"json" } } }, "url":{ "raw":"{{HOST}}/api/taskData", "host":[ "{{HOST}}" ], "path":[ "api", "taskData" ] } }, "response":[ ] } ] } ```