Skip to content

Commit

Permalink
Switch oas-validator to @stoplightio/spectra
Browse files Browse the repository at this point in the history
Most tests are passing but some are still failing.
  • Loading branch information
FallingSnow committed Jul 1, 2021
1 parent 3e2eb50 commit 4c4e92e
Show file tree
Hide file tree
Showing 13 changed files with 133 additions and 93 deletions.
8 changes: 3 additions & 5 deletions packages/openapi-to-graphql/lib/index.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion packages/openapi-to-graphql/lib/index.js.map

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion packages/openapi-to-graphql/lib/oas_3_tools.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ export declare function methodToHttpMethod(method: string): HTTP_METHODS;
* Resolves on a validated OAS 3 for the given spec (OAS 2 or OAS 3), or rejects
* if errors occur.
*/
export declare function getValidOAS3(spec: Oas2 | Oas3, oasValidatorOptions: object, swagger2OpenAPIOptions: object): Promise<Oas3>;
export declare function getValidOAS3(spec: Oas2 | Oas3, swagger2OpenAPIOptions: object): Promise<Oas3>;
/**
* Counts the number of operations in an OAS.
*/
Expand Down
19 changes: 15 additions & 4 deletions packages/openapi-to-graphql/lib/oas_3_tools.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion packages/openapi-to-graphql/lib/oas_3_tools.js.map

Large diffs are not rendered by default.

8 changes: 0 additions & 8 deletions packages/openapi-to-graphql/lib/types/options.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -240,14 +240,6 @@ export declare type InternalOptions<TSource, TContext, TArgs> = {
* header.
*/
sendOAuthTokenInQuery: boolean;
/**
* We use the oas-validator library to validate Swaggers/OASs.
*
* We expose the options so that users can have more control over validation.
*
* Based on: https://github.com/Mermade/oas-kit/blob/master/docs/options.md
*/
oasValidatorOptions: object;
/**
* We use the swagger2graphql library to translate Swaggers to OASs.
*
Expand Down
2 changes: 1 addition & 1 deletion packages/openapi-to-graphql/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -66,14 +66,14 @@
"testRegex": "/test/.*\\.test\\.(ts|tsx|js)$"
},
"dependencies": {
"@stoplight/spectral": "^5.9.1",
"debug": "^4.2.0",
"deep-equal": "^2.0.1",
"form-urlencoded": "^4.2.1",
"graphql-subscriptions": "^1.1.0",
"graphql-type-json": "^0.3.2",
"json-ptr": "^1.3.1",
"jsonpath-plus": "^4.0.0",
"oas-validator": "^5.0.2",
"pluralize": "^8.0.0",
"request": "^2.88.0",
"swagger2openapi": "^7.0.2"
Expand Down
10 changes: 1 addition & 9 deletions packages/openapi-to-graphql/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,6 @@ const DEFAULT_OPTIONS: InternalOptions<any, any, any> = {
sendOAuthTokenInQuery: false,

// Validation options
oasValidatorOptions: {},
swagger2OpenAPIOptions: {},

// Logging options
Expand Down Expand Up @@ -144,7 +143,6 @@ export function createGraphQLSchema<TSource, TContext, TArgs>(
spec.map((ele) => {
return Oas3Tools.getValidOAS3(
ele,
internalOptions.oasValidatorOptions,
internalOptions.swagger2OpenAPIOptions
)
})
Expand All @@ -161,11 +159,7 @@ export function createGraphQLSchema<TSource, TContext, TArgs>(
* If the spec is OAS 2.0, attempt to translate it into 3, then try to
* translate the spec into a GraphQL schema
*/
Oas3Tools.getValidOAS3(
spec,
internalOptions.oasValidatorOptions,
internalOptions.swagger2OpenAPIOptions
)
Oas3Tools.getValidOAS3(spec, internalOptions.swagger2OpenAPIOptions)
.then((oas) => {
resolve(translateOpenAPIToGraphQL([oas], internalOptions))
})
Expand Down Expand Up @@ -212,7 +206,6 @@ function translateOpenAPIToGraphQL<TSource, TContext, TArgs>(
sendOAuthTokenInQuery,

// Validation options
oasValidatorOptions,
swagger2OpenAPIOptions,

// Logging options
Expand Down Expand Up @@ -251,7 +244,6 @@ function translateOpenAPIToGraphQL<TSource, TContext, TArgs>(
sendOAuthTokenInQuery,

// Validation options
oasValidatorOptions,
swagger2OpenAPIOptions,

// Logging options
Expand Down
119 changes: 70 additions & 49 deletions packages/openapi-to-graphql/src/oas_3_tools.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,11 @@ import { InternalOptions } from './types/options'

// Imports:
import * as Swagger2OpenAPI from 'swagger2openapi'
import * as OASValidator from 'oas-validator'
import {
Spectral as OASValidator,
isOpenApiv2,
isOpenApiv3
} from '@stoplight/spectral'
import debug from 'debug'
import { handleWarning, MitigationTypes } from './utils'
import * as jsonptr from 'json-ptr'
Expand Down Expand Up @@ -131,7 +135,6 @@ export function methodToHttpMethod(method: string): HTTP_METHODS {
*/
export function getValidOAS3(
spec: Oas2 | Oas3,
oasValidatorOptions: object,
swagger2OpenAPIOptions: object
): Promise<Oas3> {
return new Promise((resolve, reject) => {
Expand Down Expand Up @@ -161,8 +164,25 @@ export function getValidOAS3(
) {
preprocessingLog(`Received OpenAPI Specification - going to validate...`)

OASValidator.validate(spec, oasValidatorOptions)
.then(() => resolve(spec as Oas3))
const validator = new OASValidator()
validator.registerFormat('oas3', isOpenApiv3)

validator
.loadRuleset('spectral:oas')
.then(() => validator.run(spec))
.then((results) => {
for (const result of results) {
if (result.severity < 1) {
return reject(
`Invalid OpenAPI Specification '${
(spec as Oas3).info.title
}'. [${result.path.join('.')}] ${result.message}`
)
}
}

resolve(spec as Oas3)
})
.catch((error) =>
reject(
`Could not validate OpenAPI Specification '${
Expand Down Expand Up @@ -419,7 +439,7 @@ export function getSchemaTargetGraphQLType<TSource, TContext, TArgs>(
oas: Oas3
): TargetGraphQLType | null {
let schema: SchemaObject
if ("$ref" in schemaOrRef && typeof schemaOrRef.$ref === 'string') {
if ('$ref' in schemaOrRef && typeof schemaOrRef.$ref === 'string') {
schema = resolveRef(schemaOrRef.$ref, oas)
} else {
schema = schemaOrRef as SchemaObject
Expand Down Expand Up @@ -529,7 +549,10 @@ function hasNestedOneOfUsage(schema: SchemaObject, oas: Oas3): boolean {
Array.isArray(schema.oneOf) &&
schema.oneOf.some((memberSchemaOrRef) => {
let memberSchema: SchemaObject
if ("$ref" in memberSchemaOrRef && typeof memberSchemaOrRef.$ref === 'string') {
if (
'$ref' in memberSchemaOrRef &&
typeof memberSchemaOrRef.$ref === 'string'
) {
memberSchema = resolveRef(memberSchemaOrRef.$ref, oas)
} else {
memberSchema = memberSchemaOrRef as SchemaObject
Expand Down Expand Up @@ -560,7 +583,10 @@ function hasNestedAnyOfUsage(schema: SchemaObject, oas: Oas3): boolean {
schema.anyOf.some((memberSchemaOrRef) => {
let memberSchema: SchemaObject

if ("$ref" in memberSchemaOrRef && typeof memberSchemaOrRef.$ref === 'string') {
if (
'$ref' in memberSchemaOrRef &&
typeof memberSchemaOrRef.$ref === 'string'
) {
memberSchema = resolveRef(memberSchemaOrRef.$ref, oas)
} else {
memberSchema = memberSchemaOrRef as SchemaObject
Expand Down Expand Up @@ -809,11 +835,11 @@ export function getRequestSchemaAndNames(
requestBodyObjectOrRef !== null
) {
// Resolve reference if applicable. Make sure we have a RequestBodyObject:
if ("$ref" in requestBodyObjectOrRef && typeof requestBodyObjectOrRef.$ref === 'string') {
requestBodyObject = resolveRef(
requestBodyObjectOrRef.$ref,
oas
)
if (
'$ref' in requestBodyObjectOrRef &&
typeof requestBodyObjectOrRef.$ref === 'string'
) {
requestBodyObject = resolveRef(requestBodyObjectOrRef.$ref, oas)
} else {
requestBodyObject = requestBodyObjectOrRef as RequestBodyObject
}
Expand Down Expand Up @@ -859,14 +885,11 @@ export function getRequestSchemaAndNames(
) {
// Resolve payload schema reference if applicable
if (
"$ref" in payloadSchemaOrRef &&
'$ref' in payloadSchemaOrRef &&
typeof payloadSchemaOrRef.$ref === 'string'
) {
fromRef = payloadSchemaOrRef.$ref.split('/').pop()
payloadSchema = resolveRef(
payloadSchemaOrRef.$ref,
oas
)
payloadSchema = resolveRef(payloadSchemaOrRef.$ref, oas)
} else {
payloadSchema = payloadSchemaOrRef as SchemaObject
}
Expand Down Expand Up @@ -946,11 +969,11 @@ export function getResponseSchemaAndNames<TSource, TContext, TArgs>(
// Get response object
const responseObjectOrRef = operation?.responses?.[statusCode]
if (typeof responseObjectOrRef === 'object' && responseObjectOrRef !== null) {
if ("$ref" in responseObjectOrRef && typeof responseObjectOrRef.$ref === 'string') {
responseObject = resolveRef(
responseObjectOrRef.$ref,
oas
)
if (
'$ref' in responseObjectOrRef &&
typeof responseObjectOrRef.$ref === 'string'
) {
responseObject = resolveRef(responseObjectOrRef.$ref, oas)
} else {
responseObject = responseObjectOrRef as ResponseObject
}
Expand Down Expand Up @@ -984,14 +1007,11 @@ export function getResponseSchemaAndNames<TSource, TContext, TArgs>(
responseObject?.content?.[responseContentType]?.schema
// Resolve response schema reference if applicable
if (
"$ref" in responseSchemaOrRef &&
'$ref' in responseSchemaOrRef &&
typeof responseSchemaOrRef.$ref === 'string'
) {
fromRef = responseSchemaOrRef.$ref.split('/').pop()
responseSchema = resolveRef(
responseSchemaOrRef.$ref,
oas
)
responseSchema = resolveRef(responseSchemaOrRef.$ref, oas)
} else {
responseSchema = responseSchemaOrRef as SchemaObject
}
Expand Down Expand Up @@ -1121,11 +1141,11 @@ export function getLinks<TSource, TContext, TArgs>(
const responseObjectOrRef = responses[statusCode]

let response: ResponseObject
if ("$ref" in responseObjectOrRef && typeof responseObjectOrRef.$ref === 'string') {
response = resolveRef(
responseObjectOrRef.$ref,
oas
)
if (
'$ref' in responseObjectOrRef &&
typeof responseObjectOrRef.$ref === 'string'
) {
response = resolveRef(responseObjectOrRef.$ref, oas)
} else {
response = responseObjectOrRef as ResponseObject
}
Expand All @@ -1136,7 +1156,10 @@ export function getLinks<TSource, TContext, TArgs>(
const linkObjectOrRef = epLinks[linkKey]

let link: LinkObject
if ("$ref" in linkObjectOrRef && typeof linkObjectOrRef.$ref === 'string') {
if (
'$ref' in linkObjectOrRef &&
typeof linkObjectOrRef.$ref === 'string'
) {
link = resolveRef(linkObjectOrRef.$ref, oas)
} else {
link = linkObjectOrRef as LinkObject
Expand Down Expand Up @@ -1173,17 +1196,15 @@ export function getParameters(
// First, consider parameters in Path Item Object:
const pathParams = pathItem.parameters
if (Array.isArray(pathParams)) {
const pathItemParameters: ParameterObject[] = pathParams.map(
(p) => {
if ("$ref" in p && typeof p.$ref === 'string') {
// Here we know we have a parameter object:
return resolveRef(p.$ref, oas) as ParameterObject
} else {
// Here we know we have a parameter object:
return p as ParameterObject
}
const pathItemParameters: ParameterObject[] = pathParams.map((p) => {
if ('$ref' in p && typeof p.$ref === 'string') {
// Here we know we have a parameter object:
return resolveRef(p.$ref, oas) as ParameterObject
} else {
// Here we know we have a parameter object:
return p as ParameterObject
}
)
})
parameters = parameters.concat(pathItemParameters)
}

Expand All @@ -1192,7 +1213,7 @@ export function getParameters(
if (Array.isArray(opObjectParameters)) {
const operationParameters: ParameterObject[] = opObjectParameters.map(
(p) => {
if ("$ref" in p && typeof p.$ref === 'string') {
if ('$ref' in p && typeof p.$ref === 'string') {
// Here we know we have a parameter object:
return resolveRef(p.$ref, oas)
} else {
Expand Down Expand Up @@ -1262,12 +1283,12 @@ export function getSecuritySchemes(
const securitySchemeOrRef = oas.components.securitySchemes[schemeKey]

// Ensure we have actual SecuritySchemeObject:
if ("$ref" in securitySchemeOrRef && typeof securitySchemeOrRef.$ref === 'string') {
if (
'$ref' in securitySchemeOrRef &&
typeof securitySchemeOrRef.$ref === 'string'
) {
// Result of resolution will be SecuritySchemeObject:
securitySchemes[schemeKey] = resolveRef(
securitySchemeOrRef.$ref,
oas
)
securitySchemes[schemeKey] = resolveRef(securitySchemeOrRef.$ref, oas)
} else {
// We already have a SecuritySchemeObject:
securitySchemes[schemeKey] = securitySchemeOrRef as SecuritySchemeObject
Expand Down
Loading

0 comments on commit 4c4e92e

Please sign in to comment.