Skip to content

Commit 7b853d9

Browse files
authored
Merge pull request #782 from BitGo/DX-441-allow-refs-to-have-descriptions
feat: allow `refs` to have `descriptions/examples/patterns`
2 parents 99eb5f7 + 41c80be commit 7b853d9

File tree

3 files changed

+159
-1
lines changed

3 files changed

+159
-1
lines changed

packages/openapi-generator/src/openapi.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,14 @@ function schemaToOpenAPI(
4444
// Or should we just conflate explicit null and undefined properties?
4545
return { nullable: true, enum: [] };
4646
case 'ref':
47-
return { $ref: `#/components/schemas/${schema.name}` };
47+
// if defaultOpenAPIObject is empty, no need to wrap the $ref in an allOf array
48+
if (Object.keys(defaultOpenAPIObject).length === 0) {
49+
return { $ref: `#/components/schemas/${schema.name}` };
50+
}
51+
return {
52+
allOf: [{ $ref: `#/components/schemas/${schema.name}` }],
53+
...defaultOpenAPIObject,
54+
};
4855
case 'array':
4956
const innerSchema = schemaToOpenAPI(schema.items);
5057
if (innerSchema === undefined) {

packages/openapi-generator/src/optimize.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,11 @@ export function optimize(schema: Schema): Schema {
153153
} else if (schema.type === 'tuple') {
154154
const schemas = schema.schemas.map(optimize);
155155
return { type: 'tuple', schemas };
156+
} else if (schema.type === 'ref') {
157+
if (schema.comment) {
158+
return { ...schema, comment: schema.comment };
159+
}
160+
return schema;
156161
} else {
157162
return schema;
158163
}

packages/openapi-generator/test/openapi.test.ts

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2180,3 +2180,149 @@ testCase('route with descriptions, patterns, and examples', ROUTE_WITH_DESCRIPTI
21802180
schemas: {}
21812181
}
21822182
});
2183+
2184+
const ROUTE_WITH_DESCRIPTIONS_FOR_REFERENCES = `
2185+
import * as t from 'io-ts';
2186+
import * as h from '@api-ts/io-ts-http';
2187+
2188+
const Foo = t.type({ foo: t.string });
2189+
const Bar = t.type({ bar: t.number });
2190+
2191+
/**
2192+
* A simple route with type descriptions for references
2193+
*
2194+
* @operationId api.v1.test
2195+
* @tag Test Routes
2196+
*/
2197+
export const route = h.httpRoute({
2198+
path: '/foo',
2199+
method: 'GET',
2200+
request: h.httpRequest({
2201+
query: {
2202+
bar: t.array(t.string),
2203+
},
2204+
body: {
2205+
/**
2206+
* This is a foo description.
2207+
* @example "BitGo Inc"
2208+
*/
2209+
foo: Foo,
2210+
bar: Bar,
2211+
},
2212+
}),
2213+
response: {
2214+
200: {
2215+
test: t.string
2216+
}
2217+
},
2218+
});
2219+
`;
2220+
2221+
testCase('route with descriptions for references', ROUTE_WITH_DESCRIPTIONS_FOR_REFERENCES, {
2222+
openapi: '3.0.3',
2223+
info: {
2224+
title: 'Test',
2225+
version: '1.0.0'
2226+
},
2227+
paths: {
2228+
'/foo': {
2229+
get: {
2230+
summary: 'A simple route with type descriptions for references',
2231+
operationId: 'api.v1.test',
2232+
tags: [
2233+
'Test Routes'
2234+
],
2235+
parameters: [
2236+
{
2237+
name: 'bar',
2238+
in: 'query',
2239+
required: true,
2240+
schema: {
2241+
type: 'array',
2242+
items: {
2243+
type: 'string'
2244+
}
2245+
}
2246+
}
2247+
],
2248+
requestBody: {
2249+
content: {
2250+
'application/json': {
2251+
schema: {
2252+
type: 'object',
2253+
properties: {
2254+
// needs to be wrapped in an allOf to preserve the description
2255+
foo: {
2256+
allOf: [
2257+
{
2258+
$ref: '#/components/schemas/Foo'
2259+
}
2260+
],
2261+
description: 'This is a foo description.',
2262+
example: 'BitGo Inc'
2263+
},
2264+
// should not need to be wrapped in an allOf
2265+
bar: {
2266+
$ref: '#/components/schemas/Bar'
2267+
}
2268+
},
2269+
required: [
2270+
'foo',
2271+
'bar'
2272+
]
2273+
}
2274+
}
2275+
}
2276+
},
2277+
responses: {
2278+
'200': {
2279+
description: 'OK',
2280+
content: {
2281+
'application/json': {
2282+
schema: {
2283+
type: 'object',
2284+
properties: {
2285+
test: {
2286+
type: 'string'
2287+
}
2288+
},
2289+
required: [
2290+
'test'
2291+
]
2292+
}
2293+
}
2294+
}
2295+
}
2296+
}
2297+
}
2298+
}
2299+
},
2300+
components: {
2301+
schemas: {
2302+
Foo: {
2303+
title: 'Foo',
2304+
type: 'object',
2305+
properties: {
2306+
foo: {
2307+
type: 'string'
2308+
}
2309+
},
2310+
required: [
2311+
'foo'
2312+
]
2313+
},
2314+
Bar: {
2315+
title: 'Bar',
2316+
type: 'object',
2317+
properties: {
2318+
bar: {
2319+
type: 'number'
2320+
}
2321+
},
2322+
required: [
2323+
'bar'
2324+
]
2325+
}
2326+
}
2327+
}
2328+
});

0 commit comments

Comments
 (0)