mirror of https://github.com/nocodb/nocodb
Raju Udava
1 year ago
committed by
GitHub
13 changed files with 1140 additions and 14 deletions
@ -0,0 +1,28 @@
|
||||
import { getModelPaths } from './templates/paths'; |
||||
import type { Model } from '~/models'; |
||||
import type { SwaggerColumn } from './getSwaggerColumnMetas'; |
||||
import type { SwaggerView } from './getSwaggerJSONV2'; |
||||
import Noco from '~/Noco'; |
||||
|
||||
export default async function getPaths( |
||||
{ |
||||
model, |
||||
columns, |
||||
views, |
||||
}: { |
||||
model: Model; |
||||
columns: SwaggerColumn[]; |
||||
views: SwaggerView[]; |
||||
}, |
||||
_ncMeta = Noco.ncMeta, |
||||
) { |
||||
const swaggerPaths = await getModelPaths({ |
||||
tableName: model.title, |
||||
tableId: model.id, |
||||
views, |
||||
type: model.type, |
||||
columns, |
||||
}); |
||||
|
||||
return swaggerPaths; |
||||
} |
@ -0,0 +1,29 @@
|
||||
import { getModelSchemas, getViewSchemas } from './templates/schemas'; |
||||
import type { Base, Model } from '~/models'; |
||||
|
||||
import type { SwaggerColumn } from './getSwaggerColumnMetas'; |
||||
import type { SwaggerView } from './getSwaggerJSONV2'; |
||||
import Noco from '~/Noco'; |
||||
|
||||
export default async function getSchemas( |
||||
{ |
||||
base, |
||||
model, |
||||
columns |
||||
}: { |
||||
base: Base; |
||||
model: Model; |
||||
columns: SwaggerColumn[]; |
||||
views: SwaggerView[]; |
||||
}, |
||||
_ncMeta = Noco.ncMeta, |
||||
) { |
||||
const swaggerSchemas = getModelSchemas({ |
||||
tableName: model.title, |
||||
orgs: 'v1', |
||||
baseName: base.title, |
||||
columns, |
||||
}); |
||||
|
||||
return swaggerSchemas; |
||||
} |
@ -0,0 +1,67 @@
|
||||
import { UITypes } from 'nocodb-sdk'; |
||||
import type { Base, Column, LinkToAnotherRecordColumn } from '~/models'; |
||||
import SwaggerTypes from '~/db/sql-mgr/code/routers/xc-ts/SwaggerTypes'; |
||||
import Noco from '~/Noco'; |
||||
|
||||
export default async ( |
||||
columns: Column[], |
||||
base: Base, |
||||
ncMeta = Noco.ncMeta, |
||||
): Promise<SwaggerColumn[]> => { |
||||
const dbType = await base.getBases().then((b) => b?.[0]?.type); |
||||
return Promise.all( |
||||
columns.map(async (c) => { |
||||
const field: SwaggerColumn = { |
||||
title: c.title, |
||||
type: 'object', |
||||
virtual: true, |
||||
column: c, |
||||
}; |
||||
|
||||
switch (c.uidt) { |
||||
case UITypes.LinkToAnotherRecord: |
||||
{ |
||||
const colOpt = await c.getColOptions<LinkToAnotherRecordColumn>( |
||||
ncMeta, |
||||
); |
||||
if (colOpt) { |
||||
const relTable = await colOpt.getRelatedTable(ncMeta); |
||||
field.type = undefined; |
||||
field.$ref = `#/components/schemas/${relTable.title}Request`; |
||||
} |
||||
} |
||||
break; |
||||
case UITypes.Formula: |
||||
case UITypes.Lookup: |
||||
field.type = 'object'; |
||||
break; |
||||
case UITypes.Rollup: |
||||
case UITypes.Links: |
||||
field.type = 'number'; |
||||
break; |
||||
case UITypes.Attachment: |
||||
field.type = 'array'; |
||||
field.items = { |
||||
$ref: `#/components/schemas/Attachment`, |
||||
}; |
||||
break; |
||||
default: |
||||
field.virtual = false; |
||||
SwaggerTypes.setSwaggerType(c, field, dbType); |
||||
break; |
||||
} |
||||
|
||||
return field; |
||||
}), |
||||
); |
||||
}; |
||||
|
||||
export interface SwaggerColumn { |
||||
type: any; |
||||
title: string; |
||||
description?: string; |
||||
virtual?: boolean; |
||||
$ref?: any; |
||||
column: Column; |
||||
items?: any; |
||||
} |
@ -0,0 +1,66 @@
|
||||
import { ViewTypes } from 'nocodb-sdk'; |
||||
import swaggerBase from './swagger-base.json'; |
||||
import getPaths from './getPaths'; |
||||
import getSchemas from './getSchemas'; |
||||
import getSwaggerColumnMetas from './getSwaggerColumnMetas'; |
||||
import type { |
||||
Base, |
||||
FormViewColumn, |
||||
GalleryViewColumn, |
||||
GridViewColumn, |
||||
Model, |
||||
View, |
||||
} from '~/models'; |
||||
import Noco from '~/Noco'; |
||||
|
||||
export default async function getSwaggerJSONV2( |
||||
base: Base, |
||||
models: Model[], |
||||
ncMeta = Noco.ncMeta, |
||||
) { |
||||
// base swagger object
|
||||
const swaggerObj = { |
||||
...swaggerBase, |
||||
paths: {}, |
||||
components: { |
||||
...swaggerBase.components, |
||||
schemas: { ...swaggerBase.components.schemas }, |
||||
}, |
||||
}; |
||||
|
||||
// iterate and populate swagger schema and path for models and views
|
||||
for (const model of models) { |
||||
let paths = {}; |
||||
|
||||
const columns = await getSwaggerColumnMetas( |
||||
await model.getColumns(ncMeta), |
||||
base, |
||||
ncMeta, |
||||
); |
||||
|
||||
const views: SwaggerView[] = []; |
||||
|
||||
for (const view of (await model.getViews(false, ncMeta)) || []) { |
||||
if (view.type !== ViewTypes.GRID) continue; |
||||
views.push({ |
||||
view, |
||||
columns: await view.getColumns(ncMeta), |
||||
}); |
||||
} |
||||
|
||||
// skip mm tables
|
||||
if (!model.mm) paths = await getPaths({ model, columns, views }, ncMeta); |
||||
|
||||
const schemas = await getSchemas({ base, model, columns, views }, ncMeta); |
||||
|
||||
Object.assign(swaggerObj.paths, paths); |
||||
Object.assign(swaggerObj.components.schemas, schemas); |
||||
} |
||||
|
||||
return swaggerObj; |
||||
} |
||||
|
||||
export interface SwaggerView { |
||||
view: View; |
||||
columns: Array<GridViewColumn | GalleryViewColumn | FormViewColumn>; |
||||
} |
@ -0,0 +1,128 @@
|
||||
{ |
||||
"openapi": "3.0.0", |
||||
"info": { |
||||
"title": "nocodb", |
||||
"version": "2.0" |
||||
}, |
||||
"servers": [ |
||||
{ |
||||
"url": "http://localhost:8080" |
||||
} |
||||
], |
||||
"paths": { |
||||
}, |
||||
"components": { |
||||
"schemas": { |
||||
"Paginated": { |
||||
"title": "Paginated", |
||||
"type": "object", |
||||
"properties": { |
||||
"pageSize": { |
||||
"type": "integer" |
||||
}, |
||||
"totalRows": { |
||||
"type": "integer" |
||||
}, |
||||
"isFirstPage": { |
||||
"type": "boolean" |
||||
}, |
||||
"isLastPage": { |
||||
"type": "boolean" |
||||
}, |
||||
"page": { |
||||
"type": "number" |
||||
} |
||||
} |
||||
}, |
||||
"Attachment": { |
||||
"title": "Attachment", |
||||
"type": "object", |
||||
"properties": { |
||||
"mimetype": { |
||||
"type": "string" |
||||
}, |
||||
"size": { |
||||
"type": "integer" |
||||
}, |
||||
"title": { |
||||
"type": "string" |
||||
}, |
||||
"url": { |
||||
"type": "string" |
||||
}, |
||||
"icon": { |
||||
"type": "string" |
||||
} |
||||
} |
||||
}, |
||||
"Groupby": { |
||||
"title": "Groupby", |
||||
"type": "object", |
||||
"properties": { |
||||
"count": { |
||||
"type": "number", |
||||
"description": "count" |
||||
}, |
||||
"column_name": { |
||||
"type": "string", |
||||
"description": "the value of the given column" |
||||
} |
||||
} |
||||
} |
||||
}, |
||||
"securitySchemes": { |
||||
"xcAuth": { |
||||
"type": "apiKey", |
||||
"in": "header", |
||||
"name": "xc-auth", |
||||
"description": "JWT access token" |
||||
}, |
||||
"xcToken": { |
||||
"type": "apiKey", |
||||
"in": "header", |
||||
"name": "xc-token", |
||||
"description": "API token" |
||||
} |
||||
}, |
||||
"responses": { |
||||
"BadRequest": { |
||||
"description": "BadReqeust", |
||||
"content": { |
||||
"application/json": { |
||||
"schema": { |
||||
"type": "object", |
||||
"properties": { |
||||
"msg": { |
||||
"type": "string", |
||||
"x-stoplight": { |
||||
"id": "p9mk4oi0hbihm" |
||||
}, |
||||
"example": "BadRequest [Error]: <ERROR MESSAGE>" |
||||
} |
||||
}, |
||||
"required": [ |
||||
"msg" |
||||
] |
||||
}, |
||||
"examples": { |
||||
"Example 1": { |
||||
"value": { |
||||
"msg": "BadRequest [Error]: <ERROR MESSAGE>" |
||||
} |
||||
} |
||||
} |
||||
} |
||||
}, |
||||
"headers": {} |
||||
} |
||||
} |
||||
}, |
||||
"security": [ |
||||
{ |
||||
"xcAuth": [] |
||||
}, |
||||
{ |
||||
"xcToken": [] |
||||
} |
||||
] |
||||
} |
@ -0,0 +1,10 @@
|
||||
export const csvExportResponseHeader = { |
||||
'nc-export-offset': { |
||||
schema: { |
||||
type: 'integer', |
||||
}, |
||||
description: |
||||
'Offset of next set of data which will be helpful if there is large amount of data. It will returns `-1` if all set of data exported.', |
||||
example: '1000', |
||||
}, |
||||
}; |
@ -0,0 +1,237 @@
|
||||
import { isLinksOrLTAR, RelationTypes, UITypes } from 'nocodb-sdk'; |
||||
import type { LinkToAnotherRecordColumn } from '~/models'; |
||||
import type { SwaggerColumn } from '../getSwaggerColumnMetas'; |
||||
import type { SwaggerView } from '~/services/api-docs/swaggerV2/getSwaggerJSONV2'; |
||||
|
||||
export const recordIdParam = { |
||||
schema: { |
||||
type: 'string', |
||||
}, |
||||
name: 'recordId', |
||||
in: 'path', |
||||
required: true, |
||||
example: 1, |
||||
description: |
||||
'Primary key of the record you want to read. If the table have composite primary key then combine them by using `___` and pass it as primary key.', |
||||
}; |
||||
export const fieldsParam = { |
||||
schema: { |
||||
type: 'string', |
||||
}, |
||||
in: 'query', |
||||
name: 'fields', |
||||
description: |
||||
'Array of field names or comma separated filed names to include in the response objects. In array syntax pass it like `fields[]=field1&fields[]=field2` or alternately `fields=field1,field2`.', |
||||
}; |
||||
export const sortParam = { |
||||
schema: { |
||||
type: 'string', |
||||
}, |
||||
in: 'query', |
||||
name: 'sort', |
||||
description: |
||||
'Comma separated field names to sort rows, rows will sort in ascending order based on provided columns. To sort in descending order provide `-` prefix along with column name, like `-field`. Example : `sort=field1,-field2`', |
||||
}; |
||||
export const whereParam = { |
||||
schema: { |
||||
type: 'string', |
||||
}, |
||||
in: 'query', |
||||
name: 'where', |
||||
description: |
||||
'This can be used for filtering rows, which accepts complicated where conditions. For more info visit [here](https://docs.nocodb.com/developer-resources/rest-apis#comparison-operators). Example : `where=(field1,eq,value)`', |
||||
}; |
||||
export const limitParam = { |
||||
schema: { |
||||
type: 'number', |
||||
minimum: 1, |
||||
}, |
||||
in: 'query', |
||||
name: 'limit', |
||||
description: |
||||
'The `limit` parameter used for pagination, the response collection size depends on limit value with default value `25` and maximum value `1000`, which can be overridden by environment variables `DB_QUERY_LIMIT_DEFAULT` and `DB_QUERY_LIMIT_MAX` respectively.', |
||||
example: 25, |
||||
}; |
||||
export const offsetParam = { |
||||
schema: { |
||||
type: 'number', |
||||
minimum: 0, |
||||
}, |
||||
in: 'query', |
||||
name: 'offset', |
||||
description: |
||||
'The `offset` parameter used for pagination, the value helps to select collection from a certain index.', |
||||
example: 0, |
||||
}; |
||||
|
||||
export const shuffleParam = { |
||||
schema: { |
||||
type: 'number', |
||||
minimum: 0, |
||||
maximum: 1, |
||||
}, |
||||
in: 'query', |
||||
name: 'shuffle', |
||||
description: |
||||
'The `shuffle` parameter used for pagination, the response will be shuffled if it is set to 1.', |
||||
example: 0, |
||||
}; |
||||
|
||||
export const columnNameQueryParam = { |
||||
schema: { |
||||
type: 'string', |
||||
}, |
||||
in: 'query', |
||||
name: 'column_name', |
||||
description: |
||||
'Column name of the column you want to group by, eg. `column_name=column1`', |
||||
}; |
||||
|
||||
export const linkFieldNameParam = (columns: SwaggerColumn[]) => { |
||||
const linkColumnIds = []; |
||||
const description = [ |
||||
'**Links Field Identifier** corresponding to the relation field `Links` established between tables.\n\nLink Columns:', |
||||
]; |
||||
for (const { column } of columns) { |
||||
if (!isLinksOrLTAR(column) || column.system) continue; |
||||
linkColumnIds.push(column.id); |
||||
|
||||
description.push(`* ${column.id} - ${column.title}`); |
||||
} |
||||
|
||||
return { |
||||
schema: { |
||||
type: 'string', |
||||
enum: linkColumnIds, |
||||
}, |
||||
name: 'linkFieldId', |
||||
in: 'path', |
||||
required: true, |
||||
description: description.join('\n'), |
||||
}; |
||||
}; |
||||
export const viewIdParams = (views: SwaggerView[]) => { |
||||
const viewIds = []; |
||||
const description = [ |
||||
'Allows you to fetch records that are currently visible within a specific view.\n\nViews:', |
||||
]; |
||||
|
||||
for (const { view } of views) { |
||||
viewIds.push(view.id); |
||||
description.push( |
||||
`* ${view.id} - ${view.is_default ? 'Default view' : view.title}`, |
||||
); |
||||
} |
||||
|
||||
return { |
||||
schema: { |
||||
type: 'string', |
||||
enum: viewIds, |
||||
}, |
||||
description: description.join('\n'), |
||||
name: 'viewId', |
||||
in: 'query', |
||||
required: false, |
||||
}; |
||||
}; |
||||
|
||||
export const referencedRowIdParam = { |
||||
schema: { |
||||
type: 'string', |
||||
}, |
||||
name: 'refRowId', |
||||
in: 'path', |
||||
required: true, |
||||
}; |
||||
|
||||
export const exportTypeParam = { |
||||
schema: { |
||||
type: 'string', |
||||
enum: ['csv', 'excel'], |
||||
}, |
||||
name: 'type', |
||||
in: 'path', |
||||
required: true, |
||||
}; |
||||
|
||||
export const csvExportOffsetParam = { |
||||
schema: { |
||||
type: 'number', |
||||
minimum: 0, |
||||
}, |
||||
in: 'query', |
||||
name: 'offset', |
||||
description: |
||||
'Helps to start export from a certain index. You can get the next set of data offset from previous response header named `nc-export-offset`.', |
||||
example: 0, |
||||
}; |
||||
|
||||
export const nestedWhereParam = (colName) => ({ |
||||
schema: { |
||||
type: 'string', |
||||
}, |
||||
in: 'query', |
||||
name: `nested[${colName}][where]`, |
||||
description: `This can be used for filtering rows in nested column \`${colName}\`, which accepts complicated where conditions. For more info visit [here](https://docs.nocodb.com/developer-resources/rest-apis#comparison-operators). Example : \`nested[${colName}][where]=(field1,eq,value)\``, |
||||
}); |
||||
|
||||
export const nestedFieldParam = (colName) => ({ |
||||
schema: { |
||||
type: 'string', |
||||
}, |
||||
in: 'query', |
||||
name: `nested[${colName}][fields]`, |
||||
description: `Array of field names or comma separated filed names to include in the in nested column \`${colName}\` result. In array syntax pass it like \`fields[]=field1&fields[]=field2.\`. Example : \`nested[${colName}][fields]=field1,field2\``, |
||||
}); |
||||
export const nestedSortParam = (colName) => ({ |
||||
schema: { |
||||
type: 'string', |
||||
}, |
||||
in: 'query', |
||||
name: `nested[${colName}][sort]`, |
||||
description: `Comma separated field names to sort rows in nested column \`${colName}\` rows, it will sort in ascending order based on provided columns. To sort in descending order provide \`-\` prefix along with column name, like \`-field\`. Example : \`nested[${colName}][sort]=field1,-field2\``, |
||||
}); |
||||
export const nestedLimitParam = (colName) => ({ |
||||
schema: { |
||||
type: 'number', |
||||
minimum: 1, |
||||
}, |
||||
in: 'query', |
||||
name: `nested[${colName}][limit]`, |
||||
description: `The \`limit\` parameter used for pagination of nested \`${colName}\` rows, the response collection size depends on limit value and default value is \`25\`.`, |
||||
example: '25', |
||||
}); |
||||
export const nestedOffsetParam = (colName) => ({ |
||||
schema: { |
||||
type: 'number', |
||||
minimum: 0, |
||||
}, |
||||
in: 'query', |
||||
name: `nested[${colName}][offset]`, |
||||
description: `The \`offset\` parameter used for pagination of nested \`${colName}\` rows, the value helps to select collection from a certain index.`, |
||||
example: 0, |
||||
}); |
||||
|
||||
export const getNestedParams = async ( |
||||
columns: SwaggerColumn[], |
||||
): Promise<any[]> => { |
||||
return await columns.reduce(async (paramsArr, { column }) => { |
||||
if (column.uidt === UITypes.LinkToAnotherRecord && !column.system) { |
||||
const colOpt = await column.getColOptions<LinkToAnotherRecordColumn>(); |
||||
if (colOpt.type !== RelationTypes.BELONGS_TO) { |
||||
return [ |
||||
...(await paramsArr), |
||||
nestedWhereParam(column.title), |
||||
nestedOffsetParam(column.title), |
||||
nestedLimitParam(column.title), |
||||
nestedFieldParam(column.title), |
||||
nestedSortParam(column.title), |
||||
]; |
||||
} else { |
||||
return [...(await paramsArr), nestedFieldParam(column.title)]; |
||||
} |
||||
} |
||||
|
||||
return paramsArr; |
||||
}, Promise.resolve([])); |
||||
}; |
@ -0,0 +1,407 @@
|
||||
import { ModelTypes } from 'nocodb-sdk'; |
||||
import { |
||||
fieldsParam, |
||||
getNestedParams, |
||||
limitParam, |
||||
linkFieldNameParam, |
||||
offsetParam, |
||||
recordIdParam, |
||||
shuffleParam, |
||||
sortParam, |
||||
viewIdParams, |
||||
whereParam, |
||||
} from './params'; |
||||
import type { SwaggerColumn } from '../getSwaggerColumnMetas'; |
||||
import type { SwaggerView } from '~/services/api-docs/swaggerV2/getSwaggerJSONV2'; |
||||
import { isRelationExist } from '~/services/api-docs/swagger/templates/paths'; |
||||
|
||||
export const getModelPaths = async (ctx: { |
||||
tableName: string; |
||||
type: ModelTypes; |
||||
columns: SwaggerColumn[]; |
||||
tableId: string; |
||||
views: SwaggerView[]; |
||||
}): Promise<{ [path: string]: any }> => ({ |
||||
[`/api/v2/tables/${ctx.tableId}/records`]: { |
||||
get: { |
||||
summary: `${ctx.tableName} list`, |
||||
operationId: `${ctx.tableName.toLowerCase()}-db-table-row-list`, |
||||
description: `List of all rows from ${ctx.tableName} ${ctx.type} and response data fields can be filtered based on query params.`, |
||||
tags: [ctx.tableName], |
||||
parameters: [ |
||||
viewIdParams(ctx.views), |
||||
fieldsParam, |
||||
sortParam, |
||||
whereParam, |
||||
limitParam, |
||||
shuffleParam, |
||||
offsetParam, |
||||
...(await getNestedParams(ctx.columns)), |
||||
], |
||||
responses: { |
||||
'200': { |
||||
description: 'OK', |
||||
content: { |
||||
'application/json': { |
||||
schema: getPaginatedResponseType(`${ctx.tableName}Response`), |
||||
}, |
||||
}, |
||||
}, |
||||
}, |
||||
}, |
||||
...(ctx.type === ModelTypes.TABLE |
||||
? { |
||||
post: { |
||||
summary: `${ctx.tableName} create`, |
||||
description: |
||||
'Insert a new row in table by providing a key value pair object where key refers to the column alias. All the required fields should be included with payload excluding `autoincrement` and column with default value.', |
||||
operationId: `${ctx.tableName.toLowerCase()}-create`, |
||||
responses: { |
||||
'200': { |
||||
description: 'OK', |
||||
content: { |
||||
'application/json': { |
||||
schema: { |
||||
$ref: `#/components/schemas/${ctx.tableName}Response`, |
||||
}, |
||||
}, |
||||
}, |
||||
}, |
||||
'400': { |
||||
$ref: '#/components/responses/BadRequest', |
||||
}, |
||||
}, |
||||
tags: [ctx.tableName], |
||||
requestBody: { |
||||
content: { |
||||
'application/json': { |
||||
schema: { |
||||
oneOf: [ |
||||
{ |
||||
$ref: `#/components/schemas/${ctx.tableName}Request`, |
||||
}, |
||||
{ |
||||
type: 'array', |
||||
items: { |
||||
$ref: `#/components/schemas/${ctx.tableName}Request`, |
||||
}, |
||||
}, |
||||
], |
||||
}, |
||||
}, |
||||
}, |
||||
}, |
||||
}, |
||||
patch: { |
||||
summary: `${ctx.tableName} update`, |
||||
operationId: `${ctx.tableName.toLowerCase()}-update`, |
||||
description: |
||||
'Partial update row in table by providing a key value pair object where key refers to the column alias. You need to only include columns which you want to update.', |
||||
responses: { |
||||
'200': { |
||||
description: 'OK', |
||||
content: { |
||||
'application/json': { |
||||
schema: {}, |
||||
}, |
||||
}, |
||||
}, |
||||
'400': { |
||||
$ref: '#/components/responses/BadRequest', |
||||
}, |
||||
}, |
||||
tags: [ctx.tableName], |
||||
requestBody: { |
||||
content: { |
||||
'application/json': { |
||||
schema: { |
||||
oneOf: [ |
||||
{ |
||||
$ref: `#/components/schemas/${ctx.tableName}Request`, |
||||
}, |
||||
{ |
||||
type: 'array', |
||||
items: { |
||||
$ref: `#/components/schemas/${ctx.tableName}Request`, |
||||
}, |
||||
}, |
||||
], |
||||
}, |
||||
}, |
||||
}, |
||||
}, |
||||
}, |
||||
delete: { |
||||
summary: `${ctx.tableName} delete`, |
||||
operationId: `${ctx.tableName.toLowerCase()}-delete`, |
||||
responses: { |
||||
'200': { |
||||
description: 'OK', |
||||
}, |
||||
}, |
||||
tags: [ctx.tableName], |
||||
description: |
||||
'Delete a row by using the **primary key** column value.', |
||||
requestBody: { |
||||
content: { |
||||
'application/json': { |
||||
schema: { |
||||
oneOf: [ |
||||
{ |
||||
$ref: `#/components/schemas/${ctx.tableName}IdRequest`, |
||||
}, |
||||
{ |
||||
type: 'array', |
||||
items: { |
||||
$ref: `#/components/schemas/${ctx.tableName}IdRequest`, |
||||
}, |
||||
}, |
||||
], |
||||
}, |
||||
}, |
||||
}, |
||||
}, |
||||
}, |
||||
} |
||||
: {}), |
||||
}, |
||||
[`/api/v2/tables/${ctx.tableId}/records/{recordId}`]: { |
||||
get: { |
||||
parameters: [recordIdParam, fieldsParam], |
||||
summary: `${ctx.tableName} read`, |
||||
description: 'Read a row data by using the **primary key** column value.', |
||||
operationId: `${ctx.tableName.toLowerCase()}-read`, |
||||
tags: [ctx.tableName], |
||||
responses: { |
||||
'201': { |
||||
description: 'Created', |
||||
content: { |
||||
'application/json': { |
||||
schema: { |
||||
$ref: `#/components/schemas/${ctx.tableName}Response`, |
||||
}, |
||||
}, |
||||
}, |
||||
}, |
||||
}, |
||||
}, |
||||
}, |
||||
[`/api/v2/tables/${ctx.tableId}/records/count`]: { |
||||
parameters: [viewIdParams(ctx.views)], |
||||
get: { |
||||
summary: `${ctx.tableName} count`, |
||||
operationId: `${ctx.tableName.toLowerCase()}-count`, |
||||
description: 'Get rows count of a table by applying optional filters.', |
||||
tags: [ctx.tableName], |
||||
parameters: [whereParam], |
||||
responses: { |
||||
'200': { |
||||
description: 'OK', |
||||
content: { |
||||
'application/json': { |
||||
schema: { |
||||
type: 'object', |
||||
properties: { |
||||
count: { |
||||
type: 'number', |
||||
}, |
||||
}, |
||||
required: ['list', 'pageInfo'], |
||||
}, |
||||
examples: { |
||||
'Example 1': { |
||||
value: { |
||||
count: 3, |
||||
}, |
||||
}, |
||||
}, |
||||
}, |
||||
}, |
||||
}, |
||||
'400': { |
||||
$ref: '#/components/responses/BadRequest', |
||||
}, |
||||
}, |
||||
}, |
||||
}, |
||||
|
||||
...(isRelationExist(ctx.columns) |
||||
? { |
||||
[`/api/v2/tables/${ctx.tableId}/links/{linkFieldId}/records/{recordId}`]: |
||||
{ |
||||
parameters: [linkFieldNameParam(ctx.columns), recordIdParam], |
||||
get: { |
||||
summary: 'Link Records list', |
||||
operationId: `${ctx.tableName.toLowerCase()}-nested-list`, |
||||
description: |
||||
'This API endpoint allows you to retrieve list of linked records for a specific `Link field` and `Record ID`. The response is an array of objects containing Primary Key and its corresponding display value.', |
||||
tags: [ctx.tableName], |
||||
parameters: [ |
||||
fieldsParam, |
||||
sortParam, |
||||
whereParam, |
||||
limitParam, |
||||
offsetParam, |
||||
], |
||||
responses: { |
||||
'200': { |
||||
description: 'OK', |
||||
content: { |
||||
'application/json': { |
||||
schema: { |
||||
type: 'object', |
||||
properties: { |
||||
list: { |
||||
type: 'array', |
||||
description: 'List of data objects', |
||||
items: { |
||||
type: 'object', |
||||
}, |
||||
}, |
||||
pageInfo: { |
||||
$ref: '#/components/schemas/Paginated', |
||||
description: 'Paginated Info', |
||||
}, |
||||
}, |
||||
required: ['list', 'pageInfo'], |
||||
}, |
||||
}, |
||||
}, |
||||
}, |
||||
'400': { |
||||
$ref: '#/components/responses/BadRequest', |
||||
}, |
||||
}, |
||||
}, |
||||
post: { |
||||
summary: 'Link Records', |
||||
operationId: `${ctx.tableName.toLowerCase()}-nested-link`, |
||||
responses: { |
||||
'200': { |
||||
description: 'OK', |
||||
content: { |
||||
'application/json': { |
||||
schema: {}, |
||||
examples: { |
||||
'Example 1': { |
||||
value: true, |
||||
}, |
||||
}, |
||||
}, |
||||
}, |
||||
}, |
||||
'400': { |
||||
$ref: '#/components/responses/BadRequest', |
||||
}, |
||||
}, |
||||
tags: [ctx.tableName], |
||||
requestBody: { |
||||
content: { |
||||
'application/json': { |
||||
schema: { |
||||
oneOf: [ |
||||
{ |
||||
type: 'object', |
||||
}, |
||||
{ |
||||
type: 'array', |
||||
items: { |
||||
type: 'object', |
||||
}, |
||||
}, |
||||
], |
||||
}, |
||||
examples: { |
||||
'Example 1': { |
||||
value: [ |
||||
{ |
||||
Id: 4, |
||||
}, |
||||
{ |
||||
Id: 5, |
||||
}, |
||||
], |
||||
}, |
||||
}, |
||||
}, |
||||
}, |
||||
}, |
||||
description: |
||||
'This API endpoint allows you to link records to a specific `Link field` and `Record ID`. The request payload is an array of record-ids from the adjacent table for linking purposes. Note that any existing links, if present, will be unaffected during this operation.', |
||||
parameters: [recordIdParam], |
||||
}, |
||||
delete: { |
||||
summary: 'Unlink Records', |
||||
operationId: `${ctx.tableName.toLowerCase()}-nested-unlink`, |
||||
responses: { |
||||
'200': { |
||||
description: 'OK', |
||||
content: { |
||||
'application/json': { |
||||
schema: {}, |
||||
examples: { |
||||
'Example 1': { |
||||
value: true, |
||||
}, |
||||
}, |
||||
}, |
||||
}, |
||||
}, |
||||
'400': { |
||||
$ref: '#/components/responses/BadRequest', |
||||
}, |
||||
}, |
||||
tags: [ctx.tableName], |
||||
requestBody: { |
||||
content: { |
||||
'application/json': { |
||||
schema: { |
||||
oneOf: [ |
||||
{ |
||||
type: 'array', |
||||
items: { |
||||
type: 'object', |
||||
}, |
||||
}, |
||||
], |
||||
}, |
||||
examples: { |
||||
'Example 1': { |
||||
value: [ |
||||
{ |
||||
Id: 1, |
||||
}, |
||||
{ |
||||
Id: 2, |
||||
}, |
||||
], |
||||
}, |
||||
}, |
||||
}, |
||||
}, |
||||
}, |
||||
description: |
||||
'This API endpoint allows you to unlink records from a specific `Link field` and `Record ID`. The request payload is an array of record-ids from the adjacent table for unlinking purposes. Note that, \n- duplicated record-ids will be ignored.\n- non-existent record-ids will be ignored.', |
||||
parameters: [recordIdParam], |
||||
}, |
||||
}, |
||||
} |
||||
: {}), |
||||
}); |
||||
|
||||
function getPaginatedResponseType(type: string) { |
||||
return { |
||||
type: 'object', |
||||
properties: { |
||||
list: { |
||||
type: 'array', |
||||
items: { |
||||
$ref: `#/components/schemas/${type}`, |
||||
}, |
||||
}, |
||||
PageInfo: { |
||||
$ref: `#/components/schemas/Paginated`, |
||||
}, |
||||
}, |
||||
}; |
||||
} |
@ -0,0 +1,109 @@
|
||||
import { isSystemColumn } from 'nocodb-sdk'; |
||||
import type { SwaggerColumn } from '../getSwaggerColumnMetas'; |
||||
|
||||
export const getModelSchemas = (ctx: { |
||||
tableName: string; |
||||
orgs: string; |
||||
baseName: string; |
||||
columns: Array<SwaggerColumn>; |
||||
}) => ({ |
||||
[`${ctx.tableName}Response`]: { |
||||
title: `${ctx.tableName} Response`, |
||||
type: 'object', |
||||
description: '', |
||||
'x-internal': false, |
||||
properties: { |
||||
...(ctx.columns?.reduce( |
||||
(colsObj, { title, virtual, column, ...fieldProps }) => ({ |
||||
...colsObj, |
||||
...(column.system |
||||
? {} |
||||
: { |
||||
[title]: fieldProps, |
||||
}), |
||||
}), |
||||
{}, |
||||
) || {}), |
||||
}, |
||||
}, |
||||
[`${ctx.tableName}Request`]: { |
||||
title: `${ctx.tableName} Request`, |
||||
type: 'object', |
||||
description: '', |
||||
'x-internal': false, |
||||
properties: { |
||||
...(ctx.columns?.reduce( |
||||
(colsObj, { title, virtual, column, ...fieldProps }) => ({ |
||||
...colsObj, |
||||
...(virtual || isSystemColumn(column) || column.ai || column.meta?.ag |
||||
? {} |
||||
: { |
||||
[title]: fieldProps, |
||||
}), |
||||
}), |
||||
{}, |
||||
) || {}), |
||||
}, |
||||
}, |
||||
[`${ctx.tableName}IdRequest`]: { |
||||
title: `${ctx.tableName} Id Request`, |
||||
type: 'object', |
||||
description: '', |
||||
'x-internal': false, |
||||
properties: { |
||||
...(ctx.columns?.reduce( |
||||
(colsObj, { title, virtual, column, ...fieldProps }) => ({ |
||||
...colsObj, |
||||
...(column.pk |
||||
? { |
||||
[title]: fieldProps, |
||||
} |
||||
: {}), |
||||
}), |
||||
{}, |
||||
) || {}), |
||||
}, |
||||
}, |
||||
}); |
||||
export const getViewSchemas = (ctx: { |
||||
tableName: string; |
||||
viewName: string; |
||||
orgs: string; |
||||
baseName: string; |
||||
columns: Array<SwaggerColumn>; |
||||
}) => ({ |
||||
[`${ctx.tableName}${ctx.viewName}GridResponse`]: { |
||||
title: `${ctx.tableName} : ${ctx.viewName} Response`, |
||||
type: 'object', |
||||
description: '', |
||||
'x-internal': false, |
||||
properties: { |
||||
...(ctx.columns?.reduce( |
||||
(colsObj, { title, virtual, column, ...fieldProps }) => ({ |
||||
...colsObj, |
||||
[title]: fieldProps, |
||||
}), |
||||
{}, |
||||
) || {}), |
||||
}, |
||||
}, |
||||
[`${ctx.tableName}${ctx.viewName}GridRequest`]: { |
||||
title: `${ctx.tableName} : ${ctx.viewName} Request`, |
||||
type: 'object', |
||||
description: '', |
||||
'x-internal': false, |
||||
properties: { |
||||
...(ctx.columns?.reduce( |
||||
(colsObj, { title, virtual, column, ...fieldProps }) => ({ |
||||
...colsObj, |
||||
...(virtual |
||||
? {} |
||||
: { |
||||
[title]: fieldProps, |
||||
}), |
||||
}), |
||||
{}, |
||||
) || {}), |
||||
}, |
||||
}, |
||||
}); |
Loading…
Reference in new issue