feat: v3 requests example working
This commit is contained in:
committed by
Andrew Bastin
parent
721a201e7a
commit
bc2f81ff25
@@ -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) : ""
|
||||||
|
}
|
||||||
@@ -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) : ""
|
||||||
|
}
|
||||||
@@ -24,8 +24,10 @@ import * as S from "fp-ts/string"
|
|||||||
import * as O from "fp-ts/Option"
|
import * as O from "fp-ts/Option"
|
||||||
import * as TE from "fp-ts/TaskEither"
|
import * as TE from "fp-ts/TaskEither"
|
||||||
import * as RA from "fp-ts/ReadonlyArray"
|
import * as RA from "fp-ts/ReadonlyArray"
|
||||||
import { step } from "../steps"
|
import { step } from "../../steps"
|
||||||
import { defineImporter, IMPORTER_INVALID_FILE_FORMAT } from "."
|
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
|
export const OPENAPI_DEREF_ERROR = "openapi/deref_error" as const
|
||||||
|
|
||||||
@@ -366,7 +368,8 @@ const generateRequestBodyExampleFromOpenAPIV2Body = (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const parseOpenAPIV3Body = (
|
const parseOpenAPIV3Body = (
|
||||||
op: OpenAPIV3.OperationObject | OpenAPIV31.OperationObject
|
op: OpenAPIV3.OperationObject | OpenAPIV31.OperationObject,
|
||||||
|
isV31Request: boolean
|
||||||
): HoppRESTReqBody => {
|
): HoppRESTReqBody => {
|
||||||
const objs = Object.entries(
|
const objs = Object.entries(
|
||||||
(
|
(
|
||||||
@@ -385,11 +388,19 @@ const parseOpenAPIV3Body = (
|
|||||||
OpenAPIV3.MediaTypeObject | OpenAPIV31.MediaTypeObject
|
OpenAPIV3.MediaTypeObject | OpenAPIV31.MediaTypeObject
|
||||||
] = objs[0]
|
] = objs[0]
|
||||||
|
|
||||||
|
const exampleBody = JSON.stringify(
|
||||||
|
isV31Request
|
||||||
|
? generateExampleV31(media as OpenAPIV31.MediaTypeObject)
|
||||||
|
: generateExampleV3(media as OpenAPIV3.MediaTypeObject),
|
||||||
|
null,
|
||||||
|
"\t"
|
||||||
|
)
|
||||||
|
|
||||||
return contentType in knownContentTypes
|
return contentType in knownContentTypes
|
||||||
? contentType === "multipart/form-data" ||
|
? contentType === "multipart/form-data" ||
|
||||||
contentType === "application/x-www-form-urlencoded"
|
contentType === "application/x-www-form-urlencoded"
|
||||||
? parseOpenAPIV3BodyFormData(contentType, media)
|
? parseOpenAPIV3BodyFormData(contentType, media)
|
||||||
: { contentType: contentType as any, body: "" }
|
: { contentType: contentType as any, body: exampleBody }
|
||||||
: { contentType: null, body: null }
|
: { contentType: null, body: null }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -401,12 +412,20 @@ const isOpenAPIV3Operation = (
|
|||||||
typeof doc.openapi === "string" &&
|
typeof doc.openapi === "string" &&
|
||||||
doc.openapi.startsWith("3.")
|
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 = (
|
const parseOpenAPIBody = (
|
||||||
doc: OpenAPI.Document,
|
doc: OpenAPI.Document,
|
||||||
op: OpenAPIOperationType
|
op: OpenAPIOperationType
|
||||||
): HoppRESTReqBody =>
|
): HoppRESTReqBody =>
|
||||||
isOpenAPIV3Operation(doc, op)
|
isOpenAPIV3Operation(doc, op)
|
||||||
? parseOpenAPIV3Body(op)
|
? parseOpenAPIV3Body(op, isOpenAPIV31Operation(doc, op))
|
||||||
: parseOpenAPIV2Body(op)
|
: parseOpenAPIV2Body(op)
|
||||||
|
|
||||||
const resolveOpenAPIV3SecurityObj = (
|
const resolveOpenAPIV3SecurityObj = (
|
||||||
Reference in New Issue
Block a user