Skip to content

Commit e254ba8

Browse files
arnaudArnaud Leymet
andauthored
fix(openapi): support 204 responses which have content keys with empty values (#8640)
Co-authored-by: Arnaud Leymet <[email protected]>
1 parent 2e50a7c commit e254ba8

File tree

5 files changed

+95
-1
lines changed

5 files changed

+95
-1
lines changed

.changeset/solid-chefs-lay.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@omnigraph/openapi': patch
3+
---
4+
5+
fix(openapi): support 204 responses which have content keys with empty values

packages/loaders/openapi/src/getJSONSchemaOptionsFromOpenAPIOptions.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -464,7 +464,14 @@ export async function getJSONSchemaOptionsFromOpenAPIOptions(
464464
operationConfig.headers.Accept = methodObj.produces.join(', ');
465465
}
466466

467-
if ('content' in responseObj) {
467+
/**
468+
* The OAS rule is that 204 responses should not specify a content key.
469+
* But in the real world, it happens that some specifications present 204 responses with an
470+
* empty content key.
471+
*
472+
* @see https://swagger.io/docs/specification/v3_0/describing-responses/#empty-response-body
473+
*/
474+
if ('content' in responseObj && Object.keys(responseObj.content).length !== 0) {
468475
const responseObjForStatusCode: {
469476
oneOf: JSONSchemaObject[];
470477
} = {
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import { GraphQLSchema } from 'graphql';
2+
import { printSchemaWithDirectives } from '@graphql-tools/utils';
3+
import { loadGraphQLSchemaFromOpenAPI } from '../src/loadGraphQLSchemaFromOpenAPI.js';
4+
5+
describe('204 response with empty content', () => {
6+
let createdSchema: GraphQLSchema;
7+
beforeAll(async () => {
8+
createdSchema = await loadGraphQLSchemaFromOpenAPI('test', {
9+
source: './fixtures/204-response-with-empty-content.json',
10+
cwd: __dirname,
11+
});
12+
});
13+
14+
it('should generate the schema correctly', () => {
15+
expect(printSchemaWithDirectives(createdSchema)).toMatchSnapshot();
16+
});
17+
});
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
// Jest Snapshot v1, https://goo.gl/fbAQLP
2+
3+
exports[`204 response with empty content should generate the schema correctly 1`] = `
4+
"schema @transport(subgraph: "test", kind: "rest", location: "/") {
5+
query: Query
6+
mutation: Mutation
7+
}
8+
9+
directive @httpOperation(subgraph: String, path: String, operationSpecificHeaders: [[String]], httpMethod: HTTPMethod, isBinary: Boolean, requestBaseBody: ObjMap, queryParamArgMap: ObjMap, queryStringOptionsByParam: ObjMap, jsonApiFields: Boolean, queryStringOptions: ObjMap) on FIELD_DEFINITION
10+
11+
directive @transport(subgraph: String, kind: String, location: String, headers: [[String]], queryStringOptions: ObjMap, queryParams: [[String]]) repeatable on SCHEMA
12+
13+
type Query {
14+
dummy: String
15+
}
16+
17+
type Mutation {
18+
""" """
19+
myOperation: Void @httpOperation(subgraph: "test", path: "/myoperation", httpMethod: PUT)
20+
}
21+
22+
"""Represents empty values"""
23+
scalar Void
24+
25+
enum HTTPMethod {
26+
GET
27+
HEAD
28+
POST
29+
PUT
30+
DELETE
31+
CONNECT
32+
OPTIONS
33+
TRACE
34+
PATCH
35+
}
36+
37+
scalar ObjMap"
38+
`;
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
{
2+
"openapi": "3.0.1",
3+
"info": {
4+
"title": "My operation",
5+
"version": "1.0.0",
6+
"description": " ",
7+
"contact": {}
8+
},
9+
"tags": [{ "name": "tag" }],
10+
"servers": [
11+
{
12+
"url": "/"
13+
}
14+
],
15+
"paths": {
16+
"/myoperation": {
17+
"put": {
18+
"operationId": "myOperation",
19+
"description": " ",
20+
"tags": ["tag"],
21+
"responses": {
22+
"204": { "description": "", "content": {} }
23+
}
24+
}
25+
}
26+
}
27+
}

0 commit comments

Comments
 (0)