Skip to content
This repository has been archived by the owner on Oct 11, 2023. It is now read-only.

Commit

Permalink
Merge pull request #331 from daviwil/enable-multipart-requests
Browse files Browse the repository at this point in the history
Convert multipart/form-data requests to HttpMultipartRequest
  • Loading branch information
daviwil authored Aug 7, 2020
2 parents 9968e54 + e1f8662 commit 3e46e72
Show file tree
Hide file tree
Showing 19 changed files with 2,457 additions and 40 deletions.
104 changes: 76 additions & 28 deletions modelerfour/modeler/modelerfour.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Model as oai3, Dereferenced, dereference, Refable, JsonType, IntegerFormat, StringFormat, NumberFormat, MediaType, filterOutXDash } from '@azure-tools/openapi';
import * as OpenAPI from '@azure-tools/openapi';
import { items, values, Dictionary, length, keys } from '@azure-tools/linq';
import { HttpMethod, HttpModel, CodeModel, Operation, SetType, HttpRequest, BooleanSchema, Schema, NumberSchema, ArraySchema, Parameter, ChoiceSchema, StringSchema, ObjectSchema, ByteArraySchema, CharSchema, DateSchema, DateTimeSchema, DurationSchema, UuidSchema, UriSchema, CredentialSchema, ODataQuerySchema, UnixTimeSchema, SchemaType, SchemaContext, OrSchema, XorSchema, DictionarySchema, ParameterLocation, SerializationStyle, ImplementationLocation, Property, ComplexSchema, HttpWithBodyRequest, HttpBinaryRequest, HttpParameter, Response, HttpResponse, HttpBinaryResponse, SchemaResponse, SchemaUsage, SealedChoiceSchema, ExternalDocumentation, BinaryResponse, BinarySchema, Discriminator, Relations, AnySchema, ConstantSchema, ConstantValue, HttpHeader, ChoiceValue, Language, Request, OperationGroup, TimeSchema } from '@azure-tools/codemodel';
import { HttpMethod, HttpModel, CodeModel, Operation, SetType, HttpRequest, BooleanSchema, Schema, NumberSchema, ArraySchema, Parameter, ChoiceSchema, StringSchema, ObjectSchema, ByteArraySchema, CharSchema, DateSchema, DateTimeSchema, DurationSchema, UuidSchema, UriSchema, CredentialSchema, ODataQuerySchema, UnixTimeSchema, SchemaType, SchemaContext, OrSchema, XorSchema, DictionarySchema, ParameterLocation, SerializationStyle, ImplementationLocation, Property, ComplexSchema, HttpWithBodyRequest, HttpBinaryRequest, HttpParameter, Response, HttpResponse, HttpBinaryResponse, SchemaResponse, SchemaUsage, SealedChoiceSchema, ExternalDocumentation, BinaryResponse, BinarySchema, Discriminator, Relations, AnySchema, ConstantSchema, ConstantValue, HttpHeader, ChoiceValue, Language, Request, OperationGroup, TimeSchema, HttpMultipartRequest } from '@azure-tools/codemodel';
import { Session, Channel } from '@azure-tools/autorest-extension-base';
import { Interpretations, XMSEnum } from './interpretations';
import { fail, minimum, pascalCase, knownMediaType, KnownMediaType } from '@azure-tools/codegen';
Expand Down Expand Up @@ -1121,10 +1121,17 @@ export class ModelerFour {
throw new Error('NO BODY DUDE.');

}
const http = new HttpWithBodyRequest({
knownMediaType: kmt,
mediaTypes: kmtObject.map(each => each.mediaType),
});

const http: HttpWithBodyRequest =
kmt === KnownMediaType.Multipart
? new HttpMultipartRequest({
knownMediaType: kmt,
mediaTypes: ['multipart/form-data']
})
: new HttpWithBodyRequest({
knownMediaType: kmt,
mediaTypes: kmtObject.map(each => each.mediaType),
});

// create the request object
const httpRequest = new Request({
Expand Down Expand Up @@ -1152,31 +1159,72 @@ export class ModelerFour {
}

const requestSchema = values(kmtObject).first(each => !!each.schema.instance)?.schema;
const pSchema = this.processSchema(requestSchema?.name || 'requestBody', requestSchema?.instance || <OpenAPI.Schema>{})

// Track the usage of this schema as an input with media type
this.trackSchemaUsage(pSchema, { usage: [SchemaContext.Input], serializationFormats: [kmt] });
if (kmt === KnownMediaType.Multipart) {
if (!requestSchema || !requestSchema.instance) {
throw new Error('Cannot process a multipart/form-data body without a schema.');
}

httpRequest.addParameter(new Parameter(
body.instance?.['x-ms-requestBody-name'] ?? 'body',
this.interpret.getDescription('', body?.instance || {}),
pSchema, {
extensions: this.interpret.getExtensionProperties(body.instance),
required: !!body.instance.required,
nullable: requestSchema?.instance?.nullable,
protocol: {
http: new HttpParameter(ParameterLocation.Body, {
style: <SerializationStyle><any>kmt,
})
},
implementation: ImplementationLocation.Method,
clientDefaultValue: this.interpret.getClientDefault(body?.instance || {}, {})
}));
return operation.addRequest(httpRequest);
}
// Convert schema properties into parameters. OpenAPI 3 requires that
// multipart/form-data parameters be modeled as object schema properties
// but we must turn them back into operation parameters so that code
// generators will generate them as method parameters.
for (const { key: propertyName, value: propertyDeclaration } of items(requestSchema.instance.properties)) {
const property = this.resolve(propertyDeclaration);
this.use(<OpenAPI.Refable<OpenAPI.Schema>>propertyDeclaration, (pSchemaName, pSchema) => {
const pType = this.processSchema(pSchemaName || `type·for·${propertyName}`, pSchema);
httpRequest.addParameter(new Parameter(
propertyName,
propertyDeclaration.description || this.interpret.getDescription(pType.language.default.description, property),
pType, {
schema: pType,
required:
requestSchema.instance?.required
&& requestSchema.instance?.required.indexOf(propertyName) > -1 ? true : undefined,
implementation: ImplementationLocation.Method,
extensions: this.interpret.getExtensionProperties(propertyDeclaration),
nullable: propertyDeclaration.nullable || pSchema.nullable,
protocol: {
http: new HttpParameter(ParameterLocation.Body)
},
language: {
default: {
name: propertyName,
description: propertyDeclaration.description,
serializedName: propertyName
}
},
clientDefaultValue: this.interpret.getClientDefault(propertyDeclaration, pSchema)
}));

// Track the usage of this schema as an input with media type
this.trackSchemaUsage(pType, { usage: [SchemaContext.Input], serializationFormats: [kmt] });
});
}
} else {
const pSchema = this.processSchema(requestSchema?.name || 'requestBody', requestSchema?.instance || <OpenAPI.Schema>{})

// Track the usage of this schema as an input with media type
this.trackSchemaUsage(pSchema, { usage: [SchemaContext.Input], serializationFormats: [kmt] });

httpRequest.addParameter(new Parameter(
body.instance?.['x-ms-requestBody-name'] ?? 'body',
this.interpret.getDescription('', body?.instance || {}),
pSchema, {
extensions: this.interpret.getExtensionProperties(body.instance),
required: !!body.instance.required,
nullable: requestSchema?.instance?.nullable,
protocol: {
http: new HttpParameter(ParameterLocation.Body, {
style: <SerializationStyle><any>kmt,
})
},
implementation: ImplementationLocation.Method,
clientDefaultValue: this.interpret.getClientDefault(body?.instance || {}, {})
}));
}

processMultipart(kmtMulti: Array<{ mediaType: string; schema: Dereferenced<OpenAPI.Schema | undefined>; }>, operation: Operation, body: Dereferenced<OpenAPI.RequestBody | undefined>) {
throw new Error('Multipart forms not implemented yet..');
return operation.addRequest(httpRequest);
}

processOperation(httpOperation: OpenAPI.HttpOperation, method: string, path: string, pathItem: OpenAPI.PathItem) {
Expand Down Expand Up @@ -1665,7 +1713,7 @@ export class ModelerFour {
throw new Error(`Requests with 'multipart/formdata' can not be combined in a single operation with other media types ${keys(requestBody.instance.content).toArray()} `);
}
// create multipart form upload for this.
this.processMultipart(kmtMultipart, operation, requestBody);
this.processSerializedObject(KnownMediaType.Multipart, kmtMultipart, operation, requestBody);
}
// ensure the protocol information is set on the requests
for (const request of values(operation.requests)) {
Expand Down
29 changes: 29 additions & 0 deletions modelerfour/test/scenarios/blob-storage/flattened.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -602,6 +602,7 @@ schemas: !<!Schemas>
xml:
name: Start
attribute: false
text: false
wrapped: false
language: !<!Languages>
default:
Expand All @@ -615,6 +616,7 @@ schemas: !<!Schemas>
xml:
name: End
attribute: false
text: false
wrapped: false
language: !<!Languages>
default:
Expand Down Expand Up @@ -975,6 +977,7 @@ schemas: !<!Schemas>
serialization:
xml:
attribute: true
text: false
wrapped: false
language: !<!Languages>
default:
Expand Down Expand Up @@ -1954,6 +1957,7 @@ schemas: !<!Schemas>
serialization:
xml:
attribute: true
text: false
wrapped: false
language: !<!Languages>
default:
Expand All @@ -1968,6 +1972,7 @@ schemas: !<!Schemas>
serialization:
xml:
attribute: true
text: false
wrapped: false
language: !<!Languages>
default:
Expand Down Expand Up @@ -2153,6 +2158,7 @@ schemas: !<!Schemas>
serialization:
xml:
attribute: true
text: false
wrapped: false
language: !<!Languages>
default:
Expand Down Expand Up @@ -2221,6 +2227,7 @@ schemas: !<!Schemas>
serialization:
xml:
attribute: true
text: false
wrapped: false
language: !<!Languages>
default:
Expand All @@ -2235,6 +2242,7 @@ schemas: !<!Schemas>
serialization:
xml:
attribute: true
text: false
wrapped: false
language: !<!Languages>
default:
Expand Down Expand Up @@ -4839,6 +4847,7 @@ schemas: !<!Schemas>
xml:
name: Committed
attribute: false
text: false
wrapped: false
language: !<!Languages>
default:
Expand All @@ -4854,6 +4863,7 @@ schemas: !<!Schemas>
xml:
name: Uncommitted
attribute: false
text: false
wrapped: false
language: !<!Languages>
default:
Expand All @@ -4869,6 +4879,7 @@ schemas: !<!Schemas>
xml:
name: Latest
attribute: false
text: false
wrapped: false
language: !<!Languages>
default:
Expand Down Expand Up @@ -9546,6 +9557,7 @@ schemas: !<!Schemas>
serialization:
xml:
attribute: false
text: false
wrapped: true
language: !<!Languages>
default:
Expand Down Expand Up @@ -9897,6 +9909,7 @@ schemas: !<!Schemas>
xml:
name: Container
attribute: false
text: false
wrapped: false
serializationFormats:
- xml
Expand All @@ -9912,6 +9925,7 @@ schemas: !<!Schemas>
xml:
name: Containers
attribute: false
text: false
wrapped: true
language: !<!Languages>
default:
Expand All @@ -9938,6 +9952,7 @@ schemas: !<!Schemas>
xml:
name: EnumerationResults
attribute: false
text: false
wrapped: false
serializationFormats:
- xml
Expand Down Expand Up @@ -10135,6 +10150,7 @@ schemas: !<!Schemas>
xml:
name: SignedIdentifier
attribute: false
text: false
wrapped: false
serializationFormats:
- xml
Expand Down Expand Up @@ -10535,6 +10551,7 @@ schemas: !<!Schemas>
xml:
name: Properties
attribute: false
text: false
wrapped: false
serializationFormats:
- xml
Expand Down Expand Up @@ -10577,6 +10594,7 @@ schemas: !<!Schemas>
xml:
name: Metadata
attribute: false
text: false
wrapped: false
serializationFormats:
- xml
Expand All @@ -10599,6 +10617,7 @@ schemas: !<!Schemas>
xml:
name: Blob
attribute: false
text: false
wrapped: false
serializationFormats:
- xml
Expand Down Expand Up @@ -10626,6 +10645,7 @@ schemas: !<!Schemas>
xml:
name: Blobs
attribute: false
text: false
wrapped: false
serializationFormats:
- xml
Expand Down Expand Up @@ -10657,6 +10677,7 @@ schemas: !<!Schemas>
xml:
name: EnumerationResults
attribute: false
text: false
wrapped: false
serializationFormats:
- xml
Expand Down Expand Up @@ -10805,6 +10826,7 @@ schemas: !<!Schemas>
xml:
name: Blobs
attribute: false
text: false
wrapped: false
serializationFormats:
- xml
Expand Down Expand Up @@ -10836,6 +10858,7 @@ schemas: !<!Schemas>
xml:
name: EnumerationResults
attribute: false
text: false
wrapped: false
serializationFormats:
- xml
Expand Down Expand Up @@ -10969,6 +10992,7 @@ schemas: !<!Schemas>
xml:
name: BlockList
attribute: false
text: false
wrapped: false
serializationFormats:
- xml
Expand Down Expand Up @@ -11029,6 +11053,7 @@ schemas: !<!Schemas>
serialization:
xml:
attribute: false
text: false
wrapped: true
language: !<!Languages>
default:
Expand All @@ -11051,6 +11076,7 @@ schemas: !<!Schemas>
serialization:
xml:
attribute: false
text: false
wrapped: true
language: !<!Languages>
default:
Expand Down Expand Up @@ -11114,6 +11140,7 @@ schemas: !<!Schemas>
xml:
name: PageRange
attribute: false
text: false
wrapped: false
serializationFormats:
- xml
Expand Down Expand Up @@ -11170,6 +11197,7 @@ schemas: !<!Schemas>
xml:
name: ClearRange
attribute: false
text: false
wrapped: false
serializationFormats:
- xml
Expand Down Expand Up @@ -11217,6 +11245,7 @@ schemas: !<!Schemas>
xml:
name: SignedIdentifiers
attribute: false
text: false
wrapped: true
language: !<!Languages>
default:
Expand Down
Loading

0 comments on commit 3e46e72

Please sign in to comment.