Skip to content

Commit

Permalink
Add requestFormat in endpoint schemas (#48)
Browse files Browse the repository at this point in the history
  • Loading branch information
aharisu authored Aug 16, 2024
1 parent 803aaae commit 7806860
Show file tree
Hide file tree
Showing 24 changed files with 910 additions and 1 deletion.
4 changes: 4 additions & 0 deletions packages/typed-openapi/src/generator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ const generateEndpointSchemaList = (ctx: GeneratorContext) => {
file += `export type ${endpoint.meta.alias} = {
method: "${endpoint.method.toUpperCase()}",
path: "${endpoint.path}",
requestFormat: "${endpoint.requestFormat}",
${
endpoint.meta.hasParameters
? `parameters: {
Expand Down Expand Up @@ -235,6 +236,8 @@ export type EndpointParameters = {
export type MutationMethod = "post" | "put" | "patch" | "delete";
export type Method = "get" | "head" | MutationMethod;
type RequestFormat = "json" | "form-data" | "form-url" | "binary" | "text";
export type DefaultEndpoint = {
parameters?: EndpointParameters | undefined;
response: unknown;
Expand All @@ -244,6 +247,7 @@ export type Endpoint<TConfig extends DefaultEndpoint = DefaultEndpoint> = {
operationId: string;
method: Method;
path: string;
requestFormat: RequestFormat;
parameters?: TConfig["parameters"];
meta: {
alias: string;
Expand Down
16 changes: 15 additions & 1 deletion packages/typed-openapi/src/map-openapi-endpoints.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { createRefResolver } from "./ref-resolver";
import { tsFactory } from "./ts-factory";
import { AnyBox, BoxRef, OpenapiSchemaConvertContext } from "./types";
import { pathToVariableName } from "./string-utils";
import { match, P } from "ts-pattern";

const factory = tsFactory;

Expand All @@ -25,6 +26,7 @@ export const mapOpenApiEndpoints = (doc: OpenAPIObject) => {
operation,
method: method as Method,
path,
requestFormat: "json",
response: openApiSchemaToTs({ schema: {}, ctx }),
meta: {
alias: getAlias({ path, method, operation } as Endpoint),
Expand Down Expand Up @@ -83,12 +85,21 @@ export const mapOpenApiEndpoints = (doc: OpenAPIObject) => {
ctx,
});
}

endpoint.requestFormat = match(matchingMediaType)
.with("application/octet-stream", () => "binary" as const)
.with("multipart/form-data", () => "form-data" as const)
.with("application/x-www-form-urlencoded", () => "form-url" as const)
.with(P.string.includes("json"), () => "json" as const)
.otherwise(() => "text" as const);
}

// Make parameters optional if all or some of them are not required
if (params) {
const t = createBoxFactory({}, ctx);
const filtered_params = ["query", "path", "header"] as Array<keyof Pick<typeof params, "query" | "path" | "header">>;
const filtered_params = ["query", "path", "header"] as Array<
keyof Pick<typeof params, "query" | "path" | "header">
>;

for (const k of filtered_params) {
if (params[k] && lists[k].length) {
Expand Down Expand Up @@ -165,6 +176,8 @@ export type EndpointParameters = {
path?: Box<BoxRef> | Record<string, AnyBox>;
};

type RequestFormat = "json" | "form-data" | "form-url" | "binary" | "text";

type DefaultEndpoint = {
parameters?: EndpointParameters | undefined;
response: AnyBox;
Expand All @@ -175,6 +188,7 @@ export type Endpoint<TConfig extends DefaultEndpoint = DefaultEndpoint> = {
method: Method;
path: string;
parameters?: TConfig["parameters"];
requestFormat: RequestFormat;
meta: {
alias: string;
hasParameters: boolean;
Expand Down
22 changes: 22 additions & 0 deletions packages/typed-openapi/tests/generator.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ describe("generator", () => {
export type put_UpdatePet = {
method: "PUT";
path: "/pet";
requestFormat: "json";
parameters: {
body: Schemas.Pet;
};
Expand All @@ -59,6 +60,7 @@ describe("generator", () => {
export type post_AddPet = {
method: "POST";
path: "/pet";
requestFormat: "json";
parameters: {
body: Schemas.Pet;
};
Expand All @@ -67,6 +69,7 @@ describe("generator", () => {
export type get_FindPetsByStatus = {
method: "GET";
path: "/pet/findByStatus";
requestFormat: "json";
parameters: {
query: Partial<{ status: "available" | "pending" | "sold" }>;
};
Expand All @@ -75,6 +78,7 @@ describe("generator", () => {
export type get_FindPetsByTags = {
method: "GET";
path: "/pet/findByTags";
requestFormat: "json";
parameters: {
query: Partial<{ tags: Array<string> }>;
};
Expand All @@ -83,6 +87,7 @@ describe("generator", () => {
export type get_GetPetById = {
method: "GET";
path: "/pet/{petId}";
requestFormat: "json";
parameters: {
path: { petId: number };
};
Expand All @@ -91,6 +96,7 @@ describe("generator", () => {
export type post_UpdatePetWithForm = {
method: "POST";
path: "/pet/{petId}";
requestFormat: "json";
parameters: {
query: Partial<{ name: string; status: string }>;
path: { petId: number };
Expand All @@ -100,6 +106,7 @@ describe("generator", () => {
export type delete_DeletePet = {
method: "DELETE";
path: "/pet/{petId}";
requestFormat: "json";
parameters: {
path: { petId: number };
header: Partial<{ api_key: string }>;
Expand All @@ -109,6 +116,7 @@ describe("generator", () => {
export type post_UploadFile = {
method: "POST";
path: "/pet/{petId}/uploadImage";
requestFormat: "binary";
parameters: {
query: Partial<{ additionalMetadata: string }>;
path: { petId: number };
Expand All @@ -120,12 +128,14 @@ describe("generator", () => {
export type get_GetInventory = {
method: "GET";
path: "/store/inventory";
requestFormat: "json";
parameters: never;
response: unknown;
};
export type post_PlaceOrder = {
method: "POST";
path: "/store/order";
requestFormat: "json";
parameters: {
body: Schemas.Order;
};
Expand All @@ -134,6 +144,7 @@ describe("generator", () => {
export type get_GetOrderById = {
method: "GET";
path: "/store/order/{orderId}";
requestFormat: "json";
parameters: {
path: { orderId: number };
};
Expand All @@ -142,6 +153,7 @@ describe("generator", () => {
export type delete_DeleteOrder = {
method: "DELETE";
path: "/store/order/{orderId}";
requestFormat: "json";
parameters: {
path: { orderId: number };
};
Expand All @@ -150,6 +162,7 @@ describe("generator", () => {
export type post_CreateUser = {
method: "POST";
path: "/user";
requestFormat: "json";
parameters: {
body: Schemas.User;
};
Expand All @@ -158,6 +171,7 @@ describe("generator", () => {
export type post_CreateUsersWithListInput = {
method: "POST";
path: "/user/createWithList";
requestFormat: "json";
parameters: {
body: Array<Schemas.User>;
};
Expand All @@ -166,6 +180,7 @@ describe("generator", () => {
export type get_LoginUser = {
method: "GET";
path: "/user/login";
requestFormat: "json";
parameters: {
query: Partial<{ username: string; password: string }>;
};
Expand All @@ -174,12 +189,14 @@ describe("generator", () => {
export type get_LogoutUser = {
method: "GET";
path: "/user/logout";
requestFormat: "json";
parameters: never;
response: unknown;
};
export type get_GetUserByName = {
method: "GET";
path: "/user/{username}";
requestFormat: "json";
parameters: {
path: { username: string };
};
Expand All @@ -188,6 +205,7 @@ describe("generator", () => {
export type put_UpdateUser = {
method: "PUT";
path: "/user/{username}";
requestFormat: "json";
parameters: {
path: { username: string };
Expand All @@ -198,6 +216,7 @@ describe("generator", () => {
export type delete_DeleteUser = {
method: "DELETE";
path: "/user/{username}";
requestFormat: "json";
parameters: {
path: { username: string };
};
Expand Down Expand Up @@ -259,6 +278,8 @@ describe("generator", () => {
export type MutationMethod = "post" | "put" | "patch" | "delete";
export type Method = "get" | "head" | MutationMethod;
type RequestFormat = "json" | "form-data" | "form-url" | "binary" | "text";
export type DefaultEndpoint = {
parameters?: EndpointParameters | undefined;
response: unknown;
Expand All @@ -268,6 +289,7 @@ describe("generator", () => {
operationId: string;
method: Method;
path: string;
requestFormat: RequestFormat;
parameters?: TConfig["parameters"];
meta: {
alias: string;
Expand Down
Loading

0 comments on commit 7806860

Please sign in to comment.