From d2f1d2e484242d3867c8a399b79ca68dd30254c7 Mon Sep 17 00:00:00 2001 From: meglerhagen Date: Mon, 29 Jul 2024 21:52:18 +0200 Subject: [PATCH] added openapi --- apps/api/src/validators/index.ts | 259 +++++++++++++++++----------- apps/api/src/validators/openapi.yml | 129 ++++++++++++++ apps/api/src/validators/types.ts | 44 +++-- 3 files changed, 313 insertions(+), 119 deletions(-) create mode 100644 apps/api/src/validators/openapi.yml diff --git a/apps/api/src/validators/index.ts b/apps/api/src/validators/index.ts index 5f4def89..81168670 100644 --- a/apps/api/src/validators/index.ts +++ b/apps/api/src/validators/index.ts @@ -1,138 +1,195 @@ -import { OpenAPIHono, z } from "@hono/zod-openapi"; -import * as yaml from "yaml"; +import { OpenAPIHono, z } from "@hono/zod-openapi" +import * as yaml from "yaml" import { createDocument, extendZodWithOpenApi, ZodOpenApiOperationObject, -} from "zod-openapi"; +} from "zod-openapi" -extendZodWithOpenApi(z); +extendZodWithOpenApi(z) -const app = new OpenAPIHono(); -const registry = app.openAPIRegistry; +const app = new OpenAPIHono() +const registry = app.openAPIRegistry -// Define the Event Schema with detailed OpenAPI extensions -export const EventSchema = z +// User Schema +const UserSchema = z .object({ - name: z.string().openapi({ - description: "The name of the event.", - example: "Annual Meetup", - }), - channel: z.string().openapi({ - description: "The channel name associated with the event.", - example: "Main Channel", - }), - userId: z.string().openapi({ - description: "Associated ID that you want to have on the user", - example: "user999 OR John Doe", - }), - icon: z.string().optional().openapi({ - description: "An optional icon for visual representation of the event.", - example: "icon_event.png", - }), - notify: z.boolean().openapi({ - description: - "Flag indicating whether users should be notified about the event.", - example: true, - }), - tags: z - .record(z.string()) - .optional() - .openapi({ - description: - "Tags providing additional context or categorization for the event.", - example: { Networking: "Yes", Tech: "Yes" }, - }), + id: z.number(), + email: z.string().email(), + workspaceId: z.string().nullable(), + apiKey: z.string(), }) - .openapi({ ref: "Event" }); + .openapi({ ref: "User" }) -// Schema for creating an event -export const EventCreateSchema = z +// Property Schema +const PropertySchema = z .object({ - name: z.string().openapi({ - description: "The name of the event.", - example: "You got a new payment", - }), - channel: z.string().openapi({ - description: "The channel name where the event is registered.", - example: "new-channel-name", - }), - userId: z.string().openapi({ - description: "The ID of the user associated with the event.", - example: "user-999", - }), - icon: z.string().optional().openapi({ - description: "An optional icon representing the event.", - example: "🎉", - }), - notify: z.boolean().openapi({ - description: "Whether to notify users about the event.", - example: true, - }), - tags: z - .record(z.string()) - .optional() - .openapi({ - description: "Additional tags providing context for the event.", - example: { plan: "premium", cycle: "monthly" }, - }), + id: z.string(), + name: z.string(), + type: z.string(), + workspaceId: z.string(), }) - .openapi({ ref: "EventCreate" }); + .openapi({ ref: "Property" }) -// CRUD operations for Events -export const logEvent: ZodOpenApiOperationObject = { - operationId: "logEvent", - summary: "Log a new event", - description: "Logs a new event for a user in a specified channel.", +// Building Schema +const BuildingSchema = z + .object({ + id: z.string(), + propertyId: z.string(), + // Add other relevant fields based on your application's needs + }) + .openapi({ ref: "Building" }) + +// Property Create Schema +const PropertyCreateSchema = z + .object({ + name: z.string(), + type: z.string(), + }) + .openapi({ ref: "PropertyCreate" }) + +// Building Create Schema +const BuildingCreateSchema = z + .object({ + propertyId: z.string(), + // Add other relevant fields based on your application's needs + }) + .openapi({ ref: "BuildingCreate" }) + +// CRUD operations for Properties +const createProperty: ZodOpenApiOperationObject = { + operationId: "createProperty", + summary: "Create a new property", requestBody: { - description: "Details of the event to log.", content: { "application/json": { - schema: EventCreateSchema, + schema: PropertyCreateSchema, }, }, }, responses: { "201": { - description: "Event logged successfully.", + description: "Property created successfully.", content: { "application/json": { - schema: EventSchema, + schema: PropertySchema, }, }, }, - "404": { - description: "Channel or project not found.", - }, "400": { description: "Invalid input data.", }, + "500": { + description: "Server error.", + }, }, -}; +} -// Generate an OpenAPI document -const document = createDocument({ - openapi: "3.1.0", - info: { - title: "User and Event Management API", - description: "API for managing users, their events, and projects.", - version: "1.0.0", +const getAllProperties: ZodOpenApiOperationObject = { + operationId: "getAllProperties", + summary: "Get all properties for a workspace", + responses: { + "200": { + description: "List of properties retrieved successfully.", + content: { + "application/json": { + schema: z.array(PropertySchema), + }, + }, + }, + "500": { + description: "Server error.", + }, }, - servers: [ - { - url: "https://example.com", - description: "The production server.", +} + +// CRUD operations for Buildings +const createBuilding: ZodOpenApiOperationObject = { + operationId: "createBuilding", + summary: "Create a new building", + requestBody: { + content: { + "application/json": { + schema: BuildingCreateSchema, + }, + }, + }, + responses: { + "201": { + description: "Building created successfully.", + content: { + "application/json": { + schema: BuildingSchema, + }, + }, + }, + "400": { + description: "Invalid input data.", + }, + "500": { + description: "Server error.", }, - ], - paths: { - "/events": { post: logEvent }, }, - components: { - schemas: { - Event: EventSchema, - EventCreate: EventCreateSchema, +} + +const getAllBuildings: ZodOpenApiOperationObject = { + operationId: "getAllBuildings", + summary: "Get all buildings for a workspace", + responses: { + "200": { + description: "List of buildings retrieved successfully.", + content: { + "application/json": { + schema: z.array(BuildingSchema), + }, + }, + }, + "500": { + description: "Server error.", }, }, -}); +} -console.log(yaml.stringify(document)); +// Generate an OpenAPI document +export function generateOpenAPIDocument() { + return createDocument({ + openapi: "3.1.0", + info: { + title: "Propdock API", + description: "API for managing properties and buildings.", + version: "1.0.0", + }, + servers: [ + { + url: "https://api.vegard.workers.dev", + description: "Production server.", + }, + ], + paths: { + "/properties": { + post: createProperty, + get: getAllProperties, + }, + "/buildings": { + post: createBuilding, + get: getAllBuildings, + }, + }, + components: { + schemas: { + User: UserSchema, + Property: PropertySchema, + Building: BuildingSchema, + PropertyCreate: PropertyCreateSchema, + BuildingCreate: BuildingCreateSchema, + }, + securitySchemes: { + Bearer: { + type: "http", + scheme: "bearer", + }, + }, + }, + security: [{ Bearer: [] }], + }) +} diff --git a/apps/api/src/validators/openapi.yml b/apps/api/src/validators/openapi.yml new file mode 100644 index 00000000..6ac97aea --- /dev/null +++ b/apps/api/src/validators/openapi.yml @@ -0,0 +1,129 @@ +openapi: 3.1.0 +info: + title: Propdock API + description: API for managing properties and buildings. + version: 1.0.0 +servers: + - url: https://api.vegard.workers.dev + description: Production server. +paths: + /properties: + post: + operationId: createProperty + summary: Create a new property + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/PropertyCreate" + responses: + "201": + description: Property created successfully. + content: + application/json: + schema: + $ref: "#/components/schemas/Property" + "400": + description: Invalid input data. + "500": + description: Server error. + get: + operationId: getAllProperties + summary: Get all properties for a workspace + responses: + "200": + description: List of properties retrieved successfully. + content: + application/json: + schema: + type: array + items: + $ref: "#/components/schemas/Property" + "500": + description: Server error. + /buildings: + post: + operationId: createBuilding + summary: Create a new building + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/BuildingCreate" + responses: + "201": + description: Building created successfully. + content: + application/json: + schema: + $ref: "#/components/schemas/Building" + "400": + description: Invalid input data. + "500": + description: Server error. + get: + operationId: getAllBuildings + summary: Get all buildings for a workspace + responses: + "200": + description: List of buildings retrieved successfully. + content: + application/json: + schema: + type: array + items: + $ref: "#/components/schemas/Building" + "500": + description: Server error. +components: + schemas: + User: + type: object + properties: + id: + type: number + email: + type: string + format: email + workspaceId: + type: string + nullable: true + apiKey: + type: string + Property: + type: object + properties: + id: + type: string + name: + type: string + type: + type: string + workspaceId: + type: string + Building: + type: object + properties: + id: + type: string + propertyId: + type: string + PropertyCreate: + type: object + properties: + name: + type: string + type: + type: string + BuildingCreate: + type: object + properties: + propertyId: + type: string + securitySchemes: + ApiKeyAuth: + type: apiKey + in: header + name: x-api-key +security: + - ApiKeyAuth: [] diff --git a/apps/api/src/validators/types.ts b/apps/api/src/validators/types.ts index 9e452396..e099ca51 100644 --- a/apps/api/src/validators/types.ts +++ b/apps/api/src/validators/types.ts @@ -1,20 +1,28 @@ -// interface User { -// workspaceId: any; -// id: number; -// name?: string; -// email: string; -// plan: string; -// events: Event[]; -// createdAt: Date; -// } +interface User { + id: number + email: string + workspaceId: string | null + apiKey: string +} + +interface Property { + id: string + name: string + type: string + workspaceId: string +} + +interface Building { + id: string + propertyId: string + // Add other relevant fields based on your application's needs +} + +interface Env { + // Add environment-specific properties here +} -interface Event { - id: number; - channel: string; - event: string; - userId: number; - icon: string; - notify: boolean; - tags: Record; - createdAt: Date; +interface CustomContext { + user?: User + test?: boolean }