Adding a testing system which generates the schema and compares against responses.

This commit is contained in:
Michael Drury 2022-02-24 23:21:10 +00:00
parent f2c2c903e5
commit 46d23cfb25
17 changed files with 2698 additions and 2630 deletions

View File

@ -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

View File

@ -53,6 +53,7 @@ module FetchMock {
{ {
doc: { doc: {
_id: "test", _id: "test",
tableId: opts.body.split("tableId:")[1].split('"')[0],
}, },
}, },
], ],

View File

@ -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",

View File

@ -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

View File

@ -474,7 +474,10 @@
"url" "url"
] ]
} }
} },
"required": [
"application"
]
}, },
"row": { "row": {
"description": "The row to be created/updated, based on the table schema.", "description": "The row to be created/updated, based on the table schema.",
@ -525,11 +528,18 @@
] ]
} }
} }
} },
"required": [
"row"
]
}, },
"table": { "table": {
"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",
@ -540,6 +550,8 @@
"description": "The name of the column which should be used in relationship tags when relating to this table." "description": "The name of the column which should be used in relationship tags when relating to this table."
}, },
"schema": { "schema": {
"type": "object",
"additionalProperties": {
"oneOf": [ "oneOf": [
{ {
"type": "object", "type": "object",
@ -718,6 +730,7 @@
] ]
} }
} }
}
}, },
"tableOutput": { "tableOutput": {
"type": "object", "type": "object",
@ -725,6 +738,10 @@
"table": { "table": {
"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",
@ -735,6 +752,8 @@
"description": "The name of the column which should be used in relationship tags when relating to this table." "description": "The name of the column which should be used in relationship tags when relating to this table."
}, },
"schema": { "schema": {
"type": "object",
"additionalProperties": {
"oneOf": [ "oneOf": [
{ {
"type": "object", "type": "object",
@ -916,23 +935,33 @@
} }
} }
}, },
"required": [
"table"
]
},
"query": { "query": {
"type": "object", "type": "object",
"properties": {} "properties": {},
"required": []
}, },
"user": { "user": {
"type": "object", "type": "object",
"properties": {} "properties": {},
"required": []
}, },
"userOutput": { "userOutput": {
"type": "object", "type": "object",
"properties": { "properties": {
"user": { "user": {
"type": "object", "type": "object",
"properties": {} "properties": {},
} "required": []
} }
}, },
"required": [
"user"
]
},
"nameSearch": { "nameSearch": {
"type": "object", "type": "object",
"properties": { "properties": {
@ -940,7 +969,10 @@
"type": "string", "type": "string",
"description": "The name to be used when searching - this will be used in a case insensitive starts with match." "description": "The name to be used when searching - this will be used in a case insensitive starts with match."
} }
} },
"required": [
"name"
]
} }
} }
}, },
@ -950,54 +982,6 @@
} }
], ],
"paths": { "paths": {
"/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"
}
}
}
}
}
}
}
},
"/applications": { "/applications": {
"post": { "post": {
"summary": "Create a new application.", "summary": "Create a new application.",
@ -1134,11 +1118,11 @@
} }
} }
}, },
"/queries/search": { "/applications/search": {
"post": { "post": {
"summary": "Search for a query based on its name.", "summary": "Search for an application based on its app name.",
"tags": [ "tags": [
"queries" "applications"
], ],
"parameters": [ "parameters": [
{ {
@ -1157,23 +1141,26 @@
}, },
"responses": { "responses": {
"200": { "200": {
"description": "Returns the queries found based on the search parameters.", "description": "Returns the applications that were found based on the search parameters.",
"content": { "content": {
"application/json": { "application/json": {
"schema": { "schema": {
"type": "object", "type": "object",
"required": [
"applications"
],
"properties": { "properties": {
"queries": { "applications": {
"type": "array", "type": "array",
"items": { "items": {
"$ref": "#/components/schemas/query" "$ref": "#/components/schemas/application"
} }
} }
} }
}, },
"examples": { "examples": {
"queries": { "applications": {
"$ref": "#/components/examples/queries" "$ref": "#/components/examples/applications"
} }
} }
} }
@ -1246,16 +1233,13 @@
} }
} }
}, },
"/tables/{tableId}/rows/search": { "/queries/search": {
"post": { "post": {
"summary": "Used to search for rows within a table.", "summary": "Search for a query based on its name.",
"tags": [ "tags": [
"rows" "queries"
], ],
"parameters": [ "parameters": [
{
"$ref": "#/components/parameters/tableId"
},
{ {
"$ref": "#/components/parameters/appId" "$ref": "#/components/parameters/appId"
} }
@ -1265,147 +1249,33 @@
"content": { "content": {
"application/json": { "application/json": {
"schema": { "schema": {
"type": "object", "$ref": "#/components/schemas/nameSearch"
"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": { "responses": {
"200": { "200": {
"description": "The response will contain an array of rows that match the search parameters.", "description": "Returns the queries found based on the search parameters.",
"content": { "content": {
"application/json": { "application/json": {
"schema": { "schema": {
"type": "object", "type": "object",
"required": [
"queries"
],
"properties": { "properties": {
"rows": { "queries": {
"description": "An array of rows, these will each contain an _id field which can be used to update or delete them.",
"type": "array", "type": "array",
"items": { "items": {
"type": "object" "$ref": "#/components/schemas/query"
} }
},
"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": { "examples": {
"search": { "queries": {
"$ref": "#/components/examples/rows" "$ref": "#/components/examples/queries"
} }
} }
} }
@ -1581,13 +1451,16 @@
} }
} }
}, },
"/tables/search": { "/tables/{tableId}/rows/search": {
"post": { "post": {
"summary": "Search internal and external tables based on their name.", "summary": "Used to search for rows within a table.",
"tags": [ "tags": [
"tables" "rows"
], ],
"parameters": [ "parameters": [
{
"$ref": "#/components/parameters/tableId"
},
{ {
"$ref": "#/components/parameters/appId" "$ref": "#/components/parameters/appId"
} }
@ -1597,30 +1470,153 @@
"content": { "content": {
"application/json": { "application/json": {
"schema": { "schema": {
"$ref": "#/components/schemas/nameSearch" "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": { "responses": {
"200": { "200": {
"description": "Returns the found tables, based on the search parameters.", "description": "The response will contain an array of rows that match the search parameters.",
"content": { "content": {
"application/json": { "application/json": {
"schema": { "schema": {
"type": "object", "type": "object",
"required": [
"rows"
],
"properties": { "properties": {
"applications": { "rows": {
"description": "An array of rows, these will each contain an _id field which can be used to update or delete them.",
"type": "array", "type": "array",
"items": { "items": {
"$ref": "#/components/schemas/table" "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": { "examples": {
"tables": { "search": {
"$ref": "#/components/examples/tables" "$ref": "#/components/examples/rows"
} }
} }
} }
@ -1782,11 +1778,11 @@
} }
} }
}, },
"/users/search": { "/tables/search": {
"post": { "post": {
"summary": "Search for a user based on their email/username.", "summary": "Search internal and external tables based on their name.",
"tags": [ "tags": [
"users" "tables"
], ],
"parameters": [ "parameters": [
{ {
@ -1805,18 +1801,26 @@
}, },
"responses": { "responses": {
"200": { "200": {
"description": "Returns the found users based on search parameters.", "description": "Returns the found tables, based on the search parameters.",
"content": { "content": {
"application/json": { "application/json": {
"schema": { "schema": {
"type": "object",
"required": [
"tables"
],
"properties": {
"tables": {
"type": "array", "type": "array",
"items": { "items": {
"$ref": "#/components/schemas/user" "$ref": "#/components/schemas/table"
}
}
} }
}, },
"examples": { "examples": {
"users": { "tables": {
"$ref": "#/components/examples/users" "$ref": "#/components/examples/tables"
} }
} }
} }
@ -1969,6 +1973,57 @@
} }
} }
} }
},
"/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"
}
}
}
}
}
}
}
} }
}, },
"tags": [] "tags": []

View File

@ -339,6 +339,8 @@ components:
required: required:
- name - name
- url - url
required:
- application
row: row:
description: The row to be created/updated, based on the table schema. description: The row to be created/updated, based on the table schema.
type: object type: object
@ -362,9 +364,14 @@ components:
- type: integer - type: integer
- type: array - type: array
- type: boolean - type: boolean
required:
- row
table: table:
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
@ -374,160 +381,8 @@ components:
description: The name of the column which should be used in relationship tags description: The name of the column which should be used in relationship tags
when relating to this table. when relating to this table.
schema: schema:
oneOf:
- type: object
properties:
type:
type: string
enum:
- link
description: A relationship column.
constraints:
type: object type: object
description: A constraint can be applied to the column which will be validated additionalProperties:
against when a row is saved.
properties:
type:
type: string
enum:
- string
- number
- object
- boolean
presence:
type: boolean
description: Defines whether the column is required or not.
name:
type: string
description: The name of the column.
autocolumn:
type: boolean
description: Defines whether the column is automatically generated.
fieldName:
type: string
description: The name of the column which a relationship column is related to in
another table.
tableId:
type: string
description: The ID of the table which a relationship column is related to.
relationshipType:
type: string
enum:
- one-to-many
- many-to-one
- many-to-many
description: Defines the type of relationship that this column will be used for.
through:
type: string
description: When using a SQL table that contains many to many relationships
this defines the table the relationships are linked through.
foreignKey:
type: string
description: When using a SQL table that contains a one to many relationship
this defines the foreign key.
throughFrom:
type: string
description: When using a SQL table that utilises a through table, this defines
the primary key in the through table for this table.
throughTo:
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
properties:
type:
type: string
enum:
- formula
description: A formula column.
constraints:
type: object
description: A constraint can be applied to the column which will be validated
against when a row is saved.
properties:
type:
type: string
enum:
- string
- number
- object
- boolean
presence:
type: boolean
description: Defines whether the column is required or not.
name:
type: string
description: The name of the column.
autocolumn:
type: boolean
description: Defines whether the column is automatically generated.
formula:
type: string
description: Defines a Handlebars or JavaScript formula to use, note that
Javascript formulas are expected to be provided in the
base64 format.
formulaType:
type: string
enum:
- static
- dynamic
description: Defines whether this is a static or dynamic formula.
- type: object
properties:
type:
type: string
enum:
- string
- longform
- options
- number
- boolean
- array
- datetime
- attachment
- link
- formula
- auto
- json
- internal
description: Defines the type of the column, most explain themselves, a link
column is a relationship.
constraints:
type: object
description: A constraint can be applied to the column which will be validated
against when a row is saved.
properties:
type:
type: string
enum:
- string
- number
- object
- boolean
presence:
type: boolean
description: Defines whether the column is required or not.
name:
type: string
description: The name of the column.
autocolumn:
type: boolean
description: Defines whether the column is automatically generated.
tableOutput:
type: object
properties:
table:
description: The table to be created/updated.
type: object
properties:
name:
description: The name of the table
type: string
primaryDisplay:
type: string
description: The name of the column which should be used in relationship tags
when relating to this table.
schema:
oneOf: oneOf:
- type: object - type: object
properties: properties:
@ -669,18 +524,186 @@ components:
autocolumn: autocolumn:
type: boolean type: boolean
description: Defines whether the column is automatically generated. description: Defines whether the column is automatically generated.
tableOutput:
type: object
properties:
table:
description: The table to be created/updated.
type: object
required:
- name
- schema
properties:
name:
description: The name of the table
type: string
primaryDisplay:
type: string
description: The name of the column which should be used in relationship tags
when relating to this table.
schema:
type: object
additionalProperties:
oneOf:
- type: object
properties:
type:
type: string
enum:
- link
description: A relationship column.
constraints:
type: object
description: A constraint can be applied to the column which will be validated
against when a row is saved.
properties:
type:
type: string
enum:
- string
- number
- object
- boolean
presence:
type: boolean
description: Defines whether the column is required or not.
name:
type: string
description: The name of the column.
autocolumn:
type: boolean
description: Defines whether the column is automatically generated.
fieldName:
type: string
description: The name of the column which a relationship column is related to in
another table.
tableId:
type: string
description: The ID of the table which a relationship column is related to.
relationshipType:
type: string
enum:
- one-to-many
- many-to-one
- many-to-many
description: Defines the type of relationship that this column will be used for.
through:
type: string
description: When using a SQL table that contains many to many relationships
this defines the table the relationships are linked
through.
foreignKey:
type: string
description: When using a SQL table that contains a one to many relationship
this defines the foreign key.
throughFrom:
type: string
description: When using a SQL table that utilises a through table, this defines
the primary key in the through table for this table.
throughTo:
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
properties:
type:
type: string
enum:
- formula
description: A formula column.
constraints:
type: object
description: A constraint can be applied to the column which will be validated
against when a row is saved.
properties:
type:
type: string
enum:
- string
- number
- object
- boolean
presence:
type: boolean
description: Defines whether the column is required or not.
name:
type: string
description: The name of the column.
autocolumn:
type: boolean
description: Defines whether the column is automatically generated.
formula:
type: string
description: Defines a Handlebars or JavaScript formula to use, note that
Javascript formulas are expected to be provided in the
base64 format.
formulaType:
type: string
enum:
- static
- dynamic
description: Defines whether this is a static or dynamic formula.
- type: object
properties:
type:
type: string
enum:
- string
- longform
- options
- number
- boolean
- array
- datetime
- attachment
- link
- formula
- auto
- json
- internal
description: Defines the type of the column, most explain themselves, a link
column is a relationship.
constraints:
type: object
description: A constraint can be applied to the column which will be validated
against when a row is saved.
properties:
type:
type: string
enum:
- string
- number
- object
- boolean
presence:
type: boolean
description: Defines whether the column is required or not.
name:
type: string
description: The name of the column.
autocolumn:
type: boolean
description: Defines whether the column is automatically generated.
required:
- table
query: query:
type: object type: object
properties: {} properties: {}
required: []
user: user:
type: object type: object
properties: {} properties: {}
required: []
userOutput: userOutput:
type: object type: object
properties: properties:
user: user:
type: object type: object
properties: {} properties: {}
required: []
required:
- user
nameSearch: nameSearch:
type: object type: object
properties: properties:
@ -688,38 +711,11 @@ components:
type: string type: string
description: The name to be used when searching - this will be used in a case description: The name to be used when searching - this will be used in a case
insensitive starts with match. insensitive starts with match.
required:
- name
security: security:
- ApiKeyAuth: [] - ApiKeyAuth: []
paths: paths:
/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"
/applications: /applications:
post: post:
summary: Create a new application. summary: Create a new application.
@ -798,11 +794,11 @@ paths:
examples: examples:
application: application:
$ref: "#/components/examples/application" $ref: "#/components/examples/application"
/queries/search: /applications/search:
post: post:
summary: Search for a query based on its name. summary: Search for an application based on its app name.
tags: tags:
- queries - applications
parameters: parameters:
- $ref: "#/components/parameters/appId" - $ref: "#/components/parameters/appId"
requestBody: requestBody:
@ -813,19 +809,22 @@ paths:
$ref: "#/components/schemas/nameSearch" $ref: "#/components/schemas/nameSearch"
responses: responses:
"200": "200":
description: Returns the queries found based on the search parameters. description: Returns the applications that were found based on the search
parameters.
content: content:
application/json: application/json:
schema: schema:
type: object type: object
required:
- applications
properties: properties:
queries: applications:
type: array type: array
items: items:
$ref: "#/components/schemas/query" $ref: "#/components/schemas/application"
examples: examples:
queries: applications:
$ref: "#/components/examples/queries" $ref: "#/components/examples/applications"
"/queries/{queryId}": "/queries/{queryId}":
post: post:
summary: Execute a query and retrieve its response. summary: Execute a query and retrieve its response.
@ -867,129 +866,36 @@ paths:
$ref: "#/components/examples/restResponse" $ref: "#/components/examples/restResponse"
SQL: SQL:
$ref: "#/components/examples/sqlResponse" $ref: "#/components/examples/sqlResponse"
"/tables/{tableId}/rows/search": /queries/search:
post: post:
summary: Used to search for rows within a table. summary: Search for a query based on its name.
tags: tags:
- rows - queries
parameters: parameters:
- $ref: "#/components/parameters/tableId"
- $ref: "#/components/parameters/appId" - $ref: "#/components/parameters/appId"
requestBody: requestBody:
required: true required: true
content: content:
application/json: application/json:
schema: schema:
type: object $ref: "#/components/schemas/nameSearch"
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: responses:
"200": "200":
description: The response will contain an array of rows that match the search description: Returns the queries found based on the search parameters.
parameters.
content: content:
application/json: application/json:
schema: schema:
type: object type: object
required:
- queries
properties: properties:
rows: queries:
description: An array of rows, these will each contain an _id field which can be
used to update or delete them.
type: array type: array
items: items:
type: object $ref: "#/components/schemas/query"
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: examples:
search: queries:
$ref: "#/components/examples/rows" $ref: "#/components/examples/queries"
"/tables/{tableId}/rows": "/tables/{tableId}/rows":
post: post:
summary: Creates a new row within a specified table. summary: Creates a new row within a specified table.
@ -1085,34 +991,133 @@ paths:
examples: examples:
row: row:
$ref: "#/components/examples/row" $ref: "#/components/examples/row"
/tables/search: "/tables/{tableId}/rows/search":
post: post:
summary: Search internal and external tables based on their name. summary: Used to search for rows within a table.
tags: tags:
- tables - rows
parameters: parameters:
- $ref: "#/components/parameters/tableId"
- $ref: "#/components/parameters/appId" - $ref: "#/components/parameters/appId"
requestBody: requestBody:
required: true required: true
content: content:
application/json: application/json:
schema: schema:
$ref: "#/components/schemas/nameSearch" 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: responses:
"200": "200":
description: Returns the found tables, based on the search parameters. description: The response will contain an array of rows that match the search
parameters.
content: content:
application/json: application/json:
schema: schema:
type: object type: object
required:
- rows
properties: properties:
applications: rows:
description: An array of rows, these will each contain an _id field which can be
used to update or delete them.
type: array type: array
items: items:
$ref: "#/components/schemas/table" 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: examples:
tables: search:
$ref: "#/components/examples/tables" $ref: "#/components/examples/rows"
/tables: /tables:
post: post:
summary: Create a new table. summary: Create a new table.
@ -1199,11 +1204,11 @@ paths:
examples: examples:
table: table:
$ref: "#/components/examples/table" $ref: "#/components/examples/table"
/users/search: /tables/search:
post: post:
summary: Search for a user based on their email/username. summary: Search internal and external tables based on their name.
tags: tags:
- users - tables
parameters: parameters:
- $ref: "#/components/parameters/appId" - $ref: "#/components/parameters/appId"
requestBody: requestBody:
@ -1214,16 +1219,21 @@ paths:
$ref: "#/components/schemas/nameSearch" $ref: "#/components/schemas/nameSearch"
responses: responses:
"200": "200":
description: Returns the found users based on search parameters. description: Returns the found tables, based on the search parameters.
content: content:
application/json: application/json:
schema: schema:
type: object
required:
- tables
properties:
tables:
type: array type: array
items: items:
$ref: "#/components/schemas/user" $ref: "#/components/schemas/table"
examples: examples:
users: tables:
$ref: "#/components/examples/users" $ref: "#/components/examples/tables"
/users: /users:
post: post:
summary: Create a new user in the Budibase portal. summary: Create a new user in the Budibase portal.
@ -1305,4 +1315,34 @@ paths:
examples: examples:
user: user:
$ref: "#/components/examples/user" $ref: "#/components/examples/user"
/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"
tags: [] tags: []

View File

@ -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,6 +75,8 @@ 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: {
type: "object",
additionalProperties: {
oneOf: [ oneOf: [
// relationship // relationship
{ {
@ -152,6 +155,7 @@ const tableSchema = {
], ],
}, },
}, },
},
} }
module.exports = new Resource() module.exports = new Resource()

View File

@ -2,6 +2,7 @@ exports.object = (props, opts) => {
return { return {
type: "object", type: "object",
properties: props, properties: props,
required: Object.keys(props),
...opts, ...opts,
} }
} }

View File

@ -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 }

View File

@ -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 }

View File

@ -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 }

View File

@ -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 }

View File

@ -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()
})
})

View File

@ -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 }

View File

@ -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