Skip to content

Commit 3473a26

Browse files
authored
feat(openapi): support links on non-object fields (#4376)
* feat(openapi): support links on non-object fields * Fix TS
1 parent e9f6736 commit 3473a26

File tree

6 files changed

+116
-23
lines changed

6 files changed

+116
-23
lines changed

.changeset/famous-games-arrive.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
"@omnigraph/json-schema": minor
3+
"@omnigraph/openapi": minor
4+
---
5+
6+
Support links on non-object fields

packages/loaders/json-schema/src/addExecutionLogicToComposer.ts

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -497,19 +497,32 @@ ${operationConfig.description || ''}
497497
const responseConfig = operationConfig.responseByStatusCode[statusCode];
498498
if (responseConfig.links || responseConfig.exposeResponseMetadata) {
499499
const typeTCThunked = types[statusCodeOneOfIndexMap[statusCode] || 0];
500-
const typeTC = schemaComposer.getAnyTC(typeTCThunked.getTypeName());
501-
if ('addFieldArgs' in typeTC) {
502-
if (responseConfig.exposeResponseMetadata) {
503-
typeTC.addFields({
504-
_response: {
505-
type: responseMetadataType,
506-
resolve: root => root.$response,
500+
const originalName = typeTCThunked.getTypeName();
501+
let typeTC = schemaComposer.getAnyTC(originalName);
502+
if (!('addFieldArgs' in typeTC)) {
503+
typeTC = schemaComposer.createObjectTC({
504+
name: `${operationConfig.field}_${statusCode}_response`,
505+
fields: {
506+
[originalName]: {
507+
type: typeTC as any,
508+
resolve: root => root,
507509
},
508-
});
509-
}
510-
if (responseConfig.links) {
511-
handleLinkMap(responseConfig.links, typeTC as ObjectTypeComposer);
512-
}
510+
},
511+
});
512+
// If it is a scalar or enum type, it cannot be a union type, so we can set it directly
513+
types[0] = typeTC;
514+
field.type = typeTC;
515+
}
516+
if (responseConfig.exposeResponseMetadata) {
517+
typeTC.addFields({
518+
_response: {
519+
type: responseMetadataType,
520+
resolve: root => root.$response,
521+
},
522+
});
523+
}
524+
if (responseConfig.links) {
525+
handleLinkMap(responseConfig.links, typeTC as ObjectTypeComposer);
513526
}
514527
}
515528
}

packages/loaders/json-schema/src/getUnionTypeComposers.ts

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { JSONSchemaObject } from '@json-schema-tools/meta-schema';
33
import Ajv from 'ajv';
44
import {
55
AnyTypeComposer,
6+
ComposeInputType,
67
InputTypeComposer,
78
isSomeInputTypeComposer,
89
ObjectTypeComposer,
@@ -24,6 +25,18 @@ export interface GetUnionTypeComposersOpts {
2425
logger: Logger;
2526
}
2627

28+
export function getContainerTC(schemaComposer: SchemaComposer, output: ComposeInputType) {
29+
const containerTypeName = `${output.getTypeName()}_container`;
30+
return schemaComposer.getOrCreateOTC(containerTypeName, otc =>
31+
otc.addFields({
32+
[output.getTypeName()]: {
33+
type: output as any,
34+
resolve: root => root,
35+
},
36+
})
37+
);
38+
}
39+
2740
export function getUnionTypeComposers({
2841
schemaComposer,
2942
ajv,
@@ -39,17 +52,7 @@ export function getUnionTypeComposers({
3952
typeComposersList.forEach(typeComposers => {
4053
const { input, output } = typeComposers;
4154
if (isSomeInputTypeComposer(output)) {
42-
const containerTypeName = `${output.getTypeName()}_container`;
43-
outputTypeComposers.push(
44-
schemaComposer.getOrCreateOTC(containerTypeName, otc =>
45-
otc.addFields({
46-
[output.getTypeName()]: {
47-
type: output,
48-
resolve: root => root,
49-
},
50-
})
51-
)
52-
);
55+
outputTypeComposers.push(getContainerTC(schemaComposer, output));
5356
} else {
5457
outputTypeComposers.push(output);
5558
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// Jest Snapshot v1, https://goo.gl/fbAQLP
2+
3+
exports[`Links on non-object fields should generate the correct schema 1`] = `
4+
"schema {
5+
query: Query
6+
}
7+
8+
type Query {
9+
test: test_200_response
10+
testLink: testLink_200_response
11+
}
12+
13+
type test_200_response {
14+
String: String
15+
testLink: testLink_200_response
16+
}
17+
18+
type testLink_200_response {
19+
foo: String
20+
}"
21+
`;
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
openapi: 3.0.1
2+
info:
3+
title: API
4+
description: ''
5+
contact: {}
6+
version: '1.0'
7+
servers:
8+
- url: http://localhost:7777
9+
security:
10+
- ApiKeyAuth: []
11+
tags: []
12+
paths:
13+
/test:
14+
get:
15+
operationId: test
16+
responses:
17+
200:
18+
description: ''
19+
content:
20+
application/json:
21+
schema:
22+
type: string
23+
links:
24+
testLink:
25+
operationId: testLink
26+
/test-link:
27+
get:
28+
operationId: testLink
29+
responses:
30+
200:
31+
description: ''
32+
content:
33+
application/json:
34+
schema:
35+
type: object
36+
properties:
37+
foo:
38+
type: string
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { printSchemaWithDirectives } from '@graphql-tools/utils';
2+
import loadGraphQLSchemaFromOpenAPI from '../src';
3+
4+
describe('Links on non-object fields', () => {
5+
it('should generate the correct schema', async () => {
6+
const schema = await loadGraphQLSchemaFromOpenAPI('toto', {
7+
source: './fixtures/non_string_links.yml',
8+
cwd: __dirname,
9+
});
10+
expect(printSchemaWithDirectives(schema)).toMatchSnapshot();
11+
});
12+
});

0 commit comments

Comments
 (0)