From dc56d06a11cb1ce232c72b38a5314133f5a469c3 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Thu, 17 Feb 2022 18:58:09 +0000 Subject: [PATCH] Adding in public endpoint definitions. --- packages/server/.gitignore | 3 +- packages/server/specs/generate.js | 51 ++++- packages/server/specs/openapi.json | 197 ++++++++++++++---- packages/server/specs/openapi.yaml | 160 ++++++++++++++ .../src/api/controllers/public/index.js | 24 +++ .../src/api/routes/public/applications.js | 5 + .../server/src/api/routes/public/index.js | 25 +++ .../server/src/api/routes/public/queries.js | 5 + packages/server/src/api/routes/public/rows.js | 130 ++++++++++++ .../server/src/api/routes/public/tables.js | 5 + .../server/src/api/routes/public/users.js | 5 + 11 files changed, 567 insertions(+), 43 deletions(-) create mode 100644 packages/server/specs/openapi.yaml create mode 100644 packages/server/src/api/controllers/public/index.js create mode 100644 packages/server/src/api/routes/public/applications.js create mode 100644 packages/server/src/api/routes/public/index.js create mode 100644 packages/server/src/api/routes/public/queries.js create mode 100644 packages/server/src/api/routes/public/rows.js create mode 100644 packages/server/src/api/routes/public/tables.js create mode 100644 packages/server/src/api/routes/public/users.js diff --git a/packages/server/.gitignore b/packages/server/.gitignore index 48207e3dd4..f129368792 100644 --- a/packages/server/.gitignore +++ b/packages/server/.gitignore @@ -3,8 +3,7 @@ myapps/ .env builder/* client/* -public/ db/dev.db/ dist coverage/ -watchtower-hook.json \ No newline at end of file +watchtower-hook.json diff --git a/packages/server/specs/generate.js b/packages/server/specs/generate.js index f70f339a0a..0298d8af20 100644 --- a/packages/server/specs/generate.js +++ b/packages/server/specs/generate.js @@ -18,12 +18,54 @@ const options = { description: "Budibase Cloud API", }, { - url: "http://localhost:10000/api/public/v1", + url: "{protocol}://{hostname}:10000/api/public/v1", description: "Budibase self hosted API", }, ], + components: { + examples: { + row: { + value: { + _id: "ro_ta_5b1649e42a5b41dea4ef7742a36a7a70_e6dc7e38cf1343b2b56760265201cda4", + type: "row", + tableId: "ta_5b1649e42a5b41dea4ef7742a36a7a70", + name: "Mike", + age: 30, + relationship: [ + { + primaryDisplay: "Joe", + _id: "ro_ta_...", + }, + ], + }, + }, + table: { + value: { + _id: "ta_5b1649e42a5b41dea4ef7742a36a7a70", + name: "People", + schema: { + name: { + type: "string", + name: "name", + }, + age: { + type: "number", + name: "age", + }, + relationship: { + type: "link", + name: "relationship", + tableId: "ta_...", + fieldName: "relatedColumn", + relationshipType: "many-to-many", + }, + }, + }, + }, + }, + }, }, - format: "json", + format: ".json", apis: [join(__dirname, "..", "src", "api", "routes", "public", "*.js")], } @@ -47,8 +89,7 @@ function writeFile(output, { isJson } = {}) { } const outputJSON = swaggerJsdoc(options) -options.format = "yaml" +options.format = ".yaml" const outputYAML = swaggerJsdoc(options) -console.log(outputYAML) -writeFile(outputJSON) +writeFile(outputJSON, { isJson: true }) writeFile(outputYAML) diff --git a/packages/server/specs/openapi.json b/packages/server/specs/openapi.json index 1c6dfe9d25..cccd836a23 100644 --- a/packages/server/specs/openapi.json +++ b/packages/server/specs/openapi.json @@ -7,14 +7,56 @@ }, "servers": [ { - "url": "https://budibase.app/api/public/v1", + "url": "http://budibase.app/api/public/v1", "description": "Budibase Cloud API" }, { - "url": "http://localhost:10000/api/public/v1", + "url": "{protocol}://{hostname}:10000/api/public/v1", "description": "Budibase self hosted API" } ], + "components": { + "examples": { + "row": { + "value": { + "_id": "ro_ta_5b1649e42a5b41dea4ef7742a36a7a70_e6dc7e38cf1343b2b56760265201cda4", + "type": "row", + "tableId": "ta_5b1649e42a5b41dea4ef7742a36a7a70", + "name": "Mike", + "age": 30, + "relationship": [ + { + "primaryDisplay": "Joe", + "_id": "ro_ta_..." + } + ] + } + }, + "table": { + "value": { + "_id": "ta_5b1649e42a5b41dea4ef7742a36a7a70", + "name": "People", + "schema": { + "name": { + "type": "string", + "name": "name" + }, + "age": { + "type": "number", + "name": "age" + }, + "relationship": { + "type": "link", + "name": "relationship", + "tableId": "ta_...", + "fieldName": "relatedColumn", + "relationshipType": "many-to-many" + } + } + } + } + } + }, "paths": { "/row/{tableId}/search": { "post": { @@ -37,45 +79,95 @@ "schema": { "type": "object", "properties": { - "string": { + "query": { "type": "object", - "example": { - "columnName1": "value", - "columnName2": "value" - }, - "description": "A map of field name to the string to search for, this will look for rows that have a value starting with the string value.", - "additionalProperties": { - "type": "string", - "description": "The value to search for in the column." + "properties": { + "string": { + "type": "object", + "example": { + "columnName1": "value", + "columnName2": "value" + }, + "description": "A map of field name to the string to search for, this will look for rows that have a value starting with the string value.", + "additionalProperties": { + "type": "string", + "description": "The value to search for in the column." + } + }, + "fuzzy": { + "type": "object", + "description": "A fuzzy search, only supported by internal tables." + }, + "range": { + "type": "object", + "description": "Searches within a range, the format of this must be columnName -> [low, high]." + }, + "equal": { + "type": "object", + "description": "Searches for rows that have a column value that is exactly the value set." + }, + "notEqual": { + "type": "object", + "description": "Searches for any row which does not contain the specified column value." + }, + "empty": { + "type": "object", + "description": "Searches for rows which do not contain the specified column. The object should simply contain keys of the column names, these can map to any value." + }, + "notEmpty": { + "type": "object", + "description": "Searches for rows which have the specified column." + }, + "oneOf": { + "type": "object", + "description": "Searches for rows which have a column value that is any of the specified values. The format of this must be columnName -> [value1, value2]." + } } }, - "fuzzy": { - "type": "object", - "description": "A fuzzy search, only supported by internal tables." + "paginate": { + "type": "boolean", + "description": "Enables pagination, by default this is disabled." }, - "range": { - "type": "object", - "description": "Searches within a range, the format of this must be columnName -> [low, high]." + "bookmark": { + "oneOf": [ + { + "type": "string" + }, + { + "type": "integer" + } + ], + "description": "If retrieving another page, the bookmark from the previous request must be supplied." }, - "equal": { - "type": "object", - "description": "Searches for rows that have a column value that is exactly the value set." + "limit": { + "type": "integer", + "description": "The maximum number of rows to return, useful when paginating, for internal tables this will be limited to 1000, for SQL tables it will be 5000." }, - "notEqual": { + "sort": { "type": "object", - "description": "Searches for any row which does not contain the specified column value." - }, - "empty": { - "type": "object", - "description": "Searches for rows which do not contain the specified column. The object should simply contain keys of the column names, these can map to any value." - }, - "notEmpty": { - "type": "object", - "description": "Searches for rows which have the specified column." - }, - "oneOf": { - "type": "object", - "description": "Searches for rows which have a column value that is any of the specified values. The format of this must be columnName -> [value1, value2]." + "description": "A set of parameters describing the sort behaviour of the search.", + "properties": { + "order": { + "type": "string", + "enum": [ + "ascending", + "descending" + ], + "description": "The order of the sort, by default this is ascending." + }, + "column": { + "type": "string", + "description": "The name of the column by which the rows will be sorted." + }, + "type": { + "type": "string", + "enum": [ + "string", + "number" + ], + "description": "Defines whether the column should be treated as a string or as numbers when sorting." + } + } } } } @@ -84,12 +176,45 @@ }, "responses": { "200": { - "description": "Returns the rows." + "description": "The response will contain an array of rows that match the search parameters.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "rows": { + "description": "An array of rows, these will each contain an _id field which can be used to update or delete them.", + "type": "array", + "items": { + "type": "object", + "example": { + "$ref": "#/components/examples/row" + } + } + }, + "bookmark": { + "oneOf": [ + { + "type": "string" + }, + { + "type": "integer" + } + ], + "description": "If pagination in use, this should be provided" + }, + "hasNextPage": { + "description": "If pagination in use, this will determine if there is another page to fetch.", + "type": "boolean" + } + } + } + } + } } } } } }, - "components": {}, "tags": [] } \ No newline at end of file diff --git a/packages/server/specs/openapi.yaml b/packages/server/specs/openapi.yaml new file mode 100644 index 0000000000..4cd370001d --- /dev/null +++ b/packages/server/specs/openapi.yaml @@ -0,0 +1,160 @@ +openapi: 3.0.0 +info: + title: Budibase API + description: The public API for Budibase apps and its services. + version: 1.0.0 +servers: + - url: http://budibase.app/api/public/v1 + description: Budibase Cloud API + - url: "{protocol}://{hostname}:10000/api/public/v1" + description: Budibase self hosted API +components: + examples: + row: + value: + _id: ro_ta_5b1649e42a5b41dea4ef7742a36a7a70_e6dc7e38cf1343b2b56760265201cda4 + type: row + tableId: ta_5b1649e42a5b41dea4ef7742a36a7a70 + name: Mike + age: 30 + relationship: + - primaryDisplay: Joe + _id: ro_ta_... + table: + value: + _id: ta_5b1649e42a5b41dea4ef7742a36a7a70 + name: People + schema: + name: + type: string + name: name + age: + type: number + name: age + relationship: + type: link + name: relationship + tableId: ta_... + fieldName: relatedColumn + relationshipType: many-to-many +paths: + "/row/{tableId}/search": + post: + summary: Allows searching for rows within a table. + parameters: + - in: path + name: tableId + required: true + description: The ID of the table which contains the rows which are being + searched for. + schema: + type: string + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + query: + type: object + properties: + string: + type: object + example: + columnName1: value + columnName2: value + description: A map of field name to the string to search for, this will look for + rows that have a value starting with the string value. + additionalProperties: + type: string + description: The value to search for in the column. + fuzzy: + type: object + description: A fuzzy search, only supported by internal tables. + range: + type: object + description: Searches within a range, the format of this must be columnName -> + [low, high]. + equal: + type: object + description: Searches for rows that have a column value that is exactly the + value set. + notEqual: + type: object + description: Searches for any row which does not contain the specified column + value. + empty: + type: object + description: Searches for rows which do not contain the specified column. The + object should simply contain keys of the column names, + these can map to any value. + notEmpty: + type: object + description: Searches for rows which have the specified column. + oneOf: + type: object + description: Searches for rows which have a column value that is any of the + specified values. The format of this must be columnName + -> [value1, value2]. + paginate: + type: boolean + description: Enables pagination, by default this is disabled. + bookmark: + oneOf: + - type: string + - type: integer + description: If retrieving another page, the bookmark from the previous request + must be supplied. + limit: + type: integer + description: The maximum number of rows to return, useful when paginating, for + internal tables this will be limited to 1000, for SQL tables + it will be 5000. + sort: + type: object + description: A set of parameters describing the sort behaviour of the search. + properties: + order: + type: string + enum: + - ascending + - descending + description: The order of the sort, by default this is ascending. + column: + type: string + description: The name of the column by which the rows will be sorted. + type: + type: string + enum: + - string + - number + description: Defines whether the column should be treated as a string or as + numbers when sorting. + responses: + "200": + description: The response will contain an array of rows that match the search + parameters. + content: + application/json: + schema: + type: object + properties: + rows: + description: An array of rows, these will each contain an _id field which can be + used to update or delete them. + type: array + items: + type: object + example: + $ref: "#/components/examples/row" + bookmark: + oneOf: + - type: string + - type: integer + description: If pagination in use, this should be provided + hasNextPage: + description: If pagination in use, this will determine if there is another page + to fetch. + type: boolean +tags: [] diff --git a/packages/server/src/api/controllers/public/index.js b/packages/server/src/api/controllers/public/index.js new file mode 100644 index 0000000000..b539b02e9b --- /dev/null +++ b/packages/server/src/api/controllers/public/index.js @@ -0,0 +1,24 @@ +/* + * Contains pass through functions for all of the public API, make sure + * parameters are in correct format for the main controllers. + */ + +exports.search = () => { + +} + +exports.create = () => { + +} + +exports.singleRead = () => { + +} + +exports.update = () => { + +} + +exports.delete = () => { + +} \ No newline at end of file diff --git a/packages/server/src/api/routes/public/applications.js b/packages/server/src/api/routes/public/applications.js new file mode 100644 index 0000000000..f9a77e6bc5 --- /dev/null +++ b/packages/server/src/api/routes/public/applications.js @@ -0,0 +1,5 @@ +const Router = require("@koa/router") + +const router = Router() + +module.exports = router diff --git a/packages/server/src/api/routes/public/index.js b/packages/server/src/api/routes/public/index.js new file mode 100644 index 0000000000..a4dc684771 --- /dev/null +++ b/packages/server/src/api/routes/public/index.js @@ -0,0 +1,25 @@ +const appRoute = require("./applications") +const queryRoute = require("./queries") +const tableRoute = require("./tables") +const rowRoute = require("./rows") +const userRoute = require("./users") +const Router = require("@koa/router") + +const PREFIX = "/api/public/v1" +const ROUTES = [ + appRoute, + queryRoute, + tableRoute, + rowRoute, + userRoute +] + +const router = new Router({ + prefix: PREFIX, +}) +for (let route of ROUTES) { + router.use(route.routes()) + router.use(route.allowedMethods()) +} + +module.exports = router diff --git a/packages/server/src/api/routes/public/queries.js b/packages/server/src/api/routes/public/queries.js new file mode 100644 index 0000000000..f9a77e6bc5 --- /dev/null +++ b/packages/server/src/api/routes/public/queries.js @@ -0,0 +1,5 @@ +const Router = require("@koa/router") + +const router = Router() + +module.exports = router diff --git a/packages/server/src/api/routes/public/rows.js b/packages/server/src/api/routes/public/rows.js new file mode 100644 index 0000000000..f4c59eaf9f --- /dev/null +++ b/packages/server/src/api/routes/public/rows.js @@ -0,0 +1,130 @@ +const Router = require("@koa/router") +const controller = require("../../controllers/public") + +const router = Router() + +/** + * @openapi + * /row/{tableId}/search: + * post: + * summary: Allows searching for rows within a table. + * parameters: + * - in: path + * name: tableId + * required: true + * description: The ID of the table which contains the rows + * which are being searched for. + * schema: + * type: string + * requestBody: + * required: true + * content: + * application/json: + * schema: + * type: object + * properties: + * query: + * type: object + * properties: + * string: + * type: object + * example: + * columnName1: value + * columnName2: value + * description: A map of field name to the string to search for, + * this will look for rows that have a value starting with the + * string value. + * additionalProperties: + * type: string + * description: The value to search for in the column. + * fuzzy: + * type: object + * description: A fuzzy search, only supported by internal tables. + * range: + * type: object + * description: Searches within a range, the format of this must be + * columnName -> [low, high]. + * equal: + * type: object + * description: Searches for rows that have a column value that is + * exactly the value set. + * notEqual: + * type: object + * description: Searches for any row which does not contain the specified + * column value. + * empty: + * type: object + * description: Searches for rows which do not contain the specified column. + * The object should simply contain keys of the column names, these + * can map to any value. + * notEmpty: + * type: object + * description: Searches for rows which have the specified column. + * oneOf: + * type: object + * description: Searches for rows which have a column value that is any + * of the specified values. The format of this must be columnName -> [value1, value2]. + * paginate: + * type: boolean + * description: Enables pagination, by default this is disabled. + * bookmark: + * oneOf: + * - type: string + * - type: integer + * description: If retrieving another page, the bookmark from the previous request must be supplied. + * limit: + * type: integer + * description: The maximum number of rows to return, useful when paginating, for internal tables this + * will be limited to 1000, for SQL tables it will be 5000. + * sort: + * type: object + * description: A set of parameters describing the sort behaviour of the search. + * properties: + * order: + * type: string + * enum: [ascending, descending] + * description: The order of the sort, by default this is ascending. + * column: + * type: string + * description: The name of the column by which the rows will be sorted. + * type: + * type: string + * enum: [string, number] + * description: Defines whether the column should be treated as a string + * or as numbers when sorting. + * responses: + * 200: + * description: The response will contain an array of rows that match the search parameters. + * content: + * application/json: + * schema: + * type: object + * properties: + * rows: + * description: An array of rows, these will each contain an _id field which can be used + * to update or delete them. + * type: array + * items: + * type: object + * example: + * $ref: '#/components/examples/row' + * bookmark: + * oneOf: + * - type: string + * - type: integer + * description: If pagination in use, this should be provided + * hasNextPage: + * description: If pagination in use, this will determine if there is another page to fetch. + * type: boolean + */ +router.post("/tables/:tableId/rows/search", controller.search) + +router.post("/tables/:tableId/rows", controller.create) + +router.put("/tables/:tableId/rows/:rowId", controller.update) + +router.delete("/tables/:tableId/rows/:rowId", controller.delete) + +router.get("/tables/:tableId/rows/:rowId", controller.singleRead) + +module.exports = router diff --git a/packages/server/src/api/routes/public/tables.js b/packages/server/src/api/routes/public/tables.js new file mode 100644 index 0000000000..f9a77e6bc5 --- /dev/null +++ b/packages/server/src/api/routes/public/tables.js @@ -0,0 +1,5 @@ +const Router = require("@koa/router") + +const router = Router() + +module.exports = router diff --git a/packages/server/src/api/routes/public/users.js b/packages/server/src/api/routes/public/users.js new file mode 100644 index 0000000000..f9a77e6bc5 --- /dev/null +++ b/packages/server/src/api/routes/public/users.js @@ -0,0 +1,5 @@ +const Router = require("@koa/router") + +const router = Router() + +module.exports = router