Comparing version 0.12.0-alpha.0 to 0.12.0
76
index.js
@@ -12,3 +12,2 @@ 'use strict'; | ||
const paramCase = require('param-case'); | ||
const uuid = require('uuid'); | ||
const fetch = require('@whatwg-node/fetch'); | ||
@@ -118,3 +117,3 @@ const colors = _interopDefault(require('ansi-colors')); | ||
return tslib.__awaiter(this, void 0, void 0, function* () { | ||
const id = uuid.v4(); | ||
const id = fetch.crypto.randomUUID(); | ||
const name = event.subscription; | ||
@@ -124,3 +123,2 @@ if (!this.operations.has(name)) { | ||
} | ||
const { document, operationName, variables } = this.operations.get(name); | ||
logger.info(`[Subscription] Start ${id}`, event); | ||
@@ -131,5 +129,3 @@ const result = yield this.execute({ | ||
url: event.url, | ||
document, | ||
operationName, | ||
variables, | ||
variables: event.variables, | ||
contextValue, | ||
@@ -173,5 +169,5 @@ }); | ||
} | ||
execute({ id, document, name, url, operationName, variables, contextValue, }) { | ||
execute({ id, name, url, variables, contextValue, }) { | ||
return tslib.__awaiter(this, void 0, void 0, function* () { | ||
const variableNodes = this.operations.get(name).variables; | ||
const { document, operationName, variables: variableNodes } = this.operations.get(name); | ||
const variableValues = variableNodes.reduce((values, variable) => { | ||
@@ -186,3 +182,3 @@ const value = parseVariable({ | ||
} | ||
return Object.assign(Object.assign({}, values), { [name]: value }); | ||
return Object.assign(Object.assign({}, values), { [variable.variable.name.value]: value }); | ||
}, {}); | ||
@@ -380,3 +376,3 @@ const execution = yield this.sofa.subscribe({ | ||
function createQueryRoute({ sofa, router, fieldName, }) { | ||
var _a, _b, _c, _d; | ||
var _a, _b, _c, _d, _e, _f; | ||
logger.debug(`[Router] Creating ${fieldName} query`); | ||
@@ -415,2 +411,4 @@ const queryType = sofa.schema.getQueryType(); | ||
method: route.method.toUpperCase(), | ||
tags: (_e = routeConfig === null || routeConfig === void 0 ? void 0 : routeConfig.tags) !== null && _e !== void 0 ? _e : [], | ||
description: (_f = routeConfig === null || routeConfig === void 0 ? void 0 : routeConfig.description) !== null && _f !== void 0 ? _f : '', | ||
}; | ||
@@ -449,2 +447,4 @@ } | ||
method, | ||
tags: (routeConfig === null || routeConfig === void 0 ? void 0 : routeConfig.tags) || [], | ||
description: (routeConfig === null || routeConfig === void 0 ? void 0 : routeConfig.description) || '', | ||
}; | ||
@@ -631,3 +631,3 @@ } | ||
function buildSchemaObjectFromType(type) { | ||
function buildSchemaObjectFromType(type, opts) { | ||
const required = []; | ||
@@ -641,3 +641,3 @@ const properties = {}; | ||
} | ||
properties[fieldName] = resolveField(field); | ||
properties[fieldName] = resolveField(field, opts); | ||
if (field.description) { | ||
@@ -649,4 +649,4 @@ properties[fieldName].description = field.description; | ||
} | ||
function resolveField(field) { | ||
return resolveFieldType(field.type); | ||
function resolveField(field, opts) { | ||
return resolveFieldType(field.type, opts); | ||
} | ||
@@ -656,6 +656,5 @@ // array -> [type] | ||
// scalar -> swagger primitive | ||
function resolveFieldType(type) { | ||
var _a, _b; | ||
function resolveFieldType(type, opts) { | ||
if (graphql.isNonNullType(type)) { | ||
return resolveFieldType(type.ofType); | ||
return resolveFieldType(type.ofType, opts); | ||
} | ||
@@ -665,3 +664,3 @@ if (graphql.isListType(type)) { | ||
type: 'array', | ||
items: resolveFieldType(type.ofType), | ||
items: resolveFieldType(type.ofType, opts), | ||
}; | ||
@@ -675,3 +674,4 @@ } | ||
if (graphql.isScalarType(type)) { | ||
return (mapToPrimitive(type.name) || { | ||
return (mapToPrimitive(type.name) || | ||
opts.customScalars[type.name] || { | ||
type: 'object', | ||
@@ -683,3 +683,3 @@ }); | ||
type: 'string', | ||
enum: (_b = (_a = type.astNode) === null || _a === void 0 ? void 0 : _a.values) === null || _b === void 0 ? void 0 : _b.map((value) => value.name.value), | ||
enum: type.getValues().map((value) => value.name), | ||
}; | ||
@@ -692,6 +692,8 @@ } | ||
function buildPathFromOperation({ url, schema, operation, useRequestBody, }) { | ||
function buildPathFromOperation({ url, schema, operation, useRequestBody, tags, description, customScalars, }) { | ||
const info = getOperationInfo(operation); | ||
const description = resolveDescription(schema, info.operation); | ||
return Object.assign(Object.assign({ operationId: info.name }, (useRequestBody | ||
const summary = resolveSummary(schema, info.operation); | ||
return Object.assign(Object.assign({ tags, | ||
description, | ||
summary, operationId: info.name }, (useRequestBody | ||
? { | ||
@@ -710,3 +712,3 @@ requestBody: { | ||
200: { | ||
description, | ||
description: summary, | ||
content: { | ||
@@ -717,2 +719,3 @@ 'application/json': { | ||
operation: info.operation, | ||
customScalars, | ||
}), | ||
@@ -769,3 +772,3 @@ }, | ||
} | ||
function resolveResponse({ schema, operation, }) { | ||
function resolveResponse({ schema, operation, customScalars, }) { | ||
const operationType = operation.operation; | ||
@@ -777,3 +780,3 @@ const rootField = operation.selectionSet.selections[0]; | ||
const field = queryType.getFields()[rootField.name.value]; | ||
return resolveFieldType(field.type); | ||
return resolveFieldType(field.type, { customScalars }); | ||
} | ||
@@ -783,3 +786,3 @@ if (operationType === 'mutation') { | ||
const field = mutationType.getFields()[rootField.name.value]; | ||
return resolveFieldType(field.type); | ||
return resolveFieldType(field.type, { customScalars }); | ||
} | ||
@@ -791,3 +794,3 @@ } | ||
} | ||
function resolveDescription(schema, operation) { | ||
function resolveSummary(schema, operation) { | ||
const selection = operation.selectionSet.selections[0]; | ||
@@ -813,3 +816,3 @@ const fieldName = selection.name.value; | ||
function OpenAPI({ schema, info, servers, components, security, tags, }) { | ||
function OpenAPI({ schema, info, servers, components, security, tags, customScalars = {}, }) { | ||
const types = schema.getTypeMap(); | ||
@@ -820,3 +823,3 @@ const swagger = { | ||
servers, | ||
tags, | ||
tags: [], | ||
paths: {}, | ||
@@ -831,3 +834,5 @@ components: { | ||
!graphql.isIntrospectionType(type)) { | ||
swagger.components.schemas[typeName] = buildSchemaObjectFromType(type); | ||
swagger.components.schemas[typeName] = buildSchemaObjectFromType(type, { | ||
customScalars, | ||
}); | ||
} | ||
@@ -841,2 +846,5 @@ } | ||
} | ||
if (tags) { | ||
swagger.tags = tags; | ||
} | ||
return { | ||
@@ -850,3 +858,4 @@ addRoute(info, config) { | ||
} | ||
swagger.paths[path][info.method.toLowerCase()] = buildPathFromOperation({ | ||
const pathsObj = swagger.paths[path]; | ||
pathsObj[info.method.toLowerCase()] = buildPathFromOperation({ | ||
url: path, | ||
@@ -856,2 +865,5 @@ operation: info.document, | ||
useRequestBody: ['POST', 'PUT', 'PATCH'].includes(info.method), | ||
tags: info.tags || [], | ||
description: info.description || '', | ||
customScalars, | ||
}); | ||
@@ -858,0 +870,0 @@ }, |
import { GraphQLSchema } from 'graphql'; | ||
import { RouteInfo } from '../types'; | ||
export declare function OpenAPI({ schema, info, servers, components, security, tags, }: { | ||
import { OpenAPIV3 } from 'openapi-types'; | ||
export declare function OpenAPI({ schema, info, servers, components, security, tags, customScalars, }: { | ||
schema: GraphQLSchema; | ||
info: Record<string, any>; | ||
servers?: Record<string, any>[]; | ||
info: OpenAPIV3.InfoObject; | ||
servers?: OpenAPIV3.ServerObject[]; | ||
components?: Record<string, any>; | ||
security?: Record<string, any>[]; | ||
tags?: Record<string, any>[]; | ||
security?: OpenAPIV3.SecurityRequirementObject[]; | ||
tags?: OpenAPIV3.TagObject[]; | ||
/** | ||
* Override mapping of custom scalars to OpenAPI | ||
* @example | ||
* ```js | ||
* { | ||
* Date: { type: "string", format: "date" } | ||
* } | ||
* ``` | ||
*/ | ||
customScalars?: Record<string, any>; | ||
}): { | ||
@@ -14,3 +25,3 @@ addRoute(info: RouteInfo, config?: { | ||
}): void; | ||
get(): any; | ||
get(): OpenAPIV3.Document<{}>; | ||
}; |
import { DocumentNode, GraphQLSchema } from 'graphql'; | ||
export declare function buildPathFromOperation({ url, schema, operation, useRequestBody, }: { | ||
import { OpenAPIV3 } from 'openapi-types'; | ||
export declare function buildPathFromOperation({ url, schema, operation, useRequestBody, tags, description, customScalars, }: { | ||
url: string; | ||
@@ -7,2 +8,5 @@ schema: GraphQLSchema; | ||
useRequestBody: boolean; | ||
}): any; | ||
tags?: string[]; | ||
description?: string; | ||
customScalars: Record<string, any>; | ||
}): OpenAPIV3.OperationObject; |
import { GraphQLObjectType, GraphQLInputObjectType, GraphQLType } from 'graphql'; | ||
export declare function buildSchemaObjectFromType(type: GraphQLObjectType | GraphQLInputObjectType): any; | ||
export declare function resolveFieldType(type: GraphQLType): any; | ||
export declare function buildSchemaObjectFromType(type: GraphQLObjectType | GraphQLInputObjectType, opts: { | ||
customScalars: Record<string, any>; | ||
}): any; | ||
export declare function resolveFieldType(type: GraphQLType, opts: { | ||
customScalars: Record<string, any>; | ||
}): any; |
{ | ||
"name": "sofa-api", | ||
"version": "0.12.0-alpha.0", | ||
"version": "0.12.0", | ||
"description": "Create REST APIs with GraphQL", | ||
@@ -11,10 +11,10 @@ "sideEffects": false, | ||
"@graphql-tools/utils": "8.12.0", | ||
"ansi-colors": "4.1.3", | ||
"@whatwg-node/fetch": "^0.4.3", | ||
"@whatwg-node/server": "^0.4.1", | ||
"ansi-colors": "4.1.3", | ||
"itty-router": "^2.6.1", | ||
"openapi-types": "12.0.2", | ||
"param-case": "3.0.4", | ||
"title-case": "3.0.3", | ||
"tslib": "2.4.0", | ||
"uuid": "8.3.2" | ||
"tslib": "2.4.0" | ||
}, | ||
@@ -54,2 +54,2 @@ "repository": { | ||
} | ||
} | ||
} |
@@ -344,4 +344,64 @@ [![sofa](https://user-images.githubusercontent.com/25294569/63839869-bfac8300-c988-11e9-978e-6b6c16c350de.gif)](https://www.sofa-api.com) | ||
OpenAPI (Swagger) with custom tags, summary and description | ||
```ts | ||
const openApi = OpenAPI({ | ||
schema, | ||
info: { | ||
title: 'Example API', | ||
version: '3.0.0', | ||
}, | ||
tags: [ | ||
{ | ||
name: 'Book', | ||
description: 'Book related operations', | ||
}, | ||
{ | ||
name: 'Author', | ||
description: 'Author related operations', | ||
}, | ||
], | ||
}); | ||
``` | ||
```ts | ||
@Resolver(Book) | ||
export class BookResolver { | ||
@Query(() => Book, { description: 'Get book by id' }) // custom summary tag | ||
getBookById(@Arg('id', () => Int) id: number) { | ||
return 'book'; | ||
} | ||
} | ||
``` | ||
```ts | ||
const routes: SofaConfig['routes'] = { | ||
'Query.getBookById': { | ||
method: 'POST', | ||
path: '/book/:id', | ||
tags: ['Book'], | ||
description: 'This is a custom detailed description for getBookById', | ||
}, | ||
} | ||
const createSofaMiddleware = ( | ||
schema: GraphQLSchema, | ||
openApi: ReturnType<typeof OpenAPI>, | ||
basePath = '' | ||
): ReturnType<typeof useSofa> => { | ||
return useSofa({ | ||
routes, | ||
basePath, | ||
schema, | ||
onRoute(info) { | ||
openApi.addRoute(info, { basePath }); | ||
}, | ||
}); | ||
}; | ||
// writes every recorder route | ||
openApi.save('./swagger.yml'); | ||
``` | ||
## License | ||
[MIT](https://github.com/Urigo/sofa/blob/master/LICENSE) © Uri Goldshtein |
@@ -8,2 +8,4 @@ import { GraphQLSchema, subscribe, execute } from 'graphql'; | ||
responseStatus?: number; | ||
tags?: string[]; | ||
description?: string; | ||
} | ||
@@ -10,0 +12,0 @@ export interface Route { |
@@ -9,2 +9,4 @@ import { DocumentNode } from 'graphql'; | ||
method: Method; | ||
tags?: string[]; | ||
description?: string; | ||
} | ||
@@ -11,0 +13,0 @@ export declare type OnRoute = (info: RouteInfo) => void; |
Sorry, the diff of this file is not supported yet
407
81057
18
1845
11
+ Addedopenapi-types@12.0.2
+ Addedopenapi-types@12.0.2(transitive)
- Removeduuid@8.3.2
- Removeduuid@8.3.2(transitive)