Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/workflows/version.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,9 @@ jobs:
npm install --save-exact --workspace docs-example openapi-typescript-server@${{ env.PACKAGE_VERSION }} openapi-typescript-server-express@${{ env.PACKAGE_VERSION }}
npm install --save-exact --workspace docs-example openapi-typescript-server@${{ env.PACKAGE_VERSION }} openapi-typescript-server-express@${{ env.PACKAGE_VERSION }}

npm install --save-exact --workspace tags-example openapi-typescript-server@${{ env.PACKAGE_VERSION }} openapi-typescript-server-express@${{ env.PACKAGE_VERSION }}
npm install --save-exact --workspace tags-example openapi-typescript-server@${{ env.PACKAGE_VERSION }} openapi-typescript-server-express@${{ env.PACKAGE_VERSION }}

- name: Build the packages
run: npm run build:packages

Expand Down
29 changes: 29 additions & 0 deletions examples/docs/gen/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,3 +72,32 @@ export function registerRouteHandlers<Req, Res>(server: Server<Req, Res>): Route
},
]
}

export type Tag = null;

export interface ServerForUntagged<Req = unknown, Res = unknown> {
makePetSpeak: (args: MakePetSpeakArgs<Req, Res>) => MakePetSpeakResult;
uhoh: (args: UhohArgs<Req, Res>) => UhohResult;
}

export function registerRouteHandlersByTag<Req, Res>(tag: null, server: ServerForUntagged<Req, Res>): Route[];
export function registerRouteHandlersByTag<Req, Res>(tag: Tag, server: Partial<Server<Req, Res>>): Route[] {
const routes: Route[] = [];

switch (tag) {
case null:
routes.push({
method: "post",
path: "/speak/{petId}",
handler: server.makePetSpeak as Route["handler"],
});
routes.push({
method: "get",
path: "/uhoh",
handler: server.uhoh as Route["handler"],
});
break;
}

return routes;
}
59 changes: 59 additions & 0 deletions examples/kitchensink/gen/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -250,3 +250,62 @@ export function registerRouteHandlers<Req, Res>(server: Server<Req, Res>): Route
},
]
}

export type Tag = null;

export interface ServerForUntagged<Req = unknown, Res = unknown> {
listPets: (args: ListPetsArgs<Req, Res>) => ListPetsResult;
listPetsBySize: (args: ListPetsBySizeArgs<Req, Res>) => ListPetsBySizeResult;
getPetById: (args: GetPetByIdArgs<Req, Res>) => GetPetByIdResult;
updatePetWithForm: (args: UpdatePetWithFormArgs<Req, Res>) => UpdatePetWithFormResult;
mixedContentTypes: (args: MixedContentTypesArgs<Req, Res>) => MixedContentTypesResult;
getPetImage: (args: GetPetImageArgs<Req, Res>) => GetPetImageResult;
getPetWebpage: (args: GetPetWebpageArgs<Req, Res>) => GetPetWebpageResult;
}

export function registerRouteHandlersByTag<Req, Res>(tag: null, server: ServerForUntagged<Req, Res>): Route[];
export function registerRouteHandlersByTag<Req, Res>(tag: Tag, server: Partial<Server<Req, Res>>): Route[] {
const routes: Route[] = [];

switch (tag) {
case null:
routes.push({
method: "get",
path: "/pets",
handler: server.listPets as Route["handler"],
});
routes.push({
method: "get",
path: "/pets/{size}",
handler: server.listPetsBySize as Route["handler"],
});
routes.push({
method: "get",
path: "/pet/{petId}",
handler: server.getPetById as Route["handler"],
});
routes.push({
method: "post",
path: "/pet/{petId}",
handler: server.updatePetWithForm as Route["handler"],
});
routes.push({
method: "post",
path: "/pet/{petId}/mixed-content-types",
handler: server.mixedContentTypes as Route["handler"],
});
routes.push({
method: "get",
path: "/pet/{petId}/image",
handler: server.getPetImage as Route["handler"],
});
routes.push({
method: "get",
path: "/pet/{petId}/webpage",
handler: server.getPetWebpage as Route["handler"],
});
break;
}

return routes;
}
143 changes: 143 additions & 0 deletions examples/petstore/gen/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -743,3 +743,146 @@ export function registerRouteHandlers<Req, Res>(server: Server<Req, Res>): Route
},
]
}

export type Tag = "pet" | "store" | "user";

export interface ServerForPet<Req = unknown, Res = unknown> {
updatePet: (args: UpdatePetArgs<Req, Res>) => UpdatePetResult;
addPet: (args: AddPetArgs<Req, Res>) => AddPetResult;
findPetsByStatus: (args: FindPetsByStatusArgs<Req, Res>) => FindPetsByStatusResult;
findPetsByTags: (args: FindPetsByTagsArgs<Req, Res>) => FindPetsByTagsResult;
getPetById: (args: GetPetByIdArgs<Req, Res>) => GetPetByIdResult;
updatePetWithForm: (args: UpdatePetWithFormArgs<Req, Res>) => UpdatePetWithFormResult;
deletePet: (args: DeletePetArgs<Req, Res>) => DeletePetResult;
uploadFile: (args: UploadFileArgs<Req, Res>) => UploadFileResult;
}

export interface ServerForStore<Req = unknown, Res = unknown> {
getInventory: (args: GetInventoryArgs<Req, Res>) => GetInventoryResult;
placeOrder: (args: PlaceOrderArgs<Req, Res>) => PlaceOrderResult;
getOrderById: (args: GetOrderByIdArgs<Req, Res>) => GetOrderByIdResult;
deleteOrder: (args: DeleteOrderArgs<Req, Res>) => DeleteOrderResult;
}

export interface ServerForUser<Req = unknown, Res = unknown> {
createUser: (args: CreateUserArgs<Req, Res>) => CreateUserResult;
createUsersWithListInput: (args: CreateUsersWithListInputArgs<Req, Res>) => CreateUsersWithListInputResult;
loginUser: (args: LoginUserArgs<Req, Res>) => LoginUserResult;
logoutUser: (args: LogoutUserArgs<Req, Res>) => LogoutUserResult;
getUserByName: (args: GetUserByNameArgs<Req, Res>) => GetUserByNameResult;
updateUser: (args: UpdateUserArgs<Req, Res>) => UpdateUserResult;
deleteUser: (args: DeleteUserArgs<Req, Res>) => DeleteUserResult;
}

export function registerRouteHandlersByTag<Req, Res>(tag: "pet", server: ServerForPet<Req, Res>): Route[];
export function registerRouteHandlersByTag<Req, Res>(tag: "store", server: ServerForStore<Req, Res>): Route[];
export function registerRouteHandlersByTag<Req, Res>(tag: "user", server: ServerForUser<Req, Res>): Route[];
export function registerRouteHandlersByTag<Req, Res>(tag: Tag, server: Partial<Server<Req, Res>>): Route[] {
const routes: Route[] = [];

switch (tag) {
case "pet":
routes.push({
method: "put",
path: "/pet",
handler: server.updatePet as Route["handler"],
});
routes.push({
method: "post",
path: "/pet",
handler: server.addPet as Route["handler"],
});
routes.push({
method: "get",
path: "/pet/findByStatus",
handler: server.findPetsByStatus as Route["handler"],
});
routes.push({
method: "get",
path: "/pet/findByTags",
handler: server.findPetsByTags as Route["handler"],
});
routes.push({
method: "get",
path: "/pet/{petId}",
handler: server.getPetById as Route["handler"],
});
routes.push({
method: "post",
path: "/pet/{petId}",
handler: server.updatePetWithForm as Route["handler"],
});
routes.push({
method: "delete",
path: "/pet/{petId}",
handler: server.deletePet as Route["handler"],
});
routes.push({
method: "post",
path: "/pet/{petId}/uploadImage",
handler: server.uploadFile as Route["handler"],
});
break;
case "store":
routes.push({
method: "get",
path: "/store/inventory",
handler: server.getInventory as Route["handler"],
});
routes.push({
method: "post",
path: "/store/order",
handler: server.placeOrder as Route["handler"],
});
routes.push({
method: "get",
path: "/store/order/{orderId}",
handler: server.getOrderById as Route["handler"],
});
routes.push({
method: "delete",
path: "/store/order/{orderId}",
handler: server.deleteOrder as Route["handler"],
});
break;
case "user":
routes.push({
method: "post",
path: "/user",
handler: server.createUser as Route["handler"],
});
routes.push({
method: "post",
path: "/user/createWithList",
handler: server.createUsersWithListInput as Route["handler"],
});
routes.push({
method: "get",
path: "/user/login",
handler: server.loginUser as Route["handler"],
});
routes.push({
method: "get",
path: "/user/logout",
handler: server.logoutUser as Route["handler"],
});
routes.push({
method: "get",
path: "/user/{username}",
handler: server.getUserByName as Route["handler"],
});
routes.push({
method: "put",
path: "/user/{username}",
handler: server.updateUser as Route["handler"],
});
routes.push({
method: "delete",
path: "/user/{username}",
handler: server.deleteUser as Route["handler"],
});
break;
}

return routes;
}
125 changes: 125 additions & 0 deletions examples/tags/api.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
import type * as ServerTypes from "./gen/server.ts";
import type { Request, Response } from "express";

// Service implementation for "pets" tag
export const petsService: ServerTypes.ServerForPets<Request, Response> = {
listPets: async (): ServerTypes.ListPetsResult => {
return {
content: {
200: {
"application/json": {
pets: [
{ id: 1, name: "dog" },
{ id: 2, name: "cat" },
],
},
},
},
};
},

getPetById: async ({ parameters }): ServerTypes.GetPetByIdResult => {
if (parameters.path.petId === 42) {
return {
content: {
default: {
"application/json": {
message: "Cannot get that pet",
},
},
},
status: 503,
};
}

if (parameters.path.petId === 500) {
throw new Error("Cannot get that pet");
}

return {
content: {
200: {
"application/json": {
pet: { id: parameters.path.petId, name: "dog" },
},
},
},
};
},

updatePetWithForm: async ({
parameters,
requestBody,
}): ServerTypes.UpdatePetWithFormResult => {
const { petId } = parameters.path;
const { name } = parameters.query ?? {};
const { status } = requestBody.content;

return {
content: {
200: {
"application/json": {
pet: { id: petId, name: name || "dog", status },
},
},
},
};
},
};

// Service implementation for "store" tag
export const storeService: ServerTypes.ServerForStore<Request, Response> = {
getInventory: async (): ServerTypes.GetInventoryResult => {
return {
content: {
200: {
"application/json": {
inventory: {
available: 10,
pending: 5,
sold: 3,
},
},
},
},
};
},

placeOrder: async ({ requestBody }): ServerTypes.PlaceOrderResult => {
const { petId, quantity } = requestBody.content;

return {
content: {
200: {
"application/json": {
order: {
id: Math.floor(Math.random() * 1000),
petId,
quantity,
status: "placed",
},
},
},
},
};
},
};

// Service implementation for untagged operations
export const untaggedService: ServerTypes.ServerForUntagged<Request, Response> =
{
listUsers: async (): ServerTypes.ListUsersResult => {
return {
content: {
200: {
"application/json": {
users: [
{ id: 1, username: "john_doe", email: "john@example.com" },
{ id: 2, username: "jane_smith", email: "jane@example.com" },
],
},
},
},
};
},
};
Loading