Skip to content

Commit

Permalink
Feat/openapi expanded contenttype (#4228)
Browse files Browse the repository at this point in the history
* feat: expand content type handling in openapi handler. possibly resolves for issue #3044

* Add a changeset

* Go

Co-authored-by: JB Smith <[email protected]>
  • Loading branch information
ardatan and mayan-jbsmith authored Aug 3, 2022
1 parent 4f6397f commit 31d5f6e
Show file tree
Hide file tree
Showing 5 changed files with 157 additions and 5 deletions.
5 changes: 5 additions & 0 deletions .changeset/small-rocks-pretend.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@graphql-mesh/openapi': patch
---

feat: expand content type handling in openapi handler. possibly resolves for issue #3044
10 changes: 6 additions & 4 deletions packages/handlers/openapi/src/openapi-to-graphql/oas_3_tools.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,8 @@ export enum HTTP_METHODS {

export const SUCCESS_STATUS_RX = /2[0-9]{2}|2XX/;

export const CONTENT_TYPE_JSON_RX = /^application\/(.*)json$/;

/**
* Given an HTTP method, convert it to the HTTP_METHODS enum
*/
Expand Down Expand Up @@ -462,7 +464,7 @@ export function getRequestBodyObject(

const contentTypes = Object.keys(content);
const jsonContentType = contentTypes
.find(contentType => contentType.toString().includes('application/json'))
.find(contentType => CONTENT_TYPE_JSON_RX.test(contentType.toString()))
?.toString();
const formDataContentType = contentTypes
.find(contentType => contentType.toString().includes('application/x-www-form-urlencoded'))
Expand Down Expand Up @@ -525,7 +527,7 @@ export function getRequestSchemaAndNames(path: string, operation: OperationObjec
* with the proper content-type header
*/
if (
!payloadContentType.includes('application/json') &&
!CONTENT_TYPE_JSON_RX.test(payloadContentType.toString()) &&
!payloadContentType.includes('application/x-www-form-urlencoded') &&
!payloadContentType.includes('*/*')
) {
Expand Down Expand Up @@ -587,7 +589,7 @@ export function getResponseObject(
const content: MediaTypesObject = responseObject.content;

const contentTypes = Object.keys(content);
const isJsonContent = contentTypes.some(contentType => contentType.toString().includes('application/json'));
const isJsonContent = contentTypes.some(contentType => CONTENT_TYPE_JSON_RX.test(contentType.toString()));
// Prioritize content-type JSON
if (isJsonContent) {
return {
Expand Down Expand Up @@ -662,7 +664,7 @@ export function getResponseSchemaAndNames<TSource, TContext, TArgs>(
* Edge case: if response body content-type is not application/json, do not
* parse.
*/
if (!responseContentType.includes('application/json') && !responseContentType.includes('*/*')) {
if (!CONTENT_TYPE_JSON_RX.test(responseContentType.toString()) && !responseContentType.includes('*/*')) {
let description = 'Placeholder to access non-application/json response bodies';

if ('description' in responseSchema && typeof responseSchema.description === 'string') {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1108,7 +1108,8 @@ export function getArgs<TSource, TContext, TArgs>({
} else if (typeof parameter.content === 'object') {
const contentTypes = Object.keys(parameter.content);
const jsonContentType = contentTypes.find(
contentType => contentType.toString().includes('application/json') || contentType.toString().includes('*/*')
contentType =>
Oas3Tools.CONTENT_TYPE_JSON_RX.test(contentType.toString()) || contentType.toString().includes('*/*')
);
if (
jsonContentType &&
Expand Down
36 changes: 36 additions & 0 deletions packages/handlers/openapi/test/cloudfunction_expanded.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// Copyright IBM Corp. 2017. All Rights Reserved.
// Node module: openapi-to-graphql
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT

'use strict';

/* globals beforeAll, test, expect */

import * as openAPIToGraphQL from '../src/openapi-to-graphql/index';
import { GraphQLSchema, parse, validate } from 'graphql';
import { fetch } from '@whatwg-node/fetch';

const oas = require('./fixtures/cloudfunction_expanded.json');

let createdSchema: GraphQLSchema;

beforeAll(async () => {
const { schema } = await openAPIToGraphQL.createGraphQLSchema(oas, { fetch });
createdSchema = schema;
});

test('Get response', async () => {
const query = `mutation {
mutationViewerBasicAuth (username: "test" password: "data") {
postTestAction2 (payloadInput: {age: 27}) {
payload
age
}
}
}`;
// validate that 'limit' parameter is covered by options:
const ast = parse(query);
const errors = validate(createdSchema, ast);
expect(errors).toEqual([]);
});
108 changes: 108 additions & 0 deletions packages/handlers/openapi/test/fixtures/cloudfunction_expanded.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
{
"openapi": "3.0.0",
"info": {
"title": "test-action-2-expanded",
"version": "1.0.0"
},
"paths": {
"/test-action-2": {
"post": {
"description": "Description of the action",
"responses": {
"200": {
"description": "Success response for test-action-2-expanded",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Response"
}
}
}
},
"default": {
"description": "Error response for test-action-2-expanded",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
}
},
"parameters": [
{
"name": "blocking",
"in": "query",
"schema": {
"type": "boolean",
"default": true
}
},
{
"name": "result",
"in": "query",
"schema": {
"type": "boolean",
"default": true
}
}
],
"security": [
{
"basic_protocol": []
}
],
"requestBody": {
"content": {
"application/vnd.experimental+json": {
"schema": {
"$ref": "#/components/schemas/Payload"
}
}
}
}
}
}
},
"servers": [
{
"url": "https://openwhisk.ng.bluemix.net/api/v1/namespaces/_/actions"
}
],
"components": {
"schemas": {
"Response": {
"type": "object",
"properties": {
"payload": {
"type": "string"
},
"age": {
"type": "number"
},
"valid": {
"type": "boolean"
}
},
"required": ["payload", "age", "valid"]
},
"Error": {},
"Payload": {
"type": "object",
"properties": {
"age": {
"type": "number"
}
},
"required": ["age"]
}
},
"securitySchemes": {
"basic_protocol": {
"type": "http",
"scheme": "basic"
}
}
}
}

1 comment on commit 31d5f6e

@vercel
Copy link

@vercel vercel bot commented on 31d5f6e Aug 3, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.