-
-
Notifications
You must be signed in to change notification settings - Fork 4
Closed
Labels
Description
When a middleware is defined in defineRoute
, the route is no longer generated in the Open API JSON.
@omermecitoglu same problem for me but I use
route.ts
Despite my defineRoute that I created on
/app/api/v1/orders/route.ts
, the route doesn't appear in the swagger specs... (I'm on Next.js 14.2.15)An example :
// app/api/v1/orders/route.ts import { NextResponse } from "next/server"; import { createWCOrder } from "~/actions/woocommerce/orders/orders"; import { CreateOrderDTO } from "~/actions/woocommerce/orders/orders.schema"; import { validateApiKey } from "~/lib/api"; import defineRoute from "@omer-x/next-openapi-route-handler"; import { z } from "zod"; export const { POST } = defineRoute({ operationId: "createOrder", method: "POST", summary: "Create a new order", description: "Create a new order from your store", tags: ["Orders"], requestBody: CreateOrderDTO, middleware: (handler) => async (req, context) => { const { userId } = await validateApiKey({ req }); if (!userId) { return NextResponse.json({ message: "Unauthorized" }, { status: 401 }); } return handler(req, context); }, action: async ({ body }) => { const orderCreatedData = await createWCOrder(body); return NextResponse.json(orderCreatedData, { status: 201 }); }, responses: { 200: { description: "Order created successfully", }, 401: { description: "Unauthorized", }, 400: { description: "Invalid request", }, 500: { description: "Error creating order", }, }, handleErrors: (errorType, issues) => { switch (errorType) { case "PARSE_FORM_DATA": case "PARSE_REQUEST_BODY": case "PARSE_SEARCH_PARAMS": return NextResponse.json(issues, { status: 400 }); case "PARSE_PATH_PARAMS": return new Response(null, { status: 404 }); case "UNNECESSARY_PATH_PARAMS": case "UNKNOWN_ERROR": return new Response("Error creating order", { status: 500 }); default: return new Response(null, { status: 500 }); } }, });// components/ReactSwagger.tsx "use client"; import SwaggerUI from "swagger-ui-react"; import "swagger-ui-react/swagger-ui.css"; const DocsPage = () => <SwaggerUI url="/api/swagger" />; export default DocsPage;// app/api/docs/page.tsx import ReactSwagger from "~/components/ReactSwagger"; export default async function APIDocsPage() { return <ReactSwagger />; }// app/api/swagger/route.ts import generateOpenApiSpec from "@omer-x/next-openapi-json-generator"; import { CreateOrderDTO } from "~/actions/woocommerce/orders/orders.schema"; export const dynamic = "force-static"; async function GET() { const spec = await generateOpenApiSpec( { CreateOrderDTO, }, { clearUnusedSchemas: false, securitySchemes: { apiKey: { type: "apiKey", in: "header", name: "X-API-Key", }, }, }, ); return Response.json(spec); } export { GET };JSON generated on
http://localhost:3000/api/swagger
:{ "openapi": "3.1.0", "info": { "title": "Test", "version": "0.1.0" }, "paths": { }, "components": { "schemas": { "CreateOrderDTO": { "type": "object", "properties": { "payment_method": { "type": "string" }, "payment_method_title": { "type": "string" }, "set_paid": { "type": "boolean" }, "billing": { "type": "object", "properties": { "first_name": { "type": "string" }, "last_name": { "type": "string" }, "address_1": { "type": "string" }, "address_2": { "type": "string" }, "city": { "type": "string" }, "postcode": { "type": "string" }, "country": { "type": "string" }, "state": { "type": "string" }, "email": { "type": "string", "format": "email" }, "phone": { "type": "string" } }, "required": [ "first_name", "last_name", "address_1", "city", "postcode", "country", "email" ], "additionalProperties": false }, "shipping": { "type": "object", "properties": { "first_name": { "type": "string" }, "last_name": { "type": "string" }, "address_1": { "type": "string" }, "address_2": { "type": "string" }, "city": { "type": "string" }, "postcode": { "type": "string" }, "country": { "type": "string" }, "state": { "type": "string" }, "email": { "type": "string", "format": "email" }, "phone": { "type": "string" } }, "required": [ "first_name", "last_name", "address_1", "city", "postcode", "country" ], "additionalProperties": false }, "shipping_method": { "type": "object", "properties": { "carrier": { "type": "string", "enum": [ "mondial_relay", "colissimo" ] }, "shipping_point": { "type": "object", "properties": { "country": { "type": "string", "minLength": 2, "maxLength": 2 }, "address": { "type": "string" }, "postal_code": { "type": "string" }, "city": { "type": "string" } }, "required": [ "country", "address" ], "additionalProperties": false }, "total": { "type": "string" } }, "required": [ "carrier", "total" ], "additionalProperties": false }, "line_items": { "type": "array", "items": { "type": "object", "properties": { "product_id": { "type": "number" }, "quantity": { "type": "number" }, "name": { "type": "string" }, "subtotal": { "type": "string" }, "total": { "type": "string" } }, "required": [ "product_id", "quantity" ], "additionalProperties": false } } }, "required": [ "payment_method", "payment_method_title", "set_paid", "billing", "shipping", "shipping_method", "line_items" ], "additionalProperties": false } }, "securitySchemes": { "apiKey": { "type": "apiKey", "in": "header", "name": "X-API-Key" } } }, "tags": [] }
Originally posted by @btnalexandre in #20