asteasolutions / zod-to-openapi

A library that generates OpenAPI (Swagger) docs from Zod schemas
MIT License
992 stars 60 forks source link

Extract param defined schemas into component.parameters automatically #272

Open artsiommiksiuk opened 1 day ago

artsiommiksiuk commented 1 day ago

Having path parameter defined like this

export const UserIdPathParameter = z.string().uuid()
    .openapi("UserId", {
        param: { in: "path", name: "userId" },
        description: "User Id"
    });

And having operation defined like this:

const agentQueryOrganizations = (): RouteConfig => ({
    summary: "Query for user's organizations",
    tags,
    method: "get",
    operationId: "queryUserOrganizations",
    path: "/users/{userId}/organizations",
    request: {
        params: z.object({
            userId: UserIdPathParameter
        }),
    },
    responses: {
        ...defaultResponses,
        "200": makeRESTQueryJSONResponseZ(PublicOrganizationSchema, "Organizations"),
    }
});

I'd expect a params parameter be fully extracted into component.parameters section. But rn I'm getting this:

info:
  version: 1.0.0
openapi: 3.0.0
security: []
components:
  schemas:
    Name:
      type: string
      minLength: 1
      maxLength: 256
    UserId:
      type: string
      format: uuid
      description: User Id
  parameters: {}
paths:
  /users/{userId}/organizations:
    get:
      summary: Query for user's organizations
      tags:
        - organization
      operationId: queryUserOrganizations
      parameters:
        - schema:
            $ref: "#/components/schemas/UserId"
          required: true
          in: path
          name: userId
      responses:
        "200":
        ...

Current proposed approach (register it manually in registry), is quite cumbersome, as I'll have to fight with either circular dependencies or wrap all API construction layer into functions in order to properly path registry and resulting UserId parameter schema for later referencing.

We have all the information necessary to make unbound decision on how to inject parameter into component parameters schema. I'd like it to be so, that if schema definition (openapi call specifically), contains param property and have defined name, that this schema be extracted into component.parameters group, instead of just schema. If there are some obstacles with that, we can add externalParam: bool prop to explicitly say to extract it. This is less ideal and will be inconsistent with the rest of the library, thoug.

artsiommiksiuk commented 1 day ago

To clarify a bit, so I'm expecting to have this output:

info:
  version: 1.0.0
openapi: 3.0.0
security: []
components:
  schemas:
    Name:
      type: string
      minLength: 1
      maxLength: 256
  parameters: 
    UserId: 
      schema:
        type: string
        format: uuid
        description: User Id
      required: true
      in: path
      name: userId
paths:
  /users/{userId}/organizations:
    get:
      summary: Query for user's organizations
      tags:
        - organization
      operationId: queryUserOrganizations
      parameters:
        - $ref: "#/components/parameters/UserId"
      responses:
        "200":
        ...