diff --git a/packages/openapi-generator/src/openapi.ts b/packages/openapi-generator/src/openapi.ts index 33ff817a..50f59ee3 100644 --- a/packages/openapi-generator/src/openapi.ts +++ b/packages/openapi-generator/src/openapi.ts @@ -431,11 +431,21 @@ export function convertRoutesToOpenAPI( {} as Record, ); + const sortedPaths = Object.keys(paths) + .sort() + .reduce( + (acc, key) => { + acc[key] = paths[key]!; + return acc; + }, + {} as Record, + ); + return { openapi: '3.0.3', info, ...(servers.length > 0 ? { servers } : {}), - paths, + paths: sortedPaths, components: { schemas: openapiSchemas, }, diff --git a/packages/openapi-generator/test/openapi/base.test.ts b/packages/openapi-generator/test/openapi/base.test.ts index b101c9e5..b18b8dc2 100644 --- a/packages/openapi-generator/test/openapi/base.test.ts +++ b/packages/openapi-generator/test/openapi/base.test.ts @@ -714,4 +714,139 @@ testCase('route with array union of null and undefined', ROUTE_WITH_ARRAY_UNION_ components: { schemas: {} } -}); \ No newline at end of file +}); + +const MULTIPLE_ROUTES = ` +import * as t from 'io-ts'; +import * as h from '@api-ts/io-ts-http'; + +export const route1 = h.httpRoute({ + path: '/bar', + method: 'GET', + request: h.httpRequest({ + query: { + bar: t.string, + }, + }), + response: { + 200: t.string + }, +}); + +export const route2 = h.httpRoute({ + path: '/baz', + method: 'GET', + request: h.httpRequest({ + query: { + baz: t.string, + }, + }), + response: { + 200: t.string + }, +}); + +export const route3 = h.httpRoute({ + path: '/foo', + method: 'GET', + request: h.httpRequest({ + query: { + foo: t.string, + }, + }), + response: { + 200: t.string + }, +}); +`; + +testCase('multiple routes', MULTIPLE_ROUTES, { + openapi: '3.0.3', + info: { + title: 'Test', + version: '1.0.0', + }, + paths: { + '/bar': { + get: { + parameters: [ + { + in: 'query', + name: 'bar', + required: true, + schema: { + type: 'string', + }, + }, + ], + responses: { + 200: { + description: 'OK', + content: { + 'application/json': { + schema: { + type: 'string', + }, + }, + }, + }, + }, + }, + }, + '/baz': { + get: { + parameters: [ + { + in: 'query', + name: 'baz', + required: true, + schema: { + type: 'string', + }, + }, + ], + responses: { + 200: { + description: 'OK', + content: { + 'application/json': { + schema: { + type: 'string', + }, + }, + }, + }, + }, + }, + }, + '/foo': { + get: { + parameters: [ + { + in: 'query', + name: 'foo', + required: true, + schema: { + type: 'string', + }, + }, + ], + responses: { + 200: { + description: 'OK', + content: { + 'application/json': { + schema: { + type: 'string', + }, + }, + }, + }, + }, + }, + }, + }, + components: { + schemas: {}, + }, +});