Skip to content

Commit 73b2f68

Browse files
authored
Merge pull request #4 from aep-dev/openapi_types
Openapi types
2 parents d4029b9 + b130df8 commit 73b2f68

File tree

7 files changed

+78
-504
lines changed

7 files changed

+78
-504
lines changed

src/api/api.test.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
/// <reference types="jest" />
2-
import { API, Contact, OpenAPI, Resource, APISchema } from "./types.js";
2+
import { API, Resource } from "./types.js";
3+
import { Contact, OpenAPI, Schema } from "../openapi/types.js";
34
import { APIClient } from "./api.js";
45
import { fetchOpenAPI, OpenAPIImpl } from "../openapi/openapi.js";
56
import yargs from "yargs";
@@ -314,7 +315,7 @@ describe("APIClient", () => {
314315
properties: {
315316
name: { type: "string" },
316317
},
317-
xAEPResource: {
318+
"x-aep-resource": {
318319
singular: "widget",
319320
plural: "widgets",
320321
patterns: ["/widgets/{widget}"],

src/api/api.ts

Lines changed: 25 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,17 @@
11
import {
22
API,
3-
Contact,
4-
OpenAPI,
53
PatternInfo,
64
Resource,
7-
APISchema,
8-
Response as OpenAPIResponse,
9-
RequestBody as OpenAPIRequestBody,
105
CustomMethod,
116
} from "./types.js";
7+
import {
8+
Contact,
9+
OpenAPI,
10+
Schema,
11+
Response as OpenAPIResponse,
12+
RequestBody as OpenAPIRequestBody,
13+
} from "../openapi/types.js";
1214
import { pascalCaseToKebabCase } from "../cases/cases.js";
13-
import { Schema } from "../openapi/types.js";
1415
import { logger } from "../utils/logger.js";
1516

1617
export class APIClient {
@@ -43,7 +44,7 @@ export class APIClient {
4344
continue;
4445
}
4546

46-
let schemaRef: APISchema | null = null;
47+
let schemaRef: Schema | null = null;
4748
const r: Partial<Resource> = {};
4849

4950
if (patternInfo.customMethodName && patternInfo.isResourcePattern) {
@@ -53,7 +54,7 @@ export class APIClient {
5354
}
5455

5556
if (pathItem.post) {
56-
const response = pathItem.post.responses["200"];
57+
const response = pathItem.post.responses?.["200"];
5758
if (response) {
5859
const schema = getSchemaFromResponse(response, openAPI);
5960
const responseSchema = schema
@@ -81,7 +82,7 @@ export class APIClient {
8182
}
8283

8384
if (pathItem.get) {
84-
const response = pathItem.get.responses["200"];
85+
const response = pathItem.get.responses?.["200"];
8586
if (response) {
8687
const schema = getSchemaFromResponse(response, openAPI);
8788
const responseSchema = schema
@@ -101,22 +102,22 @@ export class APIClient {
101102
r.deleteMethod = {};
102103
}
103104
if (pathItem.get) {
104-
const response = pathItem.get.responses["200"];
105+
const response = pathItem.get.responses?.["200"];
105106
if (response) {
106107
schemaRef = getSchemaFromResponse(response, openAPI);
107108
r.getMethod = {};
108109
}
109110
}
110111
if (pathItem.patch) {
111-
const response = pathItem.patch.responses["200"];
112+
const response = pathItem.patch.responses?.["200"];
112113
if (response) {
113114
schemaRef = getSchemaFromResponse(response, openAPI);
114115
r.updateMethod = {};
115116
}
116117
}
117118
} else {
118119
if (pathItem.post) {
119-
const response = pathItem.post.responses["200"];
120+
const response = pathItem.post.responses?.["200"];
120121
if (response) {
121122
schemaRef = getSchemaFromResponse(response, openAPI);
122123
const supportsUserSettableCreate =
@@ -127,7 +128,7 @@ export class APIClient {
127128
}
128129

129130
if (pathItem.get) {
130-
const response = pathItem.get.responses["200"];
131+
const response = pathItem.get.responses?.["200"];
131132
if (response) {
132133
const respSchema = getSchemaFromResponse(response, openAPI);
133134
if (!respSchema) {
@@ -218,16 +219,16 @@ export class APIClient {
218219
}
219220

220221
if (!serverURL) {
221-
serverURL = openAPI.servers[0]?.url + pathPrefix;
222+
serverURL = openAPI.servers?.[0]?.url + pathPrefix;
222223
}
223224

224225
if (serverURL == "" || serverURL == "undefined") {
225226
throw new Error("No server URL found in openapi, and none was provided");
226227
}
227228

228229
// Add non-resource schemas to API's schemas
229-
const schemas: Record<string, APISchema> = {};
230-
for (const [key, schema] of Object.entries(openAPI.components.schemas)) {
230+
const schemas: Record<string, Schema> = {};
231+
for (const [key, schema] of Object.entries(openAPI.components?.schemas || {})) {
231232
if (!resourceBySingular[key]) {
232233
schemas[key] = schema;
233234
}
@@ -322,7 +323,7 @@ async function getOrPopulateResource(
322323
if (schema) {
323324
if (schema["x-aep-resource"] && schema["x-aep-resource"].parents) {
324325
for (const parentSingular of schema["x-aep-resource"].parents) {
325-
const parentSchema = openAPI.components.schemas[parentSingular];
326+
const parentSchema = openAPI.components?.schemas[parentSingular];
326327
if (!parentSchema) {
327328
throw new Error(
328329
`Resource "${singular}" parent "${parentSingular}" not found`
@@ -357,7 +358,7 @@ function getContact(contact?: Contact): Contact | null {
357358
function getSchemaFromResponse(
358359
response: OpenAPIResponse,
359360
openAPI: OpenAPI
360-
): APISchema | null {
361+
): Schema | null {
361362
if (openAPI.openapi === "2.0") {
362363
return response.schema || null;
363364
}
@@ -367,17 +368,17 @@ function getSchemaFromResponse(
367368
function getSchemaFromRequestBody(
368369
requestBody: OpenAPIRequestBody,
369370
openAPI: OpenAPI
370-
): APISchema {
371+
): Schema {
371372
if (openAPI.openapi === "2.0") {
372373
return requestBody.schema!;
373374
}
374375
return requestBody.content["application/json"].schema!;
375376
}
376377

377378
async function dereferenceSchema(
378-
schema: APISchema,
379+
schema: Schema,
379380
openAPI: OpenAPI
380-
): Promise<APISchema> {
381+
): Promise<Schema> {
381382
if (!schema.$ref) {
382383
return schema;
383384
}
@@ -389,20 +390,20 @@ async function dereferenceSchema(
389390
if (!response.ok) {
390391
throw new Error(`Failed to fetch external schema: ${schema.$ref}`);
391392
}
392-
const externalSchema = await response.json() as APISchema;
393+
const externalSchema = await response.json() as Schema;
393394
logger.debug(
394395
`Final schema fetched from ${schema.$ref}: ${JSON.stringify(externalSchema)}`);
395396
return dereferenceSchema(externalSchema, openAPI);
396397
}
397398

398399
const parts = schema.$ref.split("/");
399400
const key = parts[parts.length - 1];
400-
let childSchema: APISchema;
401+
let childSchema: Schema;
401402

402403
if (openAPI.openapi === "2.0") {
403404
childSchema = openAPI.definitions![key];
404405
} else {
405-
childSchema = openAPI.components.schemas[key];
406+
childSchema = openAPI.components!.schemas[key];
406407
}
407408

408409
if (!childSchema) {

src/api/openapi.test.ts

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
import {
22
API,
3-
Contact,
4-
OpenAPI,
53
Resource,
6-
APISchema,
74
ListMethod,
85
} from "./types.js";
6+
import {
7+
Contact,
8+
OpenAPI,
9+
Schema,
10+
} from "../openapi/types.js";
911
import {
1012
convertToOpenAPI,
1113
generateParentPatternsWithParams,
@@ -132,7 +134,8 @@ describe("convertToOpenAPI", () => {
132134
// Verify basic OpenAPI structure
133135
expect(openAPI.openapi).toBe("3.1.0");
134136
expect(openAPI.info.title).toBe(exampleAPI.name);
135-
expect(openAPI.servers[0].url).toBe(exampleAPI.serverURL);
137+
expect(openAPI.servers).toBeDefined();
138+
expect(openAPI.servers![0].url).toBe(exampleAPI.serverURL);
136139

137140
// Verify Contact information
138141
if (exampleAPI.contact == null) {
@@ -156,11 +159,12 @@ describe("convertToOpenAPI", () => {
156159
}
157160

158161
// Verify schemas exist
162+
expect(openAPI.components).toBeDefined();
159163
for (const [key, resource] of Object.entries(exampleAPI.resources)) {
160-
const schema = openAPI.components.schemas[resource.singular];
164+
const schema = openAPI.components!.schemas[resource.singular];
161165
expect(schema).toBeDefined();
162166
expect(schema.type).toBe(resource.schema.type);
163-
expect(schema.xAEPResource?.singular).toBe(resource.singular);
167+
expect(schema["x-aep-resource"]?.singular).toBe(resource.singular);
164168
}
165169

166170
// Verify operations exist and have correct operationIds
@@ -209,7 +213,7 @@ describe("convertToOpenAPI", () => {
209213
name: "publisher",
210214
required: true,
211215
schema: { type: "string" },
212-
xAEPResourceRef: { resource: "publisher" },
216+
"x-aep-resource-reference": { resource: "publisher" },
213217
},
214218
{
215219
in: "query",
@@ -245,7 +249,7 @@ describe("convertToOpenAPI", () => {
245249
name: "publisher",
246250
required: true,
247251
schema: { type: "string" },
248-
xAEPResourceRef: { resource: "publisher" },
252+
"x-aep-resource-reference": { resource: "publisher" },
249253
},
250254
{
251255
name: "id",
@@ -265,7 +269,7 @@ describe("convertToOpenAPI", () => {
265269
name: "publisher",
266270
required: true,
267271
schema: { type: "string" },
268-
xAEPResourceRef: {
272+
"x-aep-resource-reference": {
269273
resource: "publisher",
270274
},
271275
},
@@ -285,7 +289,7 @@ describe("convertToOpenAPI", () => {
285289
name: "publisher",
286290
required: true,
287291
schema: { type: "string" },
288-
xAEPResourceRef: {
292+
"x-aep-resource-reference": {
289293
resource: "publisher",
290294
},
291295
},
@@ -313,7 +317,7 @@ describe("convertToOpenAPI", () => {
313317
name: "publisher",
314318
required: true,
315319
schema: { type: "string" },
316-
xAEPResourceRef: {
320+
"x-aep-resource-reference": {
317321
resource: "publisher",
318322
},
319323
},
@@ -341,7 +345,7 @@ describe("convertToOpenAPI", () => {
341345
name: "publisher",
342346
required: true,
343347
schema: { type: "string" },
344-
xAEPResourceRef: {
348+
"x-aep-resource-reference": {
345349
resource: "publisher",
346350
},
347351
},
@@ -492,7 +496,7 @@ describe("convertToOpenAPI", () => {
492496
name: "database",
493497
required: true,
494498
schema: { type: "string" },
495-
xAEPResourceRef: { resource: "database" },
499+
"x-aep-resource-reference": { resource: "database" },
496500
},
497501
],
498502
},
@@ -543,14 +547,14 @@ describe("convertToOpenAPI", () => {
543547
name: "account",
544548
required: true,
545549
schema: { type: "string" },
546-
xAEPResourceRef: { resource: "account" },
550+
"x-aep-resource-reference": { resource: "account" },
547551
},
548552
{
549553
in: "path",
550554
name: "database",
551555
required: true,
552556
schema: { type: "string" },
553-
xAEPResourceRef: { resource: "database" },
557+
"x-aep-resource-reference": { resource: "database" },
554558
},
555559
],
556560
},

0 commit comments

Comments
 (0)