Skip to content

Add OpenAPI documentation with Swagger UI for tRPC API#49

Closed
Copilot wants to merge 4 commits intomainfrom
copilot/add-open-api-documentation
Closed

Add OpenAPI documentation with Swagger UI for tRPC API#49
Copilot wants to merge 4 commits intomainfrom
copilot/add-open-api-documentation

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Nov 27, 2025

Adds OpenAPI 3.1 documentation for the tRPC API with an interactive Swagger UI at /api-docs.

Schema Documentation

  • Added .describe() to all Zod schemas in packages/schemas/src/ for field-level API documentation

OpenAPI Specification

  • Static OpenAPI document at packages/api/src/openapi.ts documenting all endpoints
  • Uses tRPC dot-path convention (e.g., /health.ping, /sshKeys.list)
  • Documents superjson input encoding: JSON query params for GET, JSON body for POST

Swagger UI

  • Interactive docs page at /api-docs using swagger-ui-dist
  • OpenAPI spec served at /api/docs/openapi.json
// Example documented schema
export const createServerSchema = z
    .object({
        name: z.string().describe('Display name for the server'),
        hostname: z.string().describe('Hostname or IP address'),
        port: z.number().describe('SSH port number (typically 22)'),
        user: z.string().describe('SSH username for server access'),
        SSHKeyId: z.string().describe('ID of the SSH key for authentication'),
    })
    .describe('Schema for creating a new server connection');

Notes

Used static OpenAPI document rather than trpc-to-openapi dynamic generation because tRPC uses superjson transformer and Prisma return types are complex to express as Zod output schemas.

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • checkpoint.prisma.io
    • Triggering command: /usr/local/bin/node /usr/local/bin/node /home/REDACTED/work/sea-stack-app/sea-stack-app/node_modules/.pnpm/prisma@6.19.0_typescript@5.9.3/node_modules/prisma/build/child {"product":"prisma","version":"6.19.0","cli_install_type":"local","information":"","local_timestamp":"2025-11-27T02:17:20Z","project_hash":"c1ed741a","cli_path":"/home/REDACTED/work/sea-stack-app/sea-stack-app/packages/db/node_modules/prisma/build/index.js" (dns block)
    • Triggering command: /usr/local/bin/node /usr/local/bin/node /home/REDACTED/work/sea-stack-app/sea-stack-app/node_modules/.pnpm/prisma@6.19.0_typescript@5.9.3/node_modules/prisma/build/child {"product":"prisma","version":"6.19.0","cli_install_type":"local","information":"","local_timestamp":"2025-11-27T02:37:05Z","project_hash":"c1ed741a","cli_path":"/home/REDACTED/work/sea-stack-app/sea-stack-app/packages/db/node_modules/prisma/build/index.js" (dns block)
  • https://api.github.com//advisories
    • Triggering command: /home/REDACTED/work/_temp/ghcca-node/node/bin/node /home/REDACTED/work/_temp/ghcca-node/node/bin/node --enable-source-maps /home/REDACTED/work/_temp/copilot-developer-action-main/dist/index.js (http block)

If you need me to access, download, or install something from one of these locations, you can either:

Original prompt

Add open api documentation support on the tRPC router
Add documentation on existing endpoints
Add documentation on existing schemas
Add a swagger to test the api


✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Nov 27, 2025

Important

Review skipped

Bot user detected.

To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.


Comment @coderabbitai help to get the list of available commands and usage tips.

Copilot AI and others added 3 commits November 27, 2025 02:36
Co-authored-by: SimonLoir <17649337+SimonLoir@users.noreply.github.com>
Co-authored-by: SimonLoir <17649337+SimonLoir@users.noreply.github.com>
Co-authored-by: SimonLoir <17649337+SimonLoir@users.noreply.github.com>
Copilot AI changed the title [WIP] Add Open API documentation support on tRPC router Add OpenAPI documentation with Swagger UI for tRPC API Nov 27, 2025
Copilot AI requested a review from SimonLoir November 27, 2025 02:50
@SimonLoir SimonLoir marked this pull request as ready for review November 27, 2025 11:05
Copilot AI review requested due to automatic review settings November 27, 2025 11:05
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds comprehensive OpenAPI 3.1 documentation for the tRPC API with an interactive Swagger UI interface at /api-docs. It includes field-level documentation for all Zod schemas and a manually maintained static OpenAPI specification document (chosen over auto-generation due to superjson transformation and Prisma type complexity).

  • Added .describe() calls to all Zod schemas across 10 schema files for field-level documentation
  • Created static OpenAPI 3.1 specification in packages/api/src/openapi.ts documenting all endpoints with tRPC dot-path convention
  • Implemented Swagger UI page at /api-docs with dynamic JavaScript and CSS loading from swagger-ui-dist package

Reviewed changes

Copilot reviewed 17 out of 18 changed files in this pull request and generated 14 comments.

Show a summary per file
File Description
pnpm-lock.yaml Added dependencies: swagger-ui-dist@5.30.3 for UI and openapi3-ts@4.5.0 for TypeScript types
packages/schemas/src/volumes.ts Added descriptions to volume schemas including volumeId, volume name, mount path, and readOnly fields
packages/schemas/src/sshKeys.ts Added descriptions to SSH key schemas including key creation, identification, and update operations
packages/schemas/src/services.ts Added descriptions to service schemas for Docker Swarm service management and network operations
packages/schemas/src/servers.ts Added descriptions to server schemas for SSH connection configuration
packages/schemas/src/registries.ts Added descriptions to container registry schemas for authentication and registry management
packages/schemas/src/projects.ts Added descriptions to project schemas for project identification and creation
packages/schemas/src/notifications.ts Added descriptions to notification provider schemas including Discord webhooks
packages/schemas/src/networks.ts Added descriptions to Docker network schemas including driver types, subnet, and gateway configuration
packages/schemas/src/environment-variables.ts Added descriptions for environment variable schemas in KEY=VALUE format
packages/schemas/src/domains.ts Added descriptions to domain routing schemas including FQDN validation and port configuration
packages/schemas/src/deployments.ts Added description to deployment identification schema
packages/api/src/openapi.ts Created comprehensive static OpenAPI 3.1 document with 40+ endpoint definitions using tRPC conventions
packages/api/src/index.ts Exported openApiDocument for use in web application
packages/api/package.json Added openapi3-ts dependency for OpenAPI TypeScript types
apps/web/package.json Added swagger-ui-dist dependency for Swagger UI assets
apps/web/app/api/docs/openapi.json/route.ts Created Next.js API route to serve OpenAPI JSON document
apps/web/app/api-docs/page.tsx Implemented client-side Swagger UI page with dynamic asset loading
Files not reviewed (1)
  • pnpm-lock.yaml: Language not supported

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +24 to +25
link.href =
'/_next/static/css/swagger-ui.css';
Copy link

Copilot AI Nov 27, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The CSS file path /_next/static/css/swagger-ui.css appears to be incorrect. The swagger-ui-dist package provides CSS files that should be accessed through the node_modules path or copied to the public directory. Next.js won't automatically serve CSS from swagger-ui-dist at this path.

Consider using the CSS directly from the package using an import statement or copying the CSS file to the public directory and referencing it properly. For example:

import 'swagger-ui-dist/swagger-ui.css';

Or serve it from a public asset path if you copy swagger-ui.css from the package to your public directory.

Copilot uses AI. Check for mistakes.
)}
<div ref={containerRef} />
<style jsx global>{`
/* Swagger UI CSS is loaded via the JS bundle */
Copy link

Copilot AI Nov 27, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment on line 65 mentions "Swagger UI CSS is loaded via the JS bundle", but this is misleading. The CSS is actually being loaded dynamically by manually creating a link element (lines 22-26), not through the JS bundle import. The global styles defined here only add minor adjustments to the Swagger UI styling.

Consider updating the comment to be more accurate:

/* Additional styling adjustments for Swagger UI */
Suggested change
/* Swagger UI CSS is loaded via the JS bundle */
/* Additional styling adjustments for Swagger UI */

Copilot uses AI. Check for mistakes.
Comment on lines +376 to +386
'/registries.update': {
post: {
tags: ['Registries'],
summary: 'Update a container registry',
description: 'Updates an existing container registry configuration.',
security: [{ cookieAuth: [] }],
responses: {
'200': { description: 'Updated registry' },
'401': { description: 'Unauthorized' },
},
},
Copy link

Copilot AI Nov 27, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing requestBody specification. This POST endpoint needs to specify the expected request body schema including registryId and other fields from updateRegistrySchema. Users won't know what parameters to send without this documentation.

Add the requestBody definition:

requestBody: {
    required: true,
    content: {
        'application/json': {
            schema: {
                type: 'object',
                required: ['registryId', 'name', 'username', 'password', 'url'],
                properties: {
                    registryId: { type: 'string', description: 'Unique identifier of the registry' },
                    name: { type: 'string', description: 'Display name for the container registry' },
                    username: { type: 'string', description: 'Username for registry authentication' },
                    password: { type: 'string', description: 'Password or access token for registry authentication' },
                    url: { type: 'string', description: 'URL of the container registry' },
                },
            },
        },
    },
},

Copilot uses AI. Check for mistakes.
Comment on lines +524 to +534
'/services.deleteService': {
post: {
tags: ['Services'],
summary: 'Delete a service',
description: 'Permanently deletes a service and its configurations.',
security: [{ cookieAuth: [] }],
responses: {
'200': { description: 'Deletion result' },
'401': { description: 'Unauthorized' },
},
},
Copy link

Copilot AI Nov 27, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing requestBody specification. This POST endpoint needs to specify the expected request body schema including serviceId. Users won't know what parameter to send without this documentation.

Add the requestBody definition:

requestBody: {
    required: true,
    content: {
        'application/json': {
            schema: {
                type: 'object',
                required: ['serviceId'],
                properties: {
                    serviceId: { type: 'string', description: 'Unique identifier of the service' },
                },
            },
        },
    },
},

Copilot uses AI. Check for mistakes.
Comment on lines +536 to +546
'/services.deployService': {
post: {
tags: ['Services'],
summary: 'Deploy a service',
description: 'Deploys the service to its configured server. Returns true if successful.',
security: [{ cookieAuth: [] }],
responses: {
'200': { description: 'Deployment result' },
'401': { description: 'Unauthorized' },
},
},
Copy link

Copilot AI Nov 27, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing requestBody specification. This POST endpoint needs to specify the expected request body schema including serviceId. Users won't know what parameter to send without this documentation.

Add the requestBody definition:

requestBody: {
    required: true,
    content: {
        'application/json': {
            schema: {
                type: 'object',
                required: ['serviceId'],
                properties: {
                    serviceId: { type: 'string', description: 'Unique identifier of the service' },
                },
            },
        },
    },
},

Copilot uses AI. Check for mistakes.
Comment on lines +388 to +398
'/registries.delete': {
post: {
tags: ['Registries'],
summary: 'Delete a container registry',
description: 'Permanently deletes a container registry from the organization.',
security: [{ cookieAuth: [] }],
responses: {
'200': { description: 'Deletion result' },
'401': { description: 'Unauthorized' },
},
},
Copy link

Copilot AI Nov 27, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing requestBody specification. This POST endpoint needs to specify the expected request body schema including registryId. Users won't know what parameter to send without this documentation.

Add the requestBody definition:

requestBody: {
    required: true,
    content: {
        'application/json': {
            schema: {
                type: 'object',
                required: ['registryId'],
                properties: {
                    registryId: { type: 'string', description: 'Unique identifier of the registry' },
                },
            },
        },
    },
},

Copilot uses AI. Check for mistakes.
Comment on lines +445 to +449
responses: {
'200': { description: 'Deletion result' },
'401': { description: 'Unauthorized' },
},
},
Copy link

Copilot AI Nov 27, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing requestBody specification. This POST endpoint needs to specify the expected request body schema including projectId. Users won't know what parameter to send without this documentation.

Add the requestBody definition:

requestBody: {
    required: true,
    content: {
        'application/json': {
            schema: {
                type: 'object',
                required: ['projectId'],
                properties: {
                    projectId: { type: 'string', description: 'Unique identifier of the project' },
                },
            },
        },
    },
},
Suggested change
responses: {
'200': { description: 'Deletion result' },
'401': { description: 'Unauthorized' },
},
},
requestBody: {
required: true,
content: {
'application/json': {
schema: {
type: 'object',
required: ['projectId'],
properties: {
projectId: { type: 'string', description: 'Unique identifier of the project' },
},
},
},
},
},
responses: {
'200': { description: 'Deletion result' },
'401': { description: 'Unauthorized' },
},

Copilot uses AI. Check for mistakes.
Comment on lines +578 to +588
'/domains.delete': {
post: {
tags: ['Domains'],
summary: 'Delete a domain',
description: 'Permanently deletes a domain mapping from a service.',
security: [{ cookieAuth: [] }],
responses: {
'200': { description: 'Deletion result' },
'401': { description: 'Unauthorized' },
},
},
Copy link

Copilot AI Nov 27, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing requestBody specification. This POST endpoint needs to specify the expected request body schema including domainId. Users won't know what parameter to send without this documentation.

Add the requestBody definition:

requestBody: {
    required: true,
    content: {
        'application/json': {
            schema: {
                type: 'object',
                required: ['domainId'],
                properties: {
                    domainId: { type: 'string', description: 'Unique identifier of the domain' },
                },
            },
        },
    },
},

Copilot uses AI. Check for mistakes.
Comment on lines +643 to +653
'/networks.delete': {
post: {
tags: ['Networks'],
summary: 'Delete a network',
description: 'Permanently deletes a Docker network.',
security: [{ cookieAuth: [] }],
responses: {
'200': { description: 'Deletion result' },
'401': { description: 'Unauthorized' },
},
},
Copy link

Copilot AI Nov 27, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing requestBody specification. This POST endpoint needs to specify the expected request body schema including networkId. Users won't know what parameter to send without this documentation.

Add the requestBody definition:

requestBody: {
    required: true,
    content: {
        'application/json': {
            schema: {
                type: 'object',
                required: ['networkId'],
                properties: {
                    networkId: { type: 'string', description: 'Unique identifier of the network' },
                },
            },
        },
    },
},

Copilot uses AI. Check for mistakes.
Comment on lines +705 to +715
'/volumes.update': {
post: {
tags: ['Volumes'],
summary: 'Update a volume',
description: 'Updates an existing volume configuration.',
security: [{ cookieAuth: [] }],
responses: {
'200': { description: 'Updated volume' },
'401': { description: 'Unauthorized' },
},
},
Copy link

Copilot AI Nov 27, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing requestBody specification. This POST endpoint needs to specify the expected request body schema including volumeId and optional fields from updateVolumeSchema. Users won't know what parameters to send without this documentation.

Add the requestBody definition:

requestBody: {
    required: true,
    content: {
        'application/json': {
            schema: {
                type: 'object',
                required: ['volumeId'],
                properties: {
                    volumeId: { type: 'string', description: 'Unique identifier of the volume' },
                    name: { type: 'string', description: 'Docker volume name (alphanumeric, hyphens, underscores, periods)' },
                    mountPath: { type: 'string', description: 'Absolute path inside the container where the volume will be mounted' },
                    readOnly: { type: 'boolean', description: 'Whether the volume is read-only' },
                },
            },
        },
    },
},

Copilot uses AI. Check for mistakes.
@SimonLoir SimonLoir closed this Nov 27, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants