From 090da34a99cea717cd4936654ed7146270723972 Mon Sep 17 00:00:00 2001 From: Maurits Lourens Date: Thu, 3 Mar 2022 15:19:36 +0100 Subject: [PATCH] fix openapi 3 test doc and tests --- .../query/import/sources/base/index.ts | 6 +- .../query/import/sources/openapi3.ts | 71 +++--- .../tests/openapi3/data/crud/crud.json | 144 +++++++----- .../tests/openapi3/data/crud/crud.yaml | 209 +++++++++--------- .../sources/tests/openapi3/openapi3.spec.js | 20 +- 5 files changed, 225 insertions(+), 225 deletions(-) diff --git a/packages/server/src/api/controllers/query/import/sources/base/index.ts b/packages/server/src/api/controllers/query/import/sources/base/index.ts index e666fdc193..096fa10e92 100644 --- a/packages/server/src/api/controllers/query/import/sources/base/index.ts +++ b/packages/server/src/api/controllers/query/import/sources/base/index.ts @@ -23,7 +23,7 @@ export abstract class ImportSource { name: string, method: string, path: string, - url: URL, + url: URL | null, queryString: string, headers: object = {}, parameters: QueryParameter[] = [], @@ -34,7 +34,9 @@ export abstract class ImportSource { const transformer = "return data" const schema = {} path = this.processPath(path) - path = `${url.origin}/${path}` + if (url) { + path = `${url.origin}/${path}` + } queryString = this.processQuery(queryString) const requestBody = JSON.stringify(body, null, 2) diff --git a/packages/server/src/api/controllers/query/import/sources/openapi3.ts b/packages/server/src/api/controllers/query/import/sources/openapi3.ts index 8c40c49c9d..c9e49595b2 100644 --- a/packages/server/src/api/controllers/query/import/sources/openapi3.ts +++ b/packages/server/src/api/controllers/query/import/sources/openapi3.ts @@ -3,14 +3,7 @@ import { Query, QueryParameter } from "../../../../../definitions/datasource" import { OpenAPIV3 } from "openapi-types" import { OpenAPISource } from "./base/openapi" import { URL } from "url" -import { - getGlobalDB, - getTenantId, - isMultiTenant, -} from "@budibase/backend-core/tenancy" -import { getScopedConfig } from "@budibase/backend-core/db" -const jsonMimeType = "application/json" const parameterNotRef = ( param: OpenAPIV3.ParameterObject | OpenAPIV3.ReferenceObject ): param is OpenAPIV3.ParameterObject => { @@ -25,6 +18,13 @@ const requestBodyNotRef = ( return param !== undefined } +const schemaNotRef = ( + param: OpenAPIV3.SchemaObject | OpenAPIV3.ReferenceObject | undefined +): param is OpenAPIV3.SchemaObject => { + // all refs are deferenced by parser library + return param !== undefined +} + const isOpenAPI3 = (document: any): document is OpenAPIV3.Document => { return document.openapi.includes("3") } @@ -49,9 +49,25 @@ const getRequestBody = (operation: OpenAPIV3.OperationObject) => { if (requestBodyNotRef(operation.requestBody)) { const request: OpenAPIV3.RequestBodyObject = operation.requestBody as OpenAPIV3.RequestBodyObject - return request.content[jsonMimeType]?.example + const supportedMimeTypes = getMimeTypes(operation) + return supportedMimeTypes.length > 0 && + schemaNotRef(request.content[supportedMimeTypes[0]].schema) + ? ( + request.content[supportedMimeTypes[0]] + .schema as OpenAPIV3.SchemaObject + ).example + : undefined } - return null + return undefined +} + +const getMimeTypes = (operation: OpenAPIV3.OperationObject): string[] => { + if (requestBodyNotRef(operation.requestBody)) { + const request: OpenAPIV3.RequestBodyObject = + operation.requestBody as OpenAPIV3.RequestBodyObject + return Object.keys(request.content) + } + return [] } /** @@ -75,34 +91,6 @@ export class OpenAPI3 extends OpenAPISource { } } - getPlatformUrl = async (): Promise => { - const db = getGlobalDB() - const publicConfig = await getScopedConfig(db, { - type: "settings", - }) - - let url = publicConfig.platformUrl - if (isMultiTenant()) { - url += `/${getTenantId()}` - } - return url - } - - getUrl = async (): Promise => { - const platformUrl = await this.getPlatformUrl() - let url = this.document.servers ? this.document.servers[0].url : null - if (url) { - // check if url is relative or absolute - if (url.includes("http") || url.includes("https")) { - return new URL(url) - } - - return new URL(`${platformUrl}${url}`) - } - // if the specification doesn't contain a servers object, return the PLATFORM_URM environment variable - return new URL(platformUrl) - } - getInfo = async (): Promise => { const name = this.document.info.title || "Swagger Import" return { @@ -111,7 +99,9 @@ export class OpenAPI3 extends OpenAPISource { } getQueries = async (datasourceId: string): Promise => { - const url: URL = await this.getUrl() + const url: URL | null = this.document.servers + ? new URL(this.document.servers[0].url) + : null const queries: Query[] = [] for (let [path, pathItemObject] of Object.entries(this.document.paths)) { @@ -138,6 +128,11 @@ export class OpenAPI3 extends OpenAPISource { const headers: any = {} let requestBody = getRequestBody(operation) const parameters: QueryParameter[] = [] + const mimeTypes = getMimeTypes(operation) + + if (mimeTypes.length > 0) { + headers["Content-Type"] = mimeTypes[0] + } // combine the path parameters with the operation parameters const operationParams = operation.parameters || [] diff --git a/packages/server/src/api/controllers/query/import/sources/tests/openapi3/data/crud/crud.json b/packages/server/src/api/controllers/query/import/sources/tests/openapi3/data/crud/crud.json index c1cf4c2b18..a859eec8e5 100644 --- a/packages/server/src/api/controllers/query/import/sources/tests/openapi3/data/crud/crud.json +++ b/packages/server/src/api/controllers/query/import/sources/tests/openapi3/data/crud/crud.json @@ -5,6 +5,11 @@ "version": "1.0.0", "title": "CRUD" }, + "servers": [ + { + "url": "http://example.com" + } + ], "tags": [ { "name": "entity" @@ -17,16 +22,24 @@ "entity" ], "operationId": "createEntity", - "parameters": [ - { - "$ref": "#/components/schemas/CreateEntityParameter" + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateEntity" + } + } } - ], + }, "responses": { "200": { "description": "successful operation", - "schema": { - "$ref": "#/components/schemas/Entity" + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Entity" + } + } } } } @@ -36,22 +49,23 @@ "entity" ], "operationId": "getEntities", - "produces": [ - "application/json" - ], "parameters": [ { - "$ref": "#/components/schemas/PageParameter" + "$ref": "#/components/parameters/PageParameter" }, { - "$ref": "#/components/schemas/SizeParameter" + "$ref": "#/components/parameters/SizeParameter" } ], "responses": { "200": { "description": "successful operation", - "schema": { - "$ref": "#/components/schemas/Entities" + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Entities" + } + } } } } @@ -60,7 +74,7 @@ "/entities/{entityId}": { "parameters": [ { - "$ref": "#/components/schemas/EntityIdParameter" + "$ref": "#/components/parameters/EntityIdParameter" } ], "get": { @@ -68,14 +82,15 @@ "entity" ], "operationId": "getEntity", - "produces": [ - "application/json" - ], "responses": { "200": { "description": "successful operation", - "schema": { - "$ref": "#/components/schemas/Entity" + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Entity" + } + } } } } @@ -85,16 +100,24 @@ "entity" ], "operationId": "updateEntity", - "parameters": [ - { - "$ref": "#/components/schemas/EntityParameter" + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Entity" + } + } } - ], + }, "responses": { "200": { "description": "successful operation", - "schema": { - "$ref": "#/components/schemas/Entity" + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Entity" + } + } } } } @@ -104,16 +127,24 @@ "entity" ], "operationId": "patchEntity", - "parameters": [ - { - "$ref": "#/components/schemas/EntityParameter" + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Entity" + } + } } - ], + }, "responses": { "200": { "description": "successful operation", - "schema": { - "$ref": "#/components/schemas/Entity" + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Entity" + } + } } } } @@ -124,10 +155,7 @@ ], "parameters": [ { - "type": "string", - "name": "x-api-key", - "in": "header", - "required": false + "$ref": "#/components/parameters/APIKeyParameter" } ], "operationId": "deleteEntity", @@ -140,50 +168,44 @@ } }, "components": { - "schemas": { + "parameters": { "EntityIdParameter": { - "type": "integer", - "format": "int64", + "schema": { + "type": "integer", + "format": "int64" + }, "name": "entityId", "in": "path", "required": true }, - "CreateEntityParameter": { - "name": "entity", - "in": "body", - "required": true, - "schema": { - "$ref": "#/components/schemas/CreateEntity" - } - }, - "EntityParameter": { - "name": "entity", - "in": "body", - "required": true, - "schema": { - "$ref": "#/components/schemas/Entity" - } - }, - "PageParameter": { - "type": "integer", - "format": "int32", + "PageParameter": { + "schema": { + "type": "integer", + "format": "int32" + }, "name": "page", "in": "query", "required": false }, "SizeParameter": { - "type": "integer", - "format": "int32", + "schema": { + "type": "integer", + "format": "int32" + }, "name": "size", "in": "query", "required": false }, "APIKeyParameter": { - "type": "string", + "schema": { + "type": "string" + }, "name": "x-api-key", "in": "header", "required": false - }, + } + }, + "schemas": { "CreateEntity": { "type": "object", "properties": { diff --git a/packages/server/src/api/controllers/query/import/sources/tests/openapi3/data/crud/crud.yaml b/packages/server/src/api/controllers/query/import/sources/tests/openapi3/data/crud/crud.yaml index f87b3e347c..0a44a50a7b 100644 --- a/packages/server/src/api/controllers/query/import/sources/tests/openapi3/data/crud/crud.yaml +++ b/packages/server/src/api/controllers/query/import/sources/tests/openapi3/data/crud/crud.yaml @@ -1,10 +1,11 @@ --- -openapi: "3.0.2" +openapi: 3.0.2 info: description: A basic swagger file version: 1.0.0 title: CRUD -host: example.com +servers: + - url: http://example.com tags: - name: entity paths: @@ -13,144 +14,140 @@ paths: tags: - entity operationId: createEntity - produces: - - application/json - parameters: - - "$ref": "#/parameters/CreateEntity" + requestBody: + content: + application/json: + schema: + "$ref": "#/components/schemas/CreateEntity" responses: - "200": + '200': description: successful operation - schema: - "$ref": "#/definitions/Entity" + content: + application/json: + schema: + "$ref": "#/components/schemas/Entity" get: tags: - entity operationId: getEntities - produces: - - application/json parameters: - - "$ref": "#/parameters/Page" - - "$ref": "#/parameters/Size" + - "$ref": "#/components/parameters/PageParameter" + - "$ref": "#/components/parameters/SizeParameter" responses: - "200": + '200': description: successful operation - schema: - "$ref": "#/definitions/Entities" + content: + application/json: + schema: + "$ref": "#/components/schemas/Entities" "/entities/{entityId}": parameters: - - "$ref": "#/parameters/EntityId" + - "$ref": "#/components/parameters/EntityIdParameter" get: tags: - entity operationId: getEntity - produces: - - application/json responses: - "200": + '200': description: successful operation - schema: - "$ref": "#/definitions/Entity" + content: + application/json: + schema: + "$ref": "#/components/schemas/Entity" put: tags: - entity operationId: updateEntity - consumes: - - application/json - produces: - - application/json - parameters: - - "$ref": "#/parameters/Entity" + requestBody: + content: + application/json: + schema: + "$ref": "#/components/schemas/Entity" responses: - "200": + '200': description: successful operation - schema: - "$ref": "#/definitions/Entity" + content: + application/json: + schema: + "$ref": "#/components/schemas/Entity" patch: tags: - entity operationId: patchEntity - consumes: - - application/json - produces: - - application/json - parameters: - - "$ref": "#/parameters/Entity" + requestBody: + content: + application/json: + schema: + "$ref": "#/components/schemas/Entity" responses: - "200": + '200': description: successful operation - schema: - "$ref": "#/definitions/Entity" + content: + application/json: + schema: + "$ref": "#/components/schemas/Entity" delete: tags: - entity parameters: - - "$ref": "#/parameters/APIKey" + - "$ref": "#/components/parameters/APIKeyParameter" operationId: deleteEntity - produces: - - application/json responses: - "204": + '204': description: successful operation -parameters: - EntityId: - type: integer - format: int64 - name: entityId - in: path - required: true - CreateEntity: - name: entity - in: body - required: true - schema: - "$ref": "#/definitions/CreateEntity" - Entity: - name: entity - in: body - required: true - schema: - "$ref": "#/definitions/Entity" - Page: - type: integer - format: int32 - name: page - in: query - required: false - Size: - type: integer - format: int32 - name: size - in: query - required: false - APIKey: - type: string - name: x-api-key - in: header - required: false -definitions: - CreateEntity: - type: object - properties: - name: +components: + parameters: + EntityIdParameter: + schema: + type: integer + format: int64 + name: entityId + in: path + required: true + PageParameter: + schema: + type: integer + format: int32 + name: page + in: query + required: false + SizeParameter: + schema: + type: integer + format: int32 + name: size + in: query + required: false + APIKeyParameter: + schema: type: string - type: - type: string - example: - name: name - type: type - Entity: - allOf: - - type: object - properties: - id: - type: integer - format: int64 - - "$ref": "#/definitions/CreateEntity" - example: - id: 1 - name: name - type: type - Entities: - type: array - items: - "$ref": "#/definitions/Entity" + name: x-api-key + in: header + required: false + schemas: + CreateEntity: + type: object + properties: + name: + type: string + type: + type: string + example: + name: name + type: type + Entity: + allOf: + - type: object + properties: + id: + type: integer + format: int64 + - "$ref": "#/components/schemas/CreateEntity" + example: + id: 1 + name: name + type: type + Entities: + type: array + items: + "$ref": "#/components/schemas/Entity" diff --git a/packages/server/src/api/controllers/query/import/sources/tests/openapi3/openapi3.spec.js b/packages/server/src/api/controllers/query/import/sources/tests/openapi3/openapi3.spec.js index 6278e0fece..731c245d4e 100644 --- a/packages/server/src/api/controllers/query/import/sources/tests/openapi3/openapi3.spec.js +++ b/packages/server/src/api/controllers/query/import/sources/tests/openapi3/openapi3.spec.js @@ -1,21 +1,6 @@ const fs = require("fs") const path = require("path") -const getGlobalDB = jest.fn().mockReturnValue("db") -const getTenantId = jest.fn().mockReturnValue("1") -const isMultiTenant = jest.fn().mockReturnValue(true) -const getScopedConfig = jest - .fn() - .mockResolvedValue({ platformUrl: "somePlatform" }) -jest.mock("@budibase/backend-core/db", () => ({ - getScopedConfig, -})) - -jest.mock("@budibase/backend-core/tenancy", () => ({ - getTenantId, - getGlobalDB, - isMultiTenant, -})) const { OpenAPI3 } = require("../../openapi3") const getData = (file, extension) => { @@ -48,10 +33,9 @@ describe("OpenAPI3 Import", () => { }) const runTests = async (filename, test, assertions) => { - /*for (let extension of ["json", "yaml"]) { + for (let extension of ["json", "yaml"]) { await test(filename, extension, assertions) - }*/ - await test(filename, "json", assertions) + } } const testImportInfo = async (file, extension) => {