From 6187b982e5ac44367fa1a732abd6018441286109 Mon Sep 17 00:00:00 2001 From: Patrick McLaughlin <88669932+bitgopatmcl@users.noreply.github.com> Date: Thu, 24 Oct 2024 16:18:02 -0400 Subject: [PATCH] Sort HTTP verbs within each path in OpenAPI spec Sort HTTP verbs within each path in the OpenAPI specification. * Modify `convertRoutesToOpenAPI` function in `packages/openapi-generator/src/openapi.ts` to sort HTTP verbs within each path after sorting the paths. * Add a test case in `packages/openapi-generator/test/openapi/base.test.ts` to verify the sorting of HTTP verbs within each path. --- packages/openapi-generator/src/openapi.ts | 9 +- .../test/openapi/base.test.ts | 134 +++++++++++++++++- 2 files changed, 141 insertions(+), 2 deletions(-) diff --git a/packages/openapi-generator/src/openapi.ts b/packages/openapi-generator/src/openapi.ts index b1c6df07..1e880e2e 100644 --- a/packages/openapi-generator/src/openapi.ts +++ b/packages/openapi-generator/src/openapi.ts @@ -435,7 +435,14 @@ export function convertRoutesToOpenAPI( .sort((a, b) => a.localeCompare(b)) .reduce( (acc, key) => { - acc[key] = paths[key]!; + const sortedMethods = Object.keys(paths[key]!) + .sort((a, b) => a.localeCompare(b)) + .reduce((methodAcc, methodKey) => { + methodAcc[methodKey] = paths[key]![methodKey]!; + return methodAcc; + }, {} as Record); + + acc[key] = sortedMethods; return acc; }, {} as Record, diff --git a/packages/openapi-generator/test/openapi/base.test.ts b/packages/openapi-generator/test/openapi/base.test.ts index 16767f95..6d9f6147 100644 --- a/packages/openapi-generator/test/openapi/base.test.ts +++ b/packages/openapi-generator/test/openapi/base.test.ts @@ -817,11 +817,143 @@ testCase('multiple routes', MULTIPLE_ROUTES, { }, }, }, - }, + ], + }, + }, + '/foo': { + get: { + parameters: [ + { + in: 'query', + name: 'foo', + required: true, + schema: { + type: 'string', + }, + }, + ], + responses: { + 200: { + description: 'OK', + content: { + 'application/json': { + schema: { + type: 'string', + }, + }, + }, + }, + ], }, }, + }, + components: { + schemas: {}, + }, +}); + +const MULTIPLE_ROUTES_WITH_METHODS = ` +import * as t from 'io-ts'; +import * as h from '@api-ts/io-ts-http'; + +// Purposefully out of order to test sorting +export const route1 = h.httpRoute({ + path: '/foo', + method: 'POST', + request: h.httpRequest({ + query: { + foo: t.string, + }, + }), + response: { + 200: t.string + }, +}); + +export const route2 = h.httpRoute({ + path: '/foo', + method: 'GET', + request: h.httpRequest({ + query: { + foo: t.string, + }, + }), + response: { + 200: t.string + }, +}); + +export const route3 = h.httpRoute({ + path: '/foo', + method: 'DELETE', + request: h.httpRequest({ + query: { + foo: t.string, + }, + }), + response: { + 200: t.string + }, +}); +`; + +testCase('multiple routes with methods', MULTIPLE_ROUTES_WITH_METHODS, { + openapi: '3.0.3', + info: { + title: 'Test', + version: '1.0.0', + }, + paths: { '/foo': { + delete: { + parameters: [ + { + in: 'query', + name: 'foo', + required: true, + schema: { + type: 'string', + }, + }, + ], + responses: { + 200: { + description: 'OK', + content: { + 'application/json': { + schema: { + type: 'string', + }, + }, + }, + }, + }, + }, get: { + parameters: [ + { + in: 'query', + name: 'foo', + required: true, + schema: { + type: 'string', + }, + }, + ], + responses: { + 200: { + description: 'OK', + content: { + 'application/json': { + schema: { + type: 'string', + }, + }, + }, + }, + ], + }, + post: { parameters: [ { in: 'query',