From 9b28414bbb99428d6bc5b4264caa3d65c6aceee1 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Fri, 18 Feb 2022 15:47:15 +0000 Subject: [PATCH] Rows API mostly complete, starting into tables. --- packages/server/package.json | 1 + packages/server/specs/examples.js | 32 ++- packages/server/specs/generate.js | 18 +- packages/server/specs/openapi.json | 255 ++++++++++++++++-- packages/server/specs/openapi.yaml | 156 +++++++++-- packages/server/specs/parameters.js | 13 +- packages/server/specs/security.js | 7 + .../controllers/public/{index.js => rows.js} | 5 - .../src/api/controllers/public/tables.js | 19 ++ packages/server/src/api/routes/public/rows.js | 104 ++++++- .../server/src/api/routes/public/tables.js | 112 ++++++++ 11 files changed, 652 insertions(+), 70 deletions(-) create mode 100644 packages/server/specs/security.js rename packages/server/src/api/controllers/public/{index.js => rows.js} (50%) create mode 100644 packages/server/src/api/controllers/public/tables.js diff --git a/packages/server/package.json b/packages/server/package.json index 2105c35c00..d666389284 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -22,6 +22,7 @@ "dev:stack:nuke": "node scripts/dev/manage.js nuke", "dev:builder": "yarn run dev:stack:up && nodemon", "format": "prettier --config ../../.prettierrc.json 'src/**/*.ts' --write", + "specs": "node specs/generate.js", "lint": "eslint --fix src/", "lint:fix": "yarn run format && yarn run lint", "initialise": "node scripts/initialise.js", diff --git a/packages/server/specs/examples.js b/packages/server/specs/examples.js index 855ea16bab..0ae5da4025 100644 --- a/packages/server/specs/examples.js +++ b/packages/server/specs/examples.js @@ -1,3 +1,17 @@ +const row = { + _id: "ro_ta_5b1649e42a5b41dea4ef7742a36a7a70_e6dc7e38cf1343b2b56760265201cda4", + type: "row", + tableId: "ta_5b1649e42a5b41dea4ef7742a36a7a70", + name: "Mike", + age: 30, + relationship: [ + { + primaryDisplay: "Joe", + _id: "ro_ta_...", + }, + ], +} + exports.table = { value: { _id: "ta_5b1649e42a5b41dea4ef7742a36a7a70", @@ -23,17 +37,13 @@ exports.table = { } exports.row = { + value: row, +} + +exports.search = { value: { - _id: "ro_ta_5b1649e42a5b41dea4ef7742a36a7a70_e6dc7e38cf1343b2b56760265201cda4", - type: "row", - tableId: "ta_5b1649e42a5b41dea4ef7742a36a7a70", - name: "Mike", - age: 30, - relationship: [ - { - primaryDisplay: "Joe", - _id: "ro_ta_...", - }, - ], + rows: [row], + hasNextPage: true, + bookmark: 10, }, } diff --git a/packages/server/specs/generate.js b/packages/server/specs/generate.js index b6f227e30e..351c2b8728 100644 --- a/packages/server/specs/generate.js +++ b/packages/server/specs/generate.js @@ -1,8 +1,9 @@ const swaggerJsdoc = require("swagger-jsdoc") const { join } = require("path") const { writeFileSync } = require("fs") -const { row, table } = require("./examples") -const { tableId } = require("./parameters") +const examples = require("./examples") +const parameters = require("./parameters") +const security = require("./security") const VARIABLES = {} @@ -26,13 +27,20 @@ const options = { ], components: { parameters: { - tableId: tableId, + ...parameters, }, examples: { - row: row, - table: table, + ...examples, + }, + securitySchemes: { + ...security, }, }, + security: [ + { + ApiKeyAuth: [], + }, + ], }, format: ".json", apis: [join(__dirname, "..", "src", "api", "routes", "public", "*.js")], diff --git a/packages/server/specs/openapi.json b/packages/server/specs/openapi.json index 76fa784877..2d2dd9b05d 100644 --- a/packages/server/specs/openapi.json +++ b/packages/server/specs/openapi.json @@ -21,28 +21,22 @@ "in": "path", "name": "tableId", "required": true, - "description": "The ID of the table which contains the rows which are being searched for.", + "description": "The ID of the table which this request is targeting.", + "schema": { + "type": "string" + } + }, + "rowId": { + "in": "path", + "name": "rowId", + "required": true, + "description": "The ID of the row which this request is targeting.", "schema": { "type": "string" } } }, "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", @@ -65,13 +59,65 @@ } } } + }, + "row": { + "value": { + "_id": "ro_ta_5b1649e42a5b41dea4ef7742a36a7a70_e6dc7e38cf1343b2b56760265201cda4", + "type": "row", + "tableId": "ta_5b1649e42a5b41dea4ef7742a36a7a70", + "name": "Mike", + "age": 30, + "relationship": [ + { + "primaryDisplay": "Joe", + "_id": "ro_ta_..." + } + ] + } + }, + "search": { + "value": { + "rows": [ + { + "_id": "ro_ta_5b1649e42a5b41dea4ef7742a36a7a70_e6dc7e38cf1343b2b56760265201cda4", + "type": "row", + "tableId": "ta_5b1649e42a5b41dea4ef7742a36a7a70", + "name": "Mike", + "age": 30, + "relationship": [ + { + "primaryDisplay": "Joe", + "_id": "ro_ta_..." + } + ] + } + ], + "hasNextPage": true, + "bookmark": 10 + } + } + }, + "securitySchemes": { + "ApiKeyAuth": { + "type": "apiKey", + "in": "header", + "name": "x-budibase-api-key", + "description": "Your individual API key, this will provide access based on the configured RBAC settings of your user." } } }, + "security": [ + { + "ApiKeyAuth": [] + } + ], "paths": { "/tables/{tableId}/rows/search": { "post": { - "summary": "Allows searching for rows within a table.", + "summary": "Used to search for rows within a table.", + "tags": [ + "rows" + ], "parameters": [ { "$ref": "#/components/parameters/tableId" @@ -191,10 +237,7 @@ "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" - } + "type": "object" } }, "bookmark": { @@ -206,12 +249,17 @@ "type": "integer" } ], - "description": "If pagination in use, this should be provided" + "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" } + }, + "examples": { + "search": [ + "#/components/examples/search" + ] } } } @@ -222,12 +270,81 @@ }, "/tables/{tableId}/rows": { "post": { - "summary": "Allows creating a row within a specified table.", + "summary": "Creates a new row within a specified table.", + "tags": [ + "rows" + ], "parameters": [ { "$ref": "#/components/parameters/tableId" } ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "description": "The contents of the row which is to be created, the keys of", + "type": "object", + "example": { + "$ref": "#/components/examples/row" + }, + "additionalProperties": { + "oneOf": [ + { + "type": "string" + }, + { + "type": "object" + }, + { + "type": "integer" + }, + { + "type": "array" + }, + { + "type": "boolean" + } + ] + } + } + } + } + }, + "responses": { + "200": { + "description": "Returns the created row, including the ID which has been generated for it. This can be found in the Budibase portal, viewed under the developer information.", + "content": { + "application/json": { + "schema": { + "type": "object" + }, + "examples": { + "row": { + "$ref": "#/components/examples/row" + } + } + } + } + } + } + } + }, + "/tables/{tableId}/rows/{rowId}": { + "put": { + "summary": "Update a single row within a specified table.", + "tags": [ + "rows" + ], + "parameters": [ + { + "$ref": "#/components/parameters/tableId" + }, + { + "$ref": "#/components/parameters/rowId" + } + ], "responses": { "200": { "description": "Returns the created row, including the ID which has been generated for it.", @@ -235,6 +352,98 @@ "application/json": { "schema": { "type": "object" + }, + "examples": { + "row": { + "$ref": "#/components/examples/row" + } + } + } + } + } + } + }, + "delete": { + "summary": "Delete a single row from the specified table.", + "tags": [ + "rows" + ], + "parameters": [ + { + "$ref": "#/components/parameters/tableId" + }, + { + "$ref": "#/components/parameters/rowId" + } + ], + "responses": { + "200": { + "description": "Returns the deleted row, including the ID which has been generated for it.", + "content": { + "application/json": { + "schema": { + "type": "object" + }, + "examples": { + "row": { + "$ref": "#/components/examples/row" + } + } + } + } + } + } + }, + "get": { + "summary": "Get a single row from the specified table.", + "tags": [ + "rows" + ], + "parameters": [ + { + "$ref": "#/components/parameters/tableId" + }, + { + "$ref": "#/components/parameters/rowId" + } + ], + "responses": { + "200": { + "description": "Returns the retrieved row.", + "content": { + "application/json": { + "schema": { + "type": "object" + }, + "examples": { + "row": { + "$ref": "#/components/examples/row" + } + } + } + } + } + } + } + }, + "/tables": { + "post": { + "summary": "Create a new table", + "tags": [ + "tables" + ], + "responses": { + "200": { + "description": "Returns the created table, including the ID which has been generated for it.", + "content": { + "application/json": { + "schema": { + "type": "object" + }, + "examples": { + "row": { + "$ref": "#/components/examples/table" + } } } } diff --git a/packages/server/specs/openapi.yaml b/packages/server/specs/openapi.yaml index 6b4328fef3..eeb729a1e4 100644 --- a/packages/server/specs/openapi.yaml +++ b/packages/server/specs/openapi.yaml @@ -14,20 +14,17 @@ components: in: path name: tableId required: true - description: The ID of the table which contains the rows which are being searched for. + description: The ID of the table which this request is targeting. + schema: + type: string + rowId: + in: path + name: rowId + required: true + description: The ID of the row which this request is targeting. schema: type: string 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 @@ -45,10 +42,44 @@ components: tableId: ta_... fieldName: relatedColumn relationshipType: many-to-many + row: + value: + _id: ro_ta_5b1649e42a5b41dea4ef7742a36a7a70_e6dc7e38cf1343b2b56760265201cda4 + type: row + tableId: ta_5b1649e42a5b41dea4ef7742a36a7a70 + name: Mike + age: 30 + relationship: + - primaryDisplay: Joe + _id: ro_ta_... + search: + value: + rows: + - _id: ro_ta_5b1649e42a5b41dea4ef7742a36a7a70_e6dc7e38cf1343b2b56760265201cda4 + type: row + tableId: ta_5b1649e42a5b41dea4ef7742a36a7a70 + name: Mike + age: 30 + relationship: + - primaryDisplay: Joe + _id: ro_ta_... + hasNextPage: true + bookmark: 10 + securitySchemes: + ApiKeyAuth: + type: apiKey + in: header + name: x-budibase-api-key + description: Your individual API key, this will provide access based on the + configured RBAC settings of your user. +security: + - ApiKeyAuth: [] paths: "/tables/{tableId}/rows/search": post: - summary: Allows searching for rows within a table. + summary: Used to search for rows within a table. + tags: + - rows parameters: - $ref: "#/components/parameters/tableId" requestBody: @@ -148,22 +179,61 @@ paths: 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 + 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 + examples: + search: + - "#/components/examples/search" "/tables/{tableId}/rows": post: - summary: Allows creating a row within a specified table. + summary: Creates a new row within a specified table. + tags: + - rows parameters: - $ref: "#/components/parameters/tableId" + requestBody: + required: true + content: + application/json: + schema: + description: The contents of the row which is to be created, the keys of + type: object + example: + $ref: "#/components/examples/row" + additionalProperties: + oneOf: + - type: string + - type: object + - type: integer + - type: array + - type: boolean + responses: + "200": + description: Returns the created row, including the ID which has been generated + for it. This can be found in the Budibase portal, viewed under the + developer information. + content: + application/json: + schema: + type: object + examples: + row: + $ref: "#/components/examples/row" + "/tables/{tableId}/rows/{rowId}": + put: + summary: Update a single row within a specified table. + tags: + - rows + parameters: + - $ref: "#/components/parameters/tableId" + - $ref: "#/components/parameters/rowId" responses: "200": description: Returns the created row, including the ID which has been generated @@ -172,4 +242,58 @@ paths: application/json: schema: type: object + examples: + row: + $ref: "#/components/examples/row" + delete: + summary: Delete a single row from the specified table. + tags: + - rows + parameters: + - $ref: "#/components/parameters/tableId" + - $ref: "#/components/parameters/rowId" + responses: + "200": + description: Returns the deleted row, including the ID which has been generated + for it. + content: + application/json: + schema: + type: object + examples: + row: + $ref: "#/components/examples/row" + get: + summary: Get a single row from the specified table. + tags: + - rows + parameters: + - $ref: "#/components/parameters/tableId" + - $ref: "#/components/parameters/rowId" + responses: + "200": + description: Returns the retrieved row. + content: + application/json: + schema: + type: object + examples: + row: + $ref: "#/components/examples/row" + /tables: + post: + summary: Create a new table + tags: + - tables + responses: + "200": + description: Returns the created table, including the ID which has been + generated for it. + content: + application/json: + schema: + type: object + examples: + row: + $ref: "#/components/examples/table" tags: [] diff --git a/packages/server/specs/parameters.js b/packages/server/specs/parameters.js index a01bd6f3b8..ce5874c3f1 100644 --- a/packages/server/specs/parameters.js +++ b/packages/server/specs/parameters.js @@ -2,8 +2,17 @@ exports.tableId = { in: "path", name: "tableId", required: true, - description: - "The ID of the table which contains the rows which are being searched for.", + description: "The ID of the table which this request is targeting.", + schema: { + type: "string", + }, +} + +exports.rowId = { + in: "path", + name: "rowId", + required: true, + description: "The ID of the row which this request is targeting.", schema: { type: "string", }, diff --git a/packages/server/specs/security.js b/packages/server/specs/security.js new file mode 100644 index 0000000000..cbdeb40c63 --- /dev/null +++ b/packages/server/specs/security.js @@ -0,0 +1,7 @@ +exports.ApiKeyAuth = { + type: "apiKey", + in: "header", + name: "x-budibase-api-key", + description: + "Your individual API key, this will provide access based on the configured RBAC settings of your user.", +} diff --git a/packages/server/src/api/controllers/public/index.js b/packages/server/src/api/controllers/public/rows.js similarity index 50% rename from packages/server/src/api/controllers/public/index.js rename to packages/server/src/api/controllers/public/rows.js index b539b02e9b..7c2fad4102 100644 --- a/packages/server/src/api/controllers/public/index.js +++ b/packages/server/src/api/controllers/public/rows.js @@ -1,8 +1,3 @@ -/* - * Contains pass through functions for all of the public API, make sure - * parameters are in correct format for the main controllers. - */ - exports.search = () => { } diff --git a/packages/server/src/api/controllers/public/tables.js b/packages/server/src/api/controllers/public/tables.js new file mode 100644 index 0000000000..68302f1120 --- /dev/null +++ b/packages/server/src/api/controllers/public/tables.js @@ -0,0 +1,19 @@ +exports.create = () => { + +} + +exports.getAllTables = () => { + +} + +exports.getSingleTable = () => { + +} + +exports.update = () => { + +} + +exports.delete = () => { + +} \ No newline at end of file diff --git a/packages/server/src/api/routes/public/rows.js b/packages/server/src/api/routes/public/rows.js index e1e558a7f9..2e86e53aec 100644 --- a/packages/server/src/api/routes/public/rows.js +++ b/packages/server/src/api/routes/public/rows.js @@ -1,5 +1,5 @@ const Router = require("@koa/router") -const controller = require("../../controllers/public") +const controller = require("../../controllers/public/rows") const router = Router() @@ -7,7 +7,9 @@ const router = Router() * @openapi * /tables/{tableId}/rows/search: * post: - * summary: Allows searching for rows within a table. + * summary: Used to search for rows within a table. + * tags: + * - rows * parameters: * - $ref: '#/components/parameters/tableId' * requestBody: @@ -100,16 +102,17 @@ const router = Router() * 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 + * 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 + * examples: + * search: + * - '#/components/examples/search' */ router.post("/tables/:tableId/rows/search", controller.search) @@ -117,9 +120,51 @@ router.post("/tables/:tableId/rows/search", controller.search) * @openapi * /tables/{tableId}/rows: * post: - * summary: Allows creating a row within a specified table. + * summary: Creates a new row within a specified table. + * tags: + * - rows * parameters: * - $ref: '#/components/parameters/tableId' + * requestBody: + * required: true + * content: + * application/json: + * schema: + * description: The contents of the row which is to be created, the keys of + * type: object + * example: + * $ref: '#/components/examples/row' + * additionalProperties: + * oneOf: + * - type: string + * - type: object + * - type: integer + * - type: array + * - type: boolean + * responses: + * 200: + * description: Returns the created row, including the ID which has been generated for it. + * This can be found in the Budibase portal, viewed under the developer information. + * content: + * application/json: + * schema: + * type: object + * examples: + * row: + * $ref: '#/components/examples/row' + */ +router.post("/tables/:tableId/rows", controller.create) + +/** + * @openapi + * /tables/{tableId}/rows/{rowId}: + * put: + * summary: Update a single row within a specified table. + * tags: + * - rows + * parameters: + * - $ref: '#/components/parameters/tableId' + * - $ref: '#/components/parameters/rowId' * responses: * 200: * description: Returns the created row, including the ID which has been generated for it. @@ -127,13 +172,56 @@ router.post("/tables/:tableId/rows/search", controller.search) * application/json: * schema: * type: object + * examples: + * row: + * $ref: '#/components/examples/row' */ -router.post("/tables/:tableId/rows", controller.create) - router.put("/tables/:tableId/rows/:rowId", controller.update) +/** + * @openapi + * /tables/{tableId}/rows/{rowId}: + * delete: + * summary: Delete a single row from the specified table. + * tags: + * - rows + * parameters: + * - $ref: '#/components/parameters/tableId' + * - $ref: '#/components/parameters/rowId' + * responses: + * 200: + * description: Returns the deleted row, including the ID which has been generated for it. + * content: + * application/json: + * schema: + * type: object + * examples: + * row: + * $ref: '#/components/examples/row' + */ router.delete("/tables/:tableId/rows/:rowId", controller.delete) +/** + * @openapi + * /tables/{tableId}/rows/{rowId}: + * get: + * summary: Get a single row from the specified table. + * tags: + * - rows + * parameters: + * - $ref: '#/components/parameters/tableId' + * - $ref: '#/components/parameters/rowId' + * responses: + * 200: + * description: Returns the retrieved row. + * content: + * application/json: + * schema: + * type: object + * examples: + * row: + * $ref: '#/components/examples/row' + */ 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 index f9a77e6bc5..abc5734710 100644 --- a/packages/server/src/api/routes/public/tables.js +++ b/packages/server/src/api/routes/public/tables.js @@ -1,5 +1,117 @@ const Router = require("@koa/router") +const controller = require("../../controllers/public/tables") const router = Router() +/** + * @openapi + * /tables: + * post: + * summary: Create a new table + * tags: + * - tables + * responses: + * 200: + * description: Returns the created table, including the ID which has been generated for it. + * content: + * application/json: + * schema: + * type: object + * examples: + * row: + * $ref: '#/components/examples/table' + */ +router.post("/tables", controller.create) + +/** + * @openapi + * /tables/:tableId: + * put: + * summary: Update a single row within a specified table. + * tags: + * - tables + * parameters: + * - $ref: '#/components/parameters/tableId' + * - $ref: '#/components/parameters/rowId' + * responses: + * 200: + * description: Returns the created row, including the ID which has been generated for it. + * content: + * application/json: + * schema: + * type: object + * examples: + * row: + * $ref: '#/components/examples/row' + */ +router.put("/tables/:tableId", controller.update) + +/** + * @openapi + * /tables: + * get: + * summary: Update a single row within a specified table. + * tags: + * - tables + * parameters: + * - $ref: '#/components/parameters/tableId' + * - $ref: '#/components/parameters/rowId' + * responses: + * 200: + * description: Returns the created row, including the ID which has been generated for it. + * content: + * application/json: + * schema: + * type: object + * examples: + * row: + * $ref: '#/components/examples/row' + */ +router.get("/tables", controller.getAllTables) + +/** + * @openapi + * /tables/{tableId}/rows/{rowId}: + * put: + * summary: Update a single row within a specified table. + * tags: + * - rows + * parameters: + * - $ref: '#/components/parameters/tableId' + * - $ref: '#/components/parameters/rowId' + * responses: + * 200: + * description: Returns the created row, including the ID which has been generated for it. + * content: + * application/json: + * schema: + * type: object + * examples: + * row: + * $ref: '#/components/examples/row' + */ +router.get("/tables/:tableId", controller.getSingleTable) + +/** + * @openapi + * /tables/{tableId}/rows/{rowId}: + * put: + * summary: Update a single row within a specified table. + * tags: + * - rows + * parameters: + * - $ref: '#/components/parameters/tableId' + * - $ref: '#/components/parameters/rowId' + * responses: + * 200: + * description: Returns the created row, including the ID which has been generated for it. + * content: + * application/json: + * schema: + * type: object + * examples: + * row: + * $ref: '#/components/examples/row' + */ +router.delete("/tables/:tableId", controller.delete) module.exports = router