diff --git a/modelerfour/modeler/modelerfour.ts b/modelerfour/modeler/modelerfour.ts index 6809bc6..b7e939f 100644 --- a/modelerfour/modeler/modelerfour.ts +++ b/modelerfour/modeler/modelerfour.ts @@ -780,7 +780,7 @@ export class ModelerFour { return this.processChoiceSchema(name, schema); } - if (schema.type === 'file' || schema.format === 'file' || schema.format === 'binary') { + if (this.isSchemaBinary(schema)) { // handle inconsistency in file format handling. this.session.hint( `'The schema ${schema?.['x-ms-metadata']?.name || name} with 'type: ${schema.type}', format: ${schema.format}' will be treated as a binary blob for binary media types.`, @@ -1760,7 +1760,9 @@ export class ModelerFour { throw new Error(`Operation '${operationGroup.language.default.name}/${operation.language.default.name}' must have a media type.`); } } + const kmtBinary = groupedMediaTypes.get(KnownMediaType.Binary); + if (kmtBinary) { // handle binary this.processBinary(KnownMediaType.Binary, kmtBinary, operation, requestBody); @@ -1771,7 +1773,21 @@ export class ModelerFour { } const kmtJSON = groupedMediaTypes.get(KnownMediaType.Json); if (kmtJSON) { - this.processSerializedObject(KnownMediaType.Json, kmtJSON, operation, requestBody); + if ([...kmtJSON.values()].find((x) => x.schema.instance && this.isSchemaBinary(x.schema.instance))) { + this.processBinary( + KnownMediaType.Binary, + kmtJSON, + operation, + requestBody + ); + } else { + this.processSerializedObject( + KnownMediaType.Json, + kmtJSON, + operation, + requestBody + ); + } } const kmtXML = groupedMediaTypes.get(KnownMediaType.Xml); if (kmtXML && !kmtJSON) { @@ -1882,6 +1898,14 @@ export class ModelerFour { return this.codeModel; } + private isSchemaBinary(schema: OpenAPI.Schema) { + return ( + schema.type === "file" || + schema.format === "file" || + schema.format === "binary" + ); + } + private propagateSchemaUsage(schema: Schema): void { const processedSchemas = new Set(); diff --git a/modelerfour/test/scenarios/body-binary-json/flattened.yaml b/modelerfour/test/scenarios/body-binary-json/flattened.yaml new file mode 100644 index 0000000..39956de --- /dev/null +++ b/modelerfour/test/scenarios/body-binary-json/flattened.yaml @@ -0,0 +1,110 @@ +! +info: ! + description: Acceptance test for file with json content type. + title: 'Binary with content-type: application/json' +schemas: ! + strings: + - ! &ref_0 + type: string + language: ! + default: + name: string + description: simple string + protocol: ! {} + binaries: + - ! &ref_2 + type: binary + apiVersions: + - ! + version: 1.0.0 + language: ! + default: + name: binary + description: '' + protocol: ! {} +globalParameters: + - ! &ref_1 + schema: *ref_0 + clientDefaultValue: 'https://localhost' + implementation: Client + origin: 'modelerfour:synthesized/host' + required: true + extensions: + x-ms-skip-url-encoding: true + language: ! + default: + name: $host + description: server parameter + serializedName: $host + protocol: ! + http: ! + in: uri +operationGroups: + - ! + $key: Upload + operations: + - ! + apiVersions: + - ! + version: 1.0.0 + parameters: + - *ref_1 + requests: + - ! + parameters: + - ! &ref_3 + schema: *ref_2 + implementation: Method + required: true + language: ! + default: + name: fileParam + description: Foo bar + protocol: ! + http: ! + in: body + style: binary + signatureParameters: + - *ref_3 + language: ! + default: + name: '' + description: '' + protocol: ! + http: ! + path: /file + method: post + binary: true + knownMediaType: binary + mediaTypes: + - application/json + uri: '{$host}' + signatureParameters: [] + responses: + - ! + language: ! + default: + name: '' + description: '' + protocol: ! + http: ! + statusCodes: + - '200' + language: ! + default: + name: File + description: Uploading json file + protocol: ! {} + language: ! + default: + name: Upload + description: '' + protocol: ! {} +security: ! + authenticationRequired: false +language: ! + default: + name: '' + description: '' +protocol: ! + http: ! {} diff --git a/modelerfour/test/scenarios/body-binary-json/grouped.yaml b/modelerfour/test/scenarios/body-binary-json/grouped.yaml new file mode 100644 index 0000000..39956de --- /dev/null +++ b/modelerfour/test/scenarios/body-binary-json/grouped.yaml @@ -0,0 +1,110 @@ +! +info: ! + description: Acceptance test for file with json content type. + title: 'Binary with content-type: application/json' +schemas: ! + strings: + - ! &ref_0 + type: string + language: ! + default: + name: string + description: simple string + protocol: ! {} + binaries: + - ! &ref_2 + type: binary + apiVersions: + - ! + version: 1.0.0 + language: ! + default: + name: binary + description: '' + protocol: ! {} +globalParameters: + - ! &ref_1 + schema: *ref_0 + clientDefaultValue: 'https://localhost' + implementation: Client + origin: 'modelerfour:synthesized/host' + required: true + extensions: + x-ms-skip-url-encoding: true + language: ! + default: + name: $host + description: server parameter + serializedName: $host + protocol: ! + http: ! + in: uri +operationGroups: + - ! + $key: Upload + operations: + - ! + apiVersions: + - ! + version: 1.0.0 + parameters: + - *ref_1 + requests: + - ! + parameters: + - ! &ref_3 + schema: *ref_2 + implementation: Method + required: true + language: ! + default: + name: fileParam + description: Foo bar + protocol: ! + http: ! + in: body + style: binary + signatureParameters: + - *ref_3 + language: ! + default: + name: '' + description: '' + protocol: ! + http: ! + path: /file + method: post + binary: true + knownMediaType: binary + mediaTypes: + - application/json + uri: '{$host}' + signatureParameters: [] + responses: + - ! + language: ! + default: + name: '' + description: '' + protocol: ! + http: ! + statusCodes: + - '200' + language: ! + default: + name: File + description: Uploading json file + protocol: ! {} + language: ! + default: + name: Upload + description: '' + protocol: ! {} +security: ! + authenticationRequired: false +language: ! + default: + name: '' + description: '' +protocol: ! + http: ! {} diff --git a/modelerfour/test/scenarios/body-binary-json/modeler.yaml b/modelerfour/test/scenarios/body-binary-json/modeler.yaml new file mode 100644 index 0000000..0ab3b4c --- /dev/null +++ b/modelerfour/test/scenarios/body-binary-json/modeler.yaml @@ -0,0 +1,110 @@ +! +info: ! + description: Acceptance test for file with json content type. + title: 'Binary with content-type: application/json' +schemas: ! + strings: + - ! &ref_0 + type: string + language: ! + default: + name: string + description: simple string + protocol: ! {} + binaries: + - ! &ref_1 + type: binary + apiVersions: + - ! + version: 1.0.0 + language: ! + default: + name: binary + description: '' + protocol: ! {} +globalParameters: + - ! &ref_3 + schema: *ref_0 + clientDefaultValue: 'https://localhost' + implementation: Client + origin: 'modelerfour:synthesized/host' + required: true + extensions: + x-ms-skip-url-encoding: true + language: ! + default: + name: $host + description: server parameter + serializedName: $host + protocol: ! + http: ! + in: uri +operationGroups: + - ! + $key: Upload + operations: + - ! + apiVersions: + - ! + version: 1.0.0 + parameters: + - *ref_3 + requests: + - ! + parameters: + - ! &ref_2 + schema: *ref_1 + implementation: Method + required: true + language: ! + default: + name: fileParam + description: Foo bar + protocol: ! + http: ! + in: body + style: binary + signatureParameters: + - *ref_2 + language: ! + default: + name: '' + description: '' + protocol: ! + http: ! + path: /file + method: post + binary: true + knownMediaType: binary + mediaTypes: + - application/json + uri: '{$host}' + signatureParameters: [] + responses: + - ! + language: ! + default: + name: '' + description: '' + protocol: ! + http: ! + statusCodes: + - '200' + language: ! + default: + name: File + description: Uploading json file + protocol: ! {} + language: ! + default: + name: Upload + description: '' + protocol: ! {} +security: ! + authenticationRequired: false +language: ! + default: + name: '' + description: '' +protocol: ! + http: ! {} diff --git a/modelerfour/test/scenarios/body-binary-json/namer.yaml b/modelerfour/test/scenarios/body-binary-json/namer.yaml new file mode 100644 index 0000000..8d3e296 --- /dev/null +++ b/modelerfour/test/scenarios/body-binary-json/namer.yaml @@ -0,0 +1,110 @@ +! +info: ! + description: Acceptance test for file with json content type. + title: 'Binary with content-type: application/json' +schemas: ! + strings: + - ! &ref_0 + type: string + language: ! + default: + name: String + description: simple string + protocol: ! {} + binaries: + - ! &ref_2 + type: binary + apiVersions: + - ! + version: 1.0.0 + language: ! + default: + name: binary + description: '' + protocol: ! {} +globalParameters: + - ! &ref_1 + schema: *ref_0 + clientDefaultValue: 'https://localhost' + implementation: Client + origin: 'modelerfour:synthesized/host' + required: true + extensions: + x-ms-skip-url-encoding: true + language: ! + default: + name: $host + description: server parameter + serializedName: $host + protocol: ! + http: ! + in: uri +operationGroups: + - ! + $key: Upload + operations: + - ! + apiVersions: + - ! + version: 1.0.0 + parameters: + - *ref_1 + requests: + - ! + parameters: + - ! &ref_3 + schema: *ref_2 + implementation: Method + required: true + language: ! + default: + name: fileParam + description: Foo bar + protocol: ! + http: ! + in: body + style: binary + signatureParameters: + - *ref_3 + language: ! + default: + name: '' + description: '' + protocol: ! + http: ! + path: /file + method: post + binary: true + knownMediaType: binary + mediaTypes: + - application/json + uri: '{$host}' + signatureParameters: [] + responses: + - ! + language: ! + default: + name: '' + description: '' + protocol: ! + http: ! + statusCodes: + - '200' + language: ! + default: + name: File + description: Uploading json file + protocol: ! {} + language: ! + default: + name: Upload + description: '' + protocol: ! {} +security: ! + authenticationRequired: false +language: ! + default: + name: BinaryWithContentTypeApplicationJson + description: '' +protocol: ! + http: ! {} diff --git a/modelerfour/test/scenarios/body-binary-json/oai2.loaded.json b/modelerfour/test/scenarios/body-binary-json/oai2.loaded.json new file mode 100644 index 0000000..810902f --- /dev/null +++ b/modelerfour/test/scenarios/body-binary-json/oai2.loaded.json @@ -0,0 +1,37 @@ +{ + "swagger": "2.0", + "info": { + "description": "Sample for file with json content type.", + "version": "1.0.0", + "title": "Binary with content-type: application/json" + }, + "host": "localhost", + "schemes": ["https"], + "consumes": ["application/json"], + "produces": ["application/json"], + "paths": { + "/file": { + "post": { + "description": "Uploading json file", + "operationId": "Upload_File", + "parameters": [ + { + "name": "fileParam", + "in": "body", + "schema": { + "type": "object", + "format": "file" + }, + "required": true, + "description": "Foo bar" + } + ], + "responses": { + "200": { + "description": "Cowbell was added." + } + } + } + } + } +} diff --git a/modelerfour/test/scenarios/body-binary-json/openapi-document.json b/modelerfour/test/scenarios/body-binary-json/openapi-document.json new file mode 100644 index 0000000..924344d --- /dev/null +++ b/modelerfour/test/scenarios/body-binary-json/openapi-document.json @@ -0,0 +1,134 @@ +{ + "openapi": "3.0.0", + "info": { + "x-ms-metadata": { + "merged": true, + "apiVersions": [ + "1.0.0" + ], + "deduplicated": true, + "schemaReduced": true + }, + "title": "Binary with content-type: application/json", + "description": "Acceptance test for file with json content type.", + "version": "1.0.0" + }, + "paths": { + "path:0": { + "x-ms-metadata": { + "apiVersions": [ + "1.0.0" + ], + "filename": [ + "mem:///100?oai3.shaken.json" + ], + "path": "/file", + "originalLocations": [ + "file:///C:/dev/azsdk/autorest.megarepo/modelerfour/modelerfour/test/scenarios/body-binary-json/oai2.loaded.json#/paths/~1file" + ] + } + }, + "path:0.post": { + "x-ms-metadata": { + "apiVersions": [ + "1.0.0" + ], + "filename": [ + "mem:///100?oai3.shaken.json" + ], + "path": "/file", + "originalLocations": [ + "file:///C:/dev/azsdk/autorest.megarepo/modelerfour/modelerfour/test/scenarios/body-binary-json/oai2.loaded.json#/paths/~1file" + ] + }, + "post": { + "servers": [ + { + "url": "https://localhost/" + } + ], + "description": "Uploading json file", + "operationId": "Upload_File", + "requestBody": { + "description": "Foo bar", + "$ref": "#/components/requestBodies/requestBodies:0" + }, + "x-ms-requestBody-index": 0, + "responses": { + "200": { + "description": "Cowbell was added.", + "$ref": "#/components/responses/responses:0" + } + } + } + } + }, + "components": { + "requestBodies": { + "requestBodies:0": { + "x-ms-metadata": { + "apiVersions": [ + "1.0.0" + ], + "filename": [ + "mem:///100?oai3.shaken.json" + ], + "name": "paths·c88lwi·file·post·requestbody", + "originalLocations": [ + "file:///C:/dev/azsdk/autorest.megarepo/modelerfour/modelerfour/test/scenarios/body-binary-json/oai2.loaded.json#/components/requestBodies/paths·c88lwi·file·post·requestbody" + ] + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/schemas:0" + } + } + }, + "required": true, + "description": "Foo bar", + "x-ms-requestBody-name": "fileParam" + } + }, + "schemas": { + "schemas:0": { + "x-ms-metadata": { + "apiVersions": [ + "1.0.0" + ], + "filename": [ + "mem:///100?oai3.shaken.json" + ], + "name": "paths·rjabaz·file·post·requestbody·content·application-json·schema", + "originalLocations": [ + "file:///C:/dev/azsdk/autorest.megarepo/modelerfour/modelerfour/test/scenarios/body-binary-json/oai2.loaded.json#/components/schemas/paths·rjabaz·file·post·requestbody·content·application-json·schema" + ] + }, + "type": "object", + "format": "file" + } + }, + "responses": { + "responses:0": { + "x-ms-metadata": { + "apiVersions": [ + "1.0.0" + ], + "filename": [ + "mem:///100?oai3.shaken.json" + ], + "name": "paths·2jxz45·file·post·responses·200", + "originalLocations": [ + "file:///C:/dev/azsdk/autorest.megarepo/modelerfour/modelerfour/test/scenarios/body-binary-json/oai2.loaded.json#/components/responses/paths·2jxz45·file·post·responses·200" + ] + }, + "description": "Cowbell was added." + } + } + }, + "servers": [ + { + "url": "https://localhost/" + } + ] +} \ No newline at end of file