Skip to content

Commit d56cdfe

Browse files
committed
[IO-363] Arbitrary mediaTypes for OpenAPI 3.0
1 parent 9e2b661 commit d56cdfe

File tree

6 files changed

+77
-7
lines changed

6 files changed

+77
-7
lines changed

src/language/typescript/3.0/serializers/operation-object.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,9 @@ export const getParameters = combineReader(
266266
},
267267
);
268268

269+
const blobMediaRegexp = /^(video|audio|image|application)/;
270+
const textMediaRegexp = /^text/;
271+
269272
export const serializeOperationObject = combineReader(
270273
ask<ResolveRefContext>(),
271274
getParameters,
@@ -299,10 +302,13 @@ export const serializeOperationObject = combineReader(
299302
fold(
300303
() => 'json',
301304
types => {
302-
if (types.includes('application/octet-stream')) {
305+
if (types.includes('application/json')) {
306+
return 'json';
307+
}
308+
if (types.some(s => blobMediaRegexp.test(s))) {
303309
return 'blob';
304310
}
305-
if (types.includes('text/plain')) {
311+
if (types.some(s => textMediaRegexp.test(s))) {
306312
return 'text';
307313
}
308314
return 'json';

src/language/typescript/3.0/serializers/request-body-object.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,12 @@ import { serializeSchemaObject } from './schema-object';
22
import { getSerializedRefType, SerializedType } from '../../common/data/serialized-type';
33
import { Either, mapLeft } from 'fp-ts/lib/Either';
44
import { pipe } from 'fp-ts/lib/pipeable';
5-
import { either, option, record } from 'fp-ts';
5+
import { either, option } from 'fp-ts';
66
import { fromString, Ref } from '../../../../utils/ref';
77
import { RequestBodyObject } from '../../../../schema/3.0/request-body-object';
88
import { ReferenceObjectCodec, ReferenceObject } from '../../../../schema/3.0/reference-object';
99
import { SchemaObject } from '../../../../schema/3.0/schema-object';
10+
import { getKeyMatchValue } from '../../common/utils';
1011

1112
export const serializeRequestBodyObject = (from: Ref, body: RequestBodyObject): Either<Error, SerializedType> =>
1213
pipe(
@@ -25,9 +26,10 @@ export const serializeRequestBodyObject = (from: Ref, body: RequestBodyObject):
2526
),
2627
);
2728

29+
const requestMediaRegexp = /^(video|audio|image|application|text|multipart\/form-data)/;
2830
const getSchema = (requestBodyObject: RequestBodyObject): Either<Error, ReferenceObject | SchemaObject> =>
2931
pipe(
30-
record.lookup('application/json', requestBodyObject.content),
32+
getKeyMatchValue(requestBodyObject.content, requestMediaRegexp),
3133
option.chain(media => media.schema),
3234
either.fromOption(() => new Error('No schema found for ReqeustBodyObject')),
3335
);

src/language/typescript/3.0/serializers/response-object.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,17 @@ import { either, option } from 'fp-ts';
77
import { ResponseObject } from '../../../../schema/3.0/response-object';
88
import { Option } from 'fp-ts/lib/Option';
99
import { ReferenceObjectCodec } from '../../../../schema/3.0/reference-object';
10+
import { getKeyMatchValue } from '../../common/utils';
11+
12+
const requestMediaRegexp = /^(video|audio|image|application|text)/;
1013

1114
export const serializeResponseObject = (
1215
from: Ref,
1316
responseObject: ResponseObject,
1417
): Option<Either<Error, SerializedType>> =>
1518
pipe(
1619
responseObject.content,
17-
option.mapNullable(
18-
content => content['application/json'] || content['text/plain'] || content['application/octet-stream'],
19-
),
20+
option.chain(content => getKeyMatchValue(content, requestMediaRegexp)),
2021
option.chain(media => media.schema),
2122
option.map(schema =>
2223
ReferenceObjectCodec.is(schema)

src/language/typescript/common/data/serialized-type.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ export const getSerializedStringType = (from: Ref, format: Option<string>): Eith
109109
),
110110
);
111111
}
112+
case 'base64':
112113
case 'binary': {
113114
return some(SERIALIZED_UNKNOWN_TYPE);
114115
}

src/language/typescript/common/utils.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@ import { Options } from 'prettier';
44
import { fromString, ResolveRefContext } from '../../../utils/ref';
55
import { Kind } from '../../../utils/types';
66
import { ask } from 'fp-ts/lib/Reader';
7+
import { pipe } from 'fp-ts/lib/pipeable';
8+
import { keys } from 'fp-ts/lib/Record';
9+
import { array, option } from 'fp-ts';
710

811
export const SUCCESSFUL_CODES = ['200', '201', 'default'];
912
export const CONTROLLERS_DIRECTORY = 'controllers';
@@ -77,3 +80,11 @@ export const getSafePropertyName = (value: string): string =>
7780
value.replace(REPLACE_PATTERN, '_').replace(/^(\d)/, '_$1') || '_';
7881

7982
export const context = ask<ResolveRefContext>();
83+
84+
export const getKeyMatchValue = <T>(record: Record<string, T>, regexp: RegExp): option.Option<T> =>
85+
pipe(
86+
record,
87+
keys,
88+
array.findFirst(s => regexp.test(s)),
89+
option.map(key => record[key]),
90+
);

test/specs/3.0/file-and-text.yml

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,55 @@ paths:
9191
text/plain:
9292
schema:
9393
$ref: '#/components/schemas/Text'
94+
/image:
95+
get:
96+
tags:
97+
- media
98+
summary: get image
99+
operationId: loadImage
100+
responses:
101+
200:
102+
description: succesfull operation
103+
content:
104+
image/png:
105+
schema:
106+
$ref: '#/components/schemas/File'
107+
/image:
108+
/audio:
109+
get:
110+
tags:
111+
- media
112+
summary: get audio
113+
operationId: loadAudio
114+
responses:
115+
200:
116+
description: succesfull operation
117+
content:
118+
image/png:
119+
schema:
120+
$ref: '#/components/schemas/File'
121+
/upload:
122+
post:
123+
tags:
124+
- media
125+
summary: updload image
126+
operationId: uploadImage
127+
requestBody:
128+
content:
129+
multipart/form-data:
130+
schema:
131+
type: object
132+
properties:
133+
images:
134+
type: array
135+
items:
136+
type: string
137+
format: binary
138+
required:
139+
- images
140+
responses:
141+
200:
142+
description: succesfull operation
94143
components:
95144
schemas:
96145
File:

0 commit comments

Comments
 (0)