feat: v3 requests example working

This commit is contained in:
Rishabh Agarwal
2022-04-15 12:06:51 +05:30
committed by Andrew Bastin
parent 721a201e7a
commit bc2f81ff25
3 changed files with 170 additions and 5 deletions

View File

@@ -0,0 +1,62 @@
import { OpenAPIV3 } from "openapi-types"
import { pipe } from "fp-ts/function"
import * as A from "fp-ts/Array"
import * as O from "fp-ts/Option"
type SchemaType = OpenAPIV3.ArraySchemaObjectType | OpenAPIV3.NonArraySchemaObjectType
type PrimitiveSchemaType = Exclude<SchemaType, "array" | "object">
type PrimitiveRequestBodyExampleType = string | number | boolean | null
type RequestBodyExampleType = PrimitiveRequestBodyExampleType | Array<RequestBodyExampleType> | { [name: string]: RequestBodyExampleType }
const isSchemaTypePrimitive = (schemaType: SchemaType) : schemaType is PrimitiveSchemaType => !["array", "object"].includes(schemaType)
const getPrimitiveTypePlaceholder = (primitiveType: PrimitiveSchemaType) : PrimitiveRequestBodyExampleType => {
switch(primitiveType) {
case "number": return 0.0
case "integer": return 0
case "string": return "string"
case "boolean": return true
}
}
// Use carefully, call only when type is primitive
// TODO(agarwal): Use Enum values, if any
const generatePrimitiveRequestBodyExample = (schemaObject: OpenAPIV3.NonArraySchemaObject) : RequestBodyExampleType =>
getPrimitiveTypePlaceholder(schemaObject.type as PrimitiveSchemaType)
// Use carefully, call only when type is object
const generateObjectRequestBodyExample = (schemaObject: OpenAPIV3.NonArraySchemaObject) : RequestBodyExampleType =>
pipe(
schemaObject.properties,
O.fromNullable,
O.map((properties) => Object.entries(properties) as [string, OpenAPIV3.SchemaObject][]),
O.getOrElseW(() => [] as [string, OpenAPIV3.SchemaObject][]),
A.reduce(
{} as {[name: string]: RequestBodyExampleType},
(aggregatedExample, property) => {
aggregatedExample[property[0]] = generateRequestBodyExampleFromSchemaObject(property[1])
return aggregatedExample
}
)
)
const generateArrayRequestBodyExample = (schemaObject: OpenAPIV3.ArraySchemaObject) : RequestBodyExampleType =>
Array.of(generateRequestBodyExampleFromSchemaObject(schemaObject.items as OpenAPIV3.SchemaObject))
const generateRequestBodyExampleFromSchemaObject = (schemaObject: OpenAPIV3.SchemaObject) : RequestBodyExampleType => {
// TODO: Handle schema objects with oneof or anyof
if(schemaObject.example) return schemaObject.example as RequestBodyExampleType
if(!schemaObject.type) return ""
if(isSchemaTypePrimitive(schemaObject.type)) return generatePrimitiveRequestBodyExample(schemaObject as OpenAPIV3.NonArraySchemaObject)
if(schemaObject.type === "object") return generateObjectRequestBodyExample(schemaObject as OpenAPIV3.NonArraySchemaObject)
return generateArrayRequestBodyExample(schemaObject as OpenAPIV3.ArraySchemaObject)
}
export const generateRequestBodyExampleFromMediaObject = (mediaObject: OpenAPIV3.MediaTypeObject) : RequestBodyExampleType => {
if(mediaObject.example) return mediaObject.example as RequestBodyExampleType
if(mediaObject.examples) return mediaObject.examples[0] as RequestBodyExampleType
return mediaObject.schema ? generateRequestBodyExampleFromSchemaObject(mediaObject.schema as OpenAPIV3.SchemaObject) : ""
}

View File

@@ -0,0 +1,84 @@
import { OpenAPIV3_1 as OpenAPIV31 } from "openapi-types"
import { pipe } from "fp-ts/function"
import * as O from "fp-ts/Option"
import * as A from "fp-ts/Array"
type MixedArraySchemaType = (OpenAPIV31.ArraySchemaObjectType | OpenAPIV31.NonArraySchemaObjectType)[]
type SchemaType = OpenAPIV31.ArraySchemaObjectType | OpenAPIV31.NonArraySchemaObjectType | MixedArraySchemaType
type PrimitiveSchemaType = Exclude<OpenAPIV31.NonArraySchemaObjectType, "object">
type PrimitiveRequestBodyExampleType = string | number | boolean | null
type RequestBodyExampleType = PrimitiveRequestBodyExampleType | Array<RequestBodyExampleType> | { [name: string]: RequestBodyExampleType }
const isSchemaTypePrimitive = (schemaType: SchemaType) : schemaType is PrimitiveSchemaType => !Array.isArray(schemaType) && !["array", "object"].includes(schemaType)
const getPrimitiveTypePlaceholder = (primitiveType: PrimitiveSchemaType) : PrimitiveRequestBodyExampleType => {
switch(primitiveType) {
case "number": return 0.0
case "integer": return 0
case "string": return "string"
case "boolean": return true
}
return null
}
// Use carefully, the schema type should necessarily be primitive
// TODO(agarwal): Use Enum values, if any
const generatePrimitiveRequestBodyExample = (schemaObject: OpenAPIV31.NonArraySchemaObject) : RequestBodyExampleType =>
getPrimitiveTypePlaceholder(schemaObject.type as PrimitiveSchemaType)
// Use carefully, the schema type should necessarily be object
const generateObjectRequestBodyExample = (schemaObject: OpenAPIV31.NonArraySchemaObject) : RequestBodyExampleType =>
pipe(
schemaObject.properties,
O.fromNullable,
O.map((properties) => Object.entries(properties) as [string, OpenAPIV31.SchemaObject][]),
O.getOrElseW(() => [] as [string, OpenAPIV31.SchemaObject][]),
A.reduce(
{} as {[name: string]: RequestBodyExampleType},
(aggregatedExample, property) => {
aggregatedExample[property[0]] = generateRequestBodyExampleFromSchemaObject(property[1])
return aggregatedExample
}
)
)
// Use carefully, the schema type should necessarily be mixed array
const generateMixedArrayRequestBodyEcample = (schemaObject: OpenAPIV31.SchemaObject) : RequestBodyExampleType =>
pipe(
schemaObject,
schemaObject => schemaObject.type as MixedArraySchemaType,
A.reduce(
[] as Array<RequestBodyExampleType>,
(aggregatedExample, itemType) => {
// TODO: Figure out how to include non-primitive types as well
if(isSchemaTypePrimitive(itemType)) {
aggregatedExample.push(getPrimitiveTypePlaceholder(itemType))
}
return aggregatedExample
}
)
)
const generateArrayRequestBodyExample = (schemaObject: OpenAPIV31.ArraySchemaObject) : RequestBodyExampleType =>
Array.of(generateRequestBodyExampleFromSchemaObject(schemaObject.items as OpenAPIV31.SchemaObject))
const generateRequestBodyExampleFromSchemaObject = (schemaObject: OpenAPIV31.SchemaObject) : RequestBodyExampleType => {
// TODO: Handle schema objects with oneof or anyof
if(schemaObject.example) return schemaObject.example as RequestBodyExampleType
if(schemaObject.examples) return schemaObject.examples[0] as RequestBodyExampleType
if(!schemaObject.type) return ""
if(isSchemaTypePrimitive(schemaObject.type)) return generatePrimitiveRequestBodyExample(schemaObject as OpenAPIV31.NonArraySchemaObject)
if(schemaObject.type === "object") return generateObjectRequestBodyExample(schemaObject)
if(schemaObject.type === "array") return generateArrayRequestBodyExample(schemaObject)
return generateMixedArrayRequestBodyEcample(schemaObject)
}
export const generateRequestBodyExampleFromMediaObject = (mediaObject: OpenAPIV31.MediaTypeObject) : RequestBodyExampleType => {
if(mediaObject.example) return mediaObject.example as RequestBodyExampleType
if(mediaObject.examples) return mediaObject.examples[0] as RequestBodyExampleType
return mediaObject.schema ? generateRequestBodyExampleFromSchemaObject(mediaObject.schema) : ""
}

View File

@@ -24,8 +24,10 @@ import * as S from "fp-ts/string"
import * as O from "fp-ts/Option"
import * as TE from "fp-ts/TaskEither"
import * as RA from "fp-ts/ReadonlyArray"
import { step } from "../steps"
import { defineImporter, IMPORTER_INVALID_FILE_FORMAT } from "."
import { step } from "../../steps"
import { defineImporter, IMPORTER_INVALID_FILE_FORMAT } from "../"
import { generateRequestBodyExampleFromMediaObject as generateExampleV31 } from "./exampleV31"
import { generateRequestBodyExampleFromMediaObject as generateExampleV3 } from "./exampleV3"
export const OPENAPI_DEREF_ERROR = "openapi/deref_error" as const
@@ -366,7 +368,8 @@ const generateRequestBodyExampleFromOpenAPIV2Body = (
)
const parseOpenAPIV3Body = (
op: OpenAPIV3.OperationObject | OpenAPIV31.OperationObject
op: OpenAPIV3.OperationObject | OpenAPIV31.OperationObject,
isV31Request: boolean
): HoppRESTReqBody => {
const objs = Object.entries(
(
@@ -385,11 +388,19 @@ const parseOpenAPIV3Body = (
OpenAPIV3.MediaTypeObject | OpenAPIV31.MediaTypeObject
] = objs[0]
const exampleBody = JSON.stringify(
isV31Request
? generateExampleV31(media as OpenAPIV31.MediaTypeObject)
: generateExampleV3(media as OpenAPIV3.MediaTypeObject),
null,
"\t"
)
return contentType in knownContentTypes
? contentType === "multipart/form-data" ||
contentType === "application/x-www-form-urlencoded"
? parseOpenAPIV3BodyFormData(contentType, media)
: { contentType: contentType as any, body: "" }
: { contentType: contentType as any, body: exampleBody }
: { contentType: null, body: null }
}
@@ -401,12 +412,20 @@ const isOpenAPIV3Operation = (
typeof doc.openapi === "string" &&
doc.openapi.startsWith("3.")
const isOpenAPIV31Operation = (
doc: OpenAPI.Document,
op: OpenAPIOperationType
): op is OpenAPIV31.OperationObject =>
objectHasProperty(doc, "openapi") &&
typeof doc.openapi === "string" &&
doc.openapi.startsWith("3.1")
const parseOpenAPIBody = (
doc: OpenAPI.Document,
op: OpenAPIOperationType
): HoppRESTReqBody =>
isOpenAPIV3Operation(doc, op)
? parseOpenAPIV3Body(op)
? parseOpenAPIV3Body(op, isOpenAPIV31Operation(doc, op))
: parseOpenAPIV2Body(op)
const resolveOpenAPIV3SecurityObj = (