Adding a testing system which generates the schema and compares against responses.
This commit is contained in:
parent
53f108865a
commit
01bb56cbf4
|
@ -53,10 +53,10 @@
|
||||||
to-gfm-code-block "^0.1.1"
|
to-gfm-code-block "^0.1.1"
|
||||||
year "^0.2.1"
|
year "^0.2.1"
|
||||||
|
|
||||||
"@budibase/string-templates@^1.0.66-alpha.0":
|
"@budibase/string-templates@^1.0.72-alpha.0":
|
||||||
version "1.0.72"
|
version "1.0.75"
|
||||||
resolved "https://registry.yarnpkg.com/@budibase/string-templates/-/string-templates-1.0.72.tgz#acc154e402cce98ea30eedde9c6124183ee9b37c"
|
resolved "https://registry.yarnpkg.com/@budibase/string-templates/-/string-templates-1.0.75.tgz#5b4061f1a626160ec092f32f036541376298100c"
|
||||||
integrity sha512-w715TjgO6NUHkZNqoOEo8lAKJ/PQ4b00ATWSX5VB523SAu7y/uOiqKqV1E3fgwxq1o8L+Ff7rn9FTkiYtjkV/g==
|
integrity sha512-hPgr6n5cpSCGFEha5DS/P+rtRXOLc72M6y4J/scl59JvUi/ZUJkjRgJdpQPdBLu04CNKp89V59+rAqAuDjOC0g==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@budibase/handlebars-helpers" "^0.11.7"
|
"@budibase/handlebars-helpers" "^0.11.7"
|
||||||
dayjs "^1.10.4"
|
dayjs "^1.10.4"
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -53,6 +53,7 @@ module FetchMock {
|
||||||
{
|
{
|
||||||
doc: {
|
doc: {
|
||||||
_id: "test",
|
_id: "test",
|
||||||
|
tableId: opts.body.split("tableId:")[1].split('"')[0],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
|
|
@ -158,6 +158,7 @@
|
||||||
"docker-compose": "^0.23.6",
|
"docker-compose": "^0.23.6",
|
||||||
"eslint": "^6.8.0",
|
"eslint": "^6.8.0",
|
||||||
"jest": "^27.0.5",
|
"jest": "^27.0.5",
|
||||||
|
"jest-openapi": "^0.14.2",
|
||||||
"nodemon": "^2.0.4",
|
"nodemon": "^2.0.4",
|
||||||
"openapi-types": "^9.3.1",
|
"openapi-types": "^9.3.1",
|
||||||
"path-to-regexp": "^6.2.0",
|
"path-to-regexp": "^6.2.0",
|
||||||
|
|
|
@ -49,12 +49,11 @@ const options = {
|
||||||
apis: [join(__dirname, "..", "src", "api", "routes", "public", "*.ts")],
|
apis: [join(__dirname, "..", "src", "api", "routes", "public", "*.ts")],
|
||||||
}
|
}
|
||||||
|
|
||||||
function writeFile(output, { isJson } = {}) {
|
function writeFile(output, filename) {
|
||||||
try {
|
try {
|
||||||
const filename = isJson ? "openapi.json" : "openapi.yaml"
|
|
||||||
const path = join(__dirname, filename)
|
const path = join(__dirname, filename)
|
||||||
let spec = output
|
let spec = output
|
||||||
if (isJson) {
|
if (filename.endsWith("json")) {
|
||||||
spec = JSON.stringify(output, null, 2)
|
spec = JSON.stringify(output, null, 2)
|
||||||
}
|
}
|
||||||
// input the static variables
|
// input the static variables
|
||||||
|
@ -63,13 +62,22 @@ function writeFile(output, { isJson } = {}) {
|
||||||
}
|
}
|
||||||
writeFileSync(path, spec)
|
writeFileSync(path, spec)
|
||||||
console.log(`Wrote spec to ${path}`)
|
console.log(`Wrote spec to ${path}`)
|
||||||
|
return path
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(err)
|
console.error(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const outputJSON = swaggerJsdoc(options)
|
function run() {
|
||||||
options.format = ".yaml"
|
const outputJSON = swaggerJsdoc(options)
|
||||||
const outputYAML = swaggerJsdoc(options)
|
options.format = ".yaml"
|
||||||
writeFile(outputJSON, { isJson: true })
|
const outputYAML = swaggerJsdoc(options)
|
||||||
writeFile(outputYAML)
|
writeFile(outputJSON, "openapi.json")
|
||||||
|
return writeFile(outputYAML, "openapi.yaml")
|
||||||
|
}
|
||||||
|
|
||||||
|
if (require.main === module) {
|
||||||
|
run()
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = run
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -63,6 +63,7 @@ const baseColumnDef = {
|
||||||
const tableSchema = {
|
const tableSchema = {
|
||||||
description: "The table to be created/updated.",
|
description: "The table to be created/updated.",
|
||||||
type: "object",
|
type: "object",
|
||||||
|
required: ["name", "schema"],
|
||||||
properties: {
|
properties: {
|
||||||
name: {
|
name: {
|
||||||
description: "The name of the table",
|
description: "The name of the table",
|
||||||
|
@ -74,82 +75,85 @@ const tableSchema = {
|
||||||
"The name of the column which should be used in relationship tags when relating to this table.",
|
"The name of the column which should be used in relationship tags when relating to this table.",
|
||||||
},
|
},
|
||||||
schema: {
|
schema: {
|
||||||
oneOf: [
|
type: "object",
|
||||||
// relationship
|
additionalProperties: {
|
||||||
{
|
oneOf: [
|
||||||
type: "object",
|
// relationship
|
||||||
properties: {
|
{
|
||||||
...baseColumnDef,
|
type: "object",
|
||||||
type: {
|
properties: {
|
||||||
type: "string",
|
...baseColumnDef,
|
||||||
enum: [FieldTypes.LINK],
|
type: {
|
||||||
description: "A relationship column.",
|
type: "string",
|
||||||
},
|
enum: [FieldTypes.LINK],
|
||||||
fieldName: {
|
description: "A relationship column.",
|
||||||
type: "string",
|
},
|
||||||
description:
|
fieldName: {
|
||||||
"The name of the column which a relationship column is related to in another table.",
|
type: "string",
|
||||||
},
|
description:
|
||||||
tableId: {
|
"The name of the column which a relationship column is related to in another table.",
|
||||||
type: "string",
|
},
|
||||||
description:
|
tableId: {
|
||||||
"The ID of the table which a relationship column is related to.",
|
type: "string",
|
||||||
},
|
description:
|
||||||
relationshipType: {
|
"The ID of the table which a relationship column is related to.",
|
||||||
type: "string",
|
},
|
||||||
enum: Object.values(RelationshipTypes),
|
relationshipType: {
|
||||||
description:
|
type: "string",
|
||||||
"Defines the type of relationship that this column will be used for.",
|
enum: Object.values(RelationshipTypes),
|
||||||
},
|
description:
|
||||||
through: {
|
"Defines the type of relationship that this column will be used for.",
|
||||||
type: "string",
|
},
|
||||||
description:
|
through: {
|
||||||
"When using a SQL table that contains many to many relationships this defines the table the relationships are linked through.",
|
type: "string",
|
||||||
},
|
description:
|
||||||
foreignKey: {
|
"When using a SQL table that contains many to many relationships this defines the table the relationships are linked through.",
|
||||||
type: "string",
|
},
|
||||||
description:
|
foreignKey: {
|
||||||
"When using a SQL table that contains a one to many relationship this defines the foreign key.",
|
type: "string",
|
||||||
},
|
description:
|
||||||
throughFrom: {
|
"When using a SQL table that contains a one to many relationship this defines the foreign key.",
|
||||||
type: "string",
|
},
|
||||||
description:
|
throughFrom: {
|
||||||
"When using a SQL table that utilises a through table, this defines the primary key in the through table for this table.",
|
type: "string",
|
||||||
},
|
description:
|
||||||
throughTo: {
|
"When using a SQL table that utilises a through table, this defines the primary key in the through table for this table.",
|
||||||
type: "string",
|
},
|
||||||
description:
|
throughTo: {
|
||||||
"When using a SQL table that utilises a through table, this defines the primary key in the through table for the related table.",
|
type: "string",
|
||||||
|
description:
|
||||||
|
"When using a SQL table that utilises a through table, this defines the primary key in the through table for the related table.",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
{
|
||||||
{
|
type: "object",
|
||||||
type: "object",
|
properties: {
|
||||||
properties: {
|
...baseColumnDef,
|
||||||
...baseColumnDef,
|
type: {
|
||||||
type: {
|
type: "string",
|
||||||
type: "string",
|
enum: [FieldTypes.FORMULA],
|
||||||
enum: [FieldTypes.FORMULA],
|
description: "A formula column.",
|
||||||
description: "A formula column.",
|
},
|
||||||
},
|
formula: {
|
||||||
formula: {
|
type: "string",
|
||||||
type: "string",
|
description:
|
||||||
description:
|
"Defines a Handlebars or JavaScript formula to use, note that Javascript formulas are expected to be provided in the base64 format.",
|
||||||
"Defines a Handlebars or JavaScript formula to use, note that Javascript formulas are expected to be provided in the base64 format.",
|
},
|
||||||
},
|
formulaType: {
|
||||||
formulaType: {
|
type: "string",
|
||||||
type: "string",
|
enum: Object.values(FormulaTypes),
|
||||||
enum: Object.values(FormulaTypes),
|
description:
|
||||||
description:
|
"Defines whether this is a static or dynamic formula.",
|
||||||
"Defines whether this is a static or dynamic formula.",
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
{
|
||||||
{
|
type: "object",
|
||||||
type: "object",
|
properties: baseColumnDef,
|
||||||
properties: baseColumnDef,
|
},
|
||||||
},
|
],
|
||||||
],
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ exports.object = (props, opts) => {
|
||||||
return {
|
return {
|
||||||
type: "object",
|
type: "object",
|
||||||
properties: props,
|
properties: props,
|
||||||
|
required: Object.keys(props),
|
||||||
...opts,
|
...opts,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,43 +5,6 @@ const { nameValidator, applicationValidator } = require("../utils/validators")
|
||||||
const read = [],
|
const read = [],
|
||||||
write = []
|
write = []
|
||||||
|
|
||||||
/**
|
|
||||||
* @openapi
|
|
||||||
* /applications/search:
|
|
||||||
* post:
|
|
||||||
* summary: Search for an application based on its app name.
|
|
||||||
* tags:
|
|
||||||
* - applications
|
|
||||||
* parameters:
|
|
||||||
* - $ref: '#/components/parameters/appId'
|
|
||||||
* requestBody:
|
|
||||||
* required: true
|
|
||||||
* content:
|
|
||||||
* application/json:
|
|
||||||
* schema:
|
|
||||||
* $ref: '#/components/schemas/nameSearch'
|
|
||||||
* responses:
|
|
||||||
* 200:
|
|
||||||
* description: Returns the applications that were found based on the search parameters.
|
|
||||||
* content:
|
|
||||||
* application/json:
|
|
||||||
* schema:
|
|
||||||
* type: object
|
|
||||||
* properties:
|
|
||||||
* applications:
|
|
||||||
* type: array
|
|
||||||
* items:
|
|
||||||
* $ref: '#/components/schemas/application'
|
|
||||||
* examples:
|
|
||||||
* applications:
|
|
||||||
* $ref: '#/components/examples/applications'
|
|
||||||
*/
|
|
||||||
read.push(
|
|
||||||
new Endpoint("post", "/applications/search", controller.search).addMiddleware(
|
|
||||||
nameValidator()
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @openapi
|
* @openapi
|
||||||
* /applications:
|
* /applications:
|
||||||
|
@ -68,7 +31,11 @@ read.push(
|
||||||
* application:
|
* application:
|
||||||
* $ref: '#/components/examples/application'
|
* $ref: '#/components/examples/application'
|
||||||
*/
|
*/
|
||||||
write.push(new Endpoint("post", "/applications", controller.create))
|
write.push(
|
||||||
|
new Endpoint("post", "/applications", controller.create).addMiddleware(
|
||||||
|
applicationValidator
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @openapi
|
* @openapi
|
||||||
|
@ -96,7 +63,11 @@ write.push(new Endpoint("post", "/applications", controller.create))
|
||||||
* application:
|
* application:
|
||||||
* $ref: '#/components/examples/application'
|
* $ref: '#/components/examples/application'
|
||||||
*/
|
*/
|
||||||
write.push(new Endpoint("put", "/applications/:appId", controller.update))
|
write.push(
|
||||||
|
new Endpoint("put", "/applications/:appId", controller.update).addMiddleware(
|
||||||
|
applicationValidator
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @openapi
|
* @openapi
|
||||||
|
@ -142,4 +113,43 @@ write.push(new Endpoint("delete", "/applications/:appId", controller.destroy))
|
||||||
*/
|
*/
|
||||||
read.push(new Endpoint("get", "/applications/:appId", controller.read))
|
read.push(new Endpoint("get", "/applications/:appId", controller.read))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @openapi
|
||||||
|
* /applications/search:
|
||||||
|
* post:
|
||||||
|
* summary: Search for an application based on its app name.
|
||||||
|
* tags:
|
||||||
|
* - applications
|
||||||
|
* parameters:
|
||||||
|
* - $ref: '#/components/parameters/appId'
|
||||||
|
* requestBody:
|
||||||
|
* required: true
|
||||||
|
* content:
|
||||||
|
* application/json:
|
||||||
|
* schema:
|
||||||
|
* $ref: '#/components/schemas/nameSearch'
|
||||||
|
* responses:
|
||||||
|
* 200:
|
||||||
|
* description: Returns the applications that were found based on the search parameters.
|
||||||
|
* content:
|
||||||
|
* application/json:
|
||||||
|
* schema:
|
||||||
|
* type: object
|
||||||
|
* required:
|
||||||
|
* - applications
|
||||||
|
* properties:
|
||||||
|
* applications:
|
||||||
|
* type: array
|
||||||
|
* items:
|
||||||
|
* $ref: '#/components/schemas/application'
|
||||||
|
* examples:
|
||||||
|
* applications:
|
||||||
|
* $ref: '#/components/examples/applications'
|
||||||
|
*/
|
||||||
|
read.push(
|
||||||
|
new Endpoint("post", "/applications/search", controller.search).addMiddleware(
|
||||||
|
nameValidator()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
export default { read, write }
|
export default { read, write }
|
||||||
|
|
|
@ -5,43 +5,6 @@ import { nameValidator } from "../utils/validators"
|
||||||
const read = [],
|
const read = [],
|
||||||
write = []
|
write = []
|
||||||
|
|
||||||
/**
|
|
||||||
* @openapi
|
|
||||||
* /queries/search:
|
|
||||||
* post:
|
|
||||||
* summary: Search for a query based on its name.
|
|
||||||
* tags:
|
|
||||||
* - queries
|
|
||||||
* parameters:
|
|
||||||
* - $ref: '#/components/parameters/appId'
|
|
||||||
* requestBody:
|
|
||||||
* required: true
|
|
||||||
* content:
|
|
||||||
* application/json:
|
|
||||||
* schema:
|
|
||||||
* $ref: '#/components/schemas/nameSearch'
|
|
||||||
* responses:
|
|
||||||
* 200:
|
|
||||||
* description: Returns the queries found based on the search parameters.
|
|
||||||
* content:
|
|
||||||
* application/json:
|
|
||||||
* schema:
|
|
||||||
* type: object
|
|
||||||
* properties:
|
|
||||||
* queries:
|
|
||||||
* type: array
|
|
||||||
* items:
|
|
||||||
* $ref: '#/components/schemas/query'
|
|
||||||
* examples:
|
|
||||||
* queries:
|
|
||||||
* $ref: '#/components/examples/queries'
|
|
||||||
*/
|
|
||||||
read.push(
|
|
||||||
new Endpoint("post", "/queries/search", controller.search).addMiddleware(
|
|
||||||
nameValidator()
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @openapi
|
* @openapi
|
||||||
* /queries/{queryId}:
|
* /queries/{queryId}:
|
||||||
|
@ -89,4 +52,43 @@ read.push(
|
||||||
*/
|
*/
|
||||||
write.push(new Endpoint("post", "/queries/:queryId", controller.execute))
|
write.push(new Endpoint("post", "/queries/:queryId", controller.execute))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @openapi
|
||||||
|
* /queries/search:
|
||||||
|
* post:
|
||||||
|
* summary: Search for a query based on its name.
|
||||||
|
* tags:
|
||||||
|
* - queries
|
||||||
|
* parameters:
|
||||||
|
* - $ref: '#/components/parameters/appId'
|
||||||
|
* requestBody:
|
||||||
|
* required: true
|
||||||
|
* content:
|
||||||
|
* application/json:
|
||||||
|
* schema:
|
||||||
|
* $ref: '#/components/schemas/nameSearch'
|
||||||
|
* responses:
|
||||||
|
* 200:
|
||||||
|
* description: Returns the queries found based on the search parameters.
|
||||||
|
* content:
|
||||||
|
* application/json:
|
||||||
|
* schema:
|
||||||
|
* type: object
|
||||||
|
* required:
|
||||||
|
* - queries
|
||||||
|
* properties:
|
||||||
|
* queries:
|
||||||
|
* type: array
|
||||||
|
* items:
|
||||||
|
* $ref: '#/components/schemas/query'
|
||||||
|
* examples:
|
||||||
|
* queries:
|
||||||
|
* $ref: '#/components/examples/queries'
|
||||||
|
*/
|
||||||
|
read.push(
|
||||||
|
new Endpoint("post", "/queries/search", controller.search).addMiddleware(
|
||||||
|
nameValidator()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
export default { read, write }
|
export default { read, write }
|
||||||
|
|
|
@ -5,130 +5,6 @@ import { externalSearchValidator } from "../utils/validators"
|
||||||
const read = [],
|
const read = [],
|
||||||
write = []
|
write = []
|
||||||
|
|
||||||
/**
|
|
||||||
* @openapi
|
|
||||||
* /tables/{tableId}/rows/search:
|
|
||||||
* post:
|
|
||||||
* summary: Used to search for rows within a table.
|
|
||||||
* tags:
|
|
||||||
* - rows
|
|
||||||
* parameters:
|
|
||||||
* - $ref: '#/components/parameters/tableId'
|
|
||||||
* - $ref: '#/components/parameters/appId'
|
|
||||||
* 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].
|
|
||||||
* example:
|
|
||||||
* columnName1: [10, 20]
|
|
||||||
* 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.
|
|
||||||
* example:
|
|
||||||
* columnName1: ""
|
|
||||||
* 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
|
|
||||||
* 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
|
|
||||||
* examples:
|
|
||||||
* search:
|
|
||||||
* $ref: '#/components/examples/rows'
|
|
||||||
*/
|
|
||||||
read.push(
|
|
||||||
new Endpoint(
|
|
||||||
"post",
|
|
||||||
"/tables/:tableId/rows/search",
|
|
||||||
controller.search
|
|
||||||
).addMiddleware(externalSearchValidator())
|
|
||||||
)
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @openapi
|
* @openapi
|
||||||
* /tables/{tableId}/rows:
|
* /tables/{tableId}/rows:
|
||||||
|
@ -247,4 +123,132 @@ write.push(
|
||||||
*/
|
*/
|
||||||
read.push(new Endpoint("get", "/tables/:tableId/rows/:rowId", controller.read))
|
read.push(new Endpoint("get", "/tables/:tableId/rows/:rowId", controller.read))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @openapi
|
||||||
|
* /tables/{tableId}/rows/search:
|
||||||
|
* post:
|
||||||
|
* summary: Used to search for rows within a table.
|
||||||
|
* tags:
|
||||||
|
* - rows
|
||||||
|
* parameters:
|
||||||
|
* - $ref: '#/components/parameters/tableId'
|
||||||
|
* - $ref: '#/components/parameters/appId'
|
||||||
|
* requestBody:
|
||||||
|
* required: true
|
||||||
|
* content:
|
||||||
|
* application/json:
|
||||||
|
* schema:
|
||||||
|
* type: object
|
||||||
|
* required:
|
||||||
|
* - query
|
||||||
|
* 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].
|
||||||
|
* example:
|
||||||
|
* columnName1: [10, 20]
|
||||||
|
* 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.
|
||||||
|
* example:
|
||||||
|
* columnName1: ""
|
||||||
|
* 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
|
||||||
|
* required:
|
||||||
|
* - rows
|
||||||
|
* 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
|
||||||
|
* 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
|
||||||
|
* examples:
|
||||||
|
* search:
|
||||||
|
* $ref: '#/components/examples/rows'
|
||||||
|
*/
|
||||||
|
read.push(
|
||||||
|
new Endpoint(
|
||||||
|
"post",
|
||||||
|
"/tables/:tableId/rows/search",
|
||||||
|
controller.search
|
||||||
|
).addMiddleware(externalSearchValidator())
|
||||||
|
)
|
||||||
|
|
||||||
export default { read, write }
|
export default { read, write }
|
||||||
|
|
|
@ -5,43 +5,6 @@ import { tableValidator, nameValidator } from "../utils/validators"
|
||||||
const read = [],
|
const read = [],
|
||||||
write = []
|
write = []
|
||||||
|
|
||||||
/**
|
|
||||||
* @openapi
|
|
||||||
* /tables/search:
|
|
||||||
* post:
|
|
||||||
* summary: Search internal and external tables based on their name.
|
|
||||||
* tags:
|
|
||||||
* - tables
|
|
||||||
* parameters:
|
|
||||||
* - $ref: '#/components/parameters/appId'
|
|
||||||
* requestBody:
|
|
||||||
* required: true
|
|
||||||
* content:
|
|
||||||
* application/json:
|
|
||||||
* schema:
|
|
||||||
* $ref: '#/components/schemas/nameSearch'
|
|
||||||
* responses:
|
|
||||||
* 200:
|
|
||||||
* description: Returns the found tables, based on the search parameters.
|
|
||||||
* content:
|
|
||||||
* application/json:
|
|
||||||
* schema:
|
|
||||||
* type: object
|
|
||||||
* properties:
|
|
||||||
* applications:
|
|
||||||
* type: array
|
|
||||||
* items:
|
|
||||||
* $ref: '#/components/schemas/table'
|
|
||||||
* examples:
|
|
||||||
* tables:
|
|
||||||
* $ref: '#/components/examples/tables'
|
|
||||||
*/
|
|
||||||
read.push(
|
|
||||||
new Endpoint("post", "/tables/search", controller.search).addMiddleware(
|
|
||||||
nameValidator()
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @openapi
|
* @openapi
|
||||||
* /tables:
|
* /tables:
|
||||||
|
@ -158,4 +121,43 @@ write.push(new Endpoint("delete", "/tables/:tableId", controller.destroy))
|
||||||
*/
|
*/
|
||||||
read.push(new Endpoint("get", "/tables/:tableId", controller.read))
|
read.push(new Endpoint("get", "/tables/:tableId", controller.read))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @openapi
|
||||||
|
* /tables/search:
|
||||||
|
* post:
|
||||||
|
* summary: Search internal and external tables based on their name.
|
||||||
|
* tags:
|
||||||
|
* - tables
|
||||||
|
* parameters:
|
||||||
|
* - $ref: '#/components/parameters/appId'
|
||||||
|
* requestBody:
|
||||||
|
* required: true
|
||||||
|
* content:
|
||||||
|
* application/json:
|
||||||
|
* schema:
|
||||||
|
* $ref: '#/components/schemas/nameSearch'
|
||||||
|
* responses:
|
||||||
|
* 200:
|
||||||
|
* description: Returns the found tables, based on the search parameters.
|
||||||
|
* content:
|
||||||
|
* application/json:
|
||||||
|
* schema:
|
||||||
|
* type: object
|
||||||
|
* required:
|
||||||
|
* - tables
|
||||||
|
* properties:
|
||||||
|
* tables:
|
||||||
|
* type: array
|
||||||
|
* items:
|
||||||
|
* $ref: '#/components/schemas/table'
|
||||||
|
* examples:
|
||||||
|
* tables:
|
||||||
|
* $ref: '#/components/examples/tables'
|
||||||
|
*/
|
||||||
|
read.push(
|
||||||
|
new Endpoint("post", "/tables/search", controller.search).addMiddleware(
|
||||||
|
nameValidator()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
export default { read, write }
|
export default { read, write }
|
||||||
|
|
|
@ -0,0 +1,74 @@
|
||||||
|
const jestOpenAPI = require("jest-openapi").default
|
||||||
|
const generateSchema = require("../../../../../specs/generate")
|
||||||
|
const setup = require("../../tests/utilities")
|
||||||
|
const { checkSlashesInUrl } = require("../../../../utilities")
|
||||||
|
|
||||||
|
const yamlPath = generateSchema()
|
||||||
|
jestOpenAPI(yamlPath)
|
||||||
|
|
||||||
|
let request = setup.getRequest()
|
||||||
|
let config = setup.getConfig()
|
||||||
|
let apiKey, table
|
||||||
|
|
||||||
|
beforeAll(async () => {
|
||||||
|
await config.init()
|
||||||
|
table = await config.updateTable()
|
||||||
|
apiKey = await config.generateApiKey()
|
||||||
|
})
|
||||||
|
|
||||||
|
afterAll(setup.afterAll)
|
||||||
|
|
||||||
|
async function makeRequest(method, endpoint, body, appId) {
|
||||||
|
const extraHeaders = {
|
||||||
|
"x-budibase-api-key": apiKey,
|
||||||
|
"x-budibase-app-id": appId ? appId : config.getAppId(),
|
||||||
|
}
|
||||||
|
const req = request
|
||||||
|
[method](checkSlashesInUrl(`/api/public/v1/${endpoint}`))
|
||||||
|
.set(config.defaultHeaders(extraHeaders))
|
||||||
|
if (body) {
|
||||||
|
req.send(body)
|
||||||
|
}
|
||||||
|
const res = await req.expect("Content-Type", /json/).expect(200)
|
||||||
|
expect(res.body).toBeDefined()
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
describe("check the applications endpoints", () => {
|
||||||
|
it("should allow retrieving applications through search", async () => {
|
||||||
|
const res = await makeRequest("post", "/applications/search")
|
||||||
|
expect(res).toSatisfyApiSpec()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("check the tables endpoints", () => {
|
||||||
|
it("should allow retrieving applications through search", async () => {
|
||||||
|
const res = await makeRequest("post", "/tables/search")
|
||||||
|
expect(res).toSatisfyApiSpec()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("check the rows endpoints", () => {
|
||||||
|
it("should allow retrieving applications through search", async () => {
|
||||||
|
const res = await makeRequest("post", `/tables/${table._id}/rows/search`, {
|
||||||
|
query: {
|
||||||
|
},
|
||||||
|
})
|
||||||
|
expect(res).toSatisfyApiSpec()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("check the users endpoints", () => {
|
||||||
|
it("should allow retrieving applications through search", async () => {
|
||||||
|
const res = await makeRequest("post", "/users/search")
|
||||||
|
expect(res).toSatisfyApiSpec()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("check the queries endpoints", () => {
|
||||||
|
it("should allow retrieving applications through search", async () => {
|
||||||
|
const res = await makeRequest("post", "/queries/search")
|
||||||
|
expect(res).toSatisfyApiSpec()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
|
@ -5,40 +5,6 @@ import { nameValidator } from "../utils/validators"
|
||||||
const read = [],
|
const read = [],
|
||||||
write = []
|
write = []
|
||||||
|
|
||||||
/**
|
|
||||||
* @openapi
|
|
||||||
* /users/search:
|
|
||||||
* post:
|
|
||||||
* summary: Search for a user based on their email/username.
|
|
||||||
* tags:
|
|
||||||
* - users
|
|
||||||
* parameters:
|
|
||||||
* - $ref: '#/components/parameters/appId'
|
|
||||||
* requestBody:
|
|
||||||
* required: true
|
|
||||||
* content:
|
|
||||||
* application/json:
|
|
||||||
* schema:
|
|
||||||
* $ref: '#/components/schemas/nameSearch'
|
|
||||||
* responses:
|
|
||||||
* 200:
|
|
||||||
* description: Returns the found users based on search parameters.
|
|
||||||
* content:
|
|
||||||
* application/json:
|
|
||||||
* schema:
|
|
||||||
* type: array
|
|
||||||
* items:
|
|
||||||
* $ref: '#/components/schemas/user'
|
|
||||||
* examples:
|
|
||||||
* users:
|
|
||||||
* $ref: '#/components/examples/users'
|
|
||||||
*/
|
|
||||||
read.push(
|
|
||||||
new Endpoint("post", "/users/search", controller.search).addMiddleware(
|
|
||||||
nameValidator()
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @openapi
|
* @openapi
|
||||||
* /users:
|
* /users:
|
||||||
|
@ -142,4 +108,43 @@ write.push(new Endpoint("delete", "/users/:userId", controller.destroy))
|
||||||
*/
|
*/
|
||||||
read.push(new Endpoint("get", "/users/:userId", controller.read))
|
read.push(new Endpoint("get", "/users/:userId", controller.read))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @openapi
|
||||||
|
* /users/search:
|
||||||
|
* post:
|
||||||
|
* summary: Search for a user based on their email/username.
|
||||||
|
* tags:
|
||||||
|
* - users
|
||||||
|
* parameters:
|
||||||
|
* - $ref: '#/components/parameters/appId'
|
||||||
|
* requestBody:
|
||||||
|
* required: true
|
||||||
|
* content:
|
||||||
|
* application/json:
|
||||||
|
* schema:
|
||||||
|
* $ref: '#/components/schemas/nameSearch'
|
||||||
|
* responses:
|
||||||
|
* 200:
|
||||||
|
* description: Returns the found users based on search parameters.
|
||||||
|
* content:
|
||||||
|
* application/json:
|
||||||
|
* schema:
|
||||||
|
* type: object
|
||||||
|
* required:
|
||||||
|
* - users
|
||||||
|
* properties:
|
||||||
|
* users:
|
||||||
|
* type: array
|
||||||
|
* items:
|
||||||
|
* $ref: '#/components/schemas/user'
|
||||||
|
* examples:
|
||||||
|
* users:
|
||||||
|
* $ref: '#/components/examples/users'
|
||||||
|
*/
|
||||||
|
read.push(
|
||||||
|
new Endpoint("post", "/users/search", controller.search).addMiddleware(
|
||||||
|
nameValidator()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
export default { read, write }
|
export default { read, write }
|
||||||
|
|
|
@ -25,6 +25,8 @@ const { createASession } = require("@budibase/backend-core/sessions")
|
||||||
const { user: userCache } = require("@budibase/backend-core/cache")
|
const { user: userCache } = require("@budibase/backend-core/cache")
|
||||||
const newid = require("../../db/newid")
|
const newid = require("../../db/newid")
|
||||||
const context = require("@budibase/backend-core/context")
|
const context = require("@budibase/backend-core/context")
|
||||||
|
const { generateDevInfoID, SEPARATOR } = require("@budibase/backend-core/db")
|
||||||
|
const { encrypt } = require("@budibase/backend-core/encryption")
|
||||||
|
|
||||||
const GLOBAL_USER_ID = "us_uuid1"
|
const GLOBAL_USER_ID = "us_uuid1"
|
||||||
const EMAIL = "babs@babs.com"
|
const EMAIL = "babs@babs.com"
|
||||||
|
@ -83,6 +85,20 @@ class TestConfiguration {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async generateApiKey(userId = GLOBAL_USER_ID) {
|
||||||
|
const db = getGlobalDB(TENANT_ID)
|
||||||
|
const id = generateDevInfoID(userId)
|
||||||
|
let devInfo
|
||||||
|
try {
|
||||||
|
devInfo = await db.get(id)
|
||||||
|
} catch (err) {
|
||||||
|
devInfo = { _id: id, userId }
|
||||||
|
}
|
||||||
|
devInfo.apiKey = encrypt(`${TENANT_ID}${SEPARATOR}${newid()}`)
|
||||||
|
await db.put(devInfo)
|
||||||
|
return devInfo.apiKey
|
||||||
|
}
|
||||||
|
|
||||||
async globalUser({
|
async globalUser({
|
||||||
id = GLOBAL_USER_ID,
|
id = GLOBAL_USER_ID,
|
||||||
builder = true,
|
builder = true,
|
||||||
|
@ -135,7 +151,7 @@ class TestConfiguration {
|
||||||
cleanup(this.allApps.map(app => app.appId))
|
cleanup(this.allApps.map(app => app.appId))
|
||||||
}
|
}
|
||||||
|
|
||||||
defaultHeaders() {
|
defaultHeaders(extras = {}) {
|
||||||
const auth = {
|
const auth = {
|
||||||
userId: GLOBAL_USER_ID,
|
userId: GLOBAL_USER_ID,
|
||||||
sessionId: "sessionid",
|
sessionId: "sessionid",
|
||||||
|
@ -154,6 +170,7 @@ class TestConfiguration {
|
||||||
`${Cookies.CurrentApp}=${appToken}`,
|
`${Cookies.CurrentApp}=${appToken}`,
|
||||||
],
|
],
|
||||||
[Headers.CSRF_TOKEN]: CSRF_TOKEN,
|
[Headers.CSRF_TOKEN]: CSRF_TOKEN,
|
||||||
|
...extras,
|
||||||
}
|
}
|
||||||
if (this.appId) {
|
if (this.appId) {
|
||||||
headers[Headers.APP_ID] = this.appId
|
headers[Headers.APP_ID] = this.appId
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue