Documentation
Documentation
Introduction

Getting Started

Getting StartedInstallationQuick StartProject Structure

Architecture

Architecture OverviewTech StacktRPC MiddlewareDesign Principles

Patterns

Code Patterns & ConventionsFeature ModulesError HandlingType Safety

Database

DatabaseSchema DefinitionDatabase OperationsMigrationsCaching

API

tRPCProceduresRouterstRPC Proxy Setup
APIsOpenAPIREST Endpoints

Auth & Access

AuthenticationConfigurationOAuth ProvidersRolesSession Management
AuthorizationUser RolesPermissions

Routing & i18n

RoutingDeclarative RoutingNavigation
InternationalizationTranslationsLocale Routing

Components & UI

ComponentsButtonsFormsNavigationDialogs
StylesTailwind CSSThemingTypography

Storage

StorageConfigurationUsageBuckets

Configuration

ConfigurationEnvironment VariablesFeature Flags

Templates

Template GuidesCreate New FeatureCreate New PageCreate Database TableCreate tRPC RouterAdd Translations

Development

DevelopmentCommandsAI AgentsBest Practices

APIs

REST APIs and OpenAPI integration

Overview

This project exposes REST APIs through automatic OpenAPI integration with tRPC. Any tRPC procedure can be exposed as a REST endpoint with proper configuration, enabling external clients to consume your API without using tRPC.

Key Features

  • OpenAPI Specification - Automatic generation from tRPC procedures
  • Type-Safe REST Endpoints - Maintained type safety from server to client
  • Authentication - Bearer token (API key) authentication
  • Rate Limiting - Built-in rate limiting per endpoint
  • Documentation - Auto-generated API documentation
  • Swagger UI - Interactive API explorer

Architecture

The API layer is built on top of tRPC with the following components:

┌─────────────────┐
│ External Client │
└────────┬────────┘
         │ HTTP Request
         │ (Bearer Token)
         ↓
┌─────────────────┐
│  OpenAPI Layer  │ ← trpc-to-openapi
└────────┬────────┘
         │
         ↓
┌─────────────────┐
│  tRPC Router    │ ← Type-safe procedures
└────────┬────────┘
         │
         ↓
┌─────────────────┐
│   Database      │
└─────────────────┘

Enabling REST Endpoints

To expose a tRPC procedure as a REST endpoint, add OpenAPI metadata to the procedure definition:

import { authProcedure } from "@/trpc/procedures/trpc";
import { z } from "zod";

export const apiKeyRouter = createTRPCRouter({
  list: authProcedure
    .meta({
      rateLimit: "QUERY",
      openapi: {
        enabled: true,
        method: "GET",
        path: "/api-keys",
        tags: ["API Keys"],
        summary: "List API keys",
        description: "Returns all API keys for the authenticated user",
        protect: true, // Requires authentication
      },
    })
    .input(z.object({}))
    .output(z.object({
      success: z.boolean(),
      payload: z.array(apiKeySchema),
    }))
    .query(async ({ ctx }) => {
      const keys = await getByUserId(ctx.auth.user.id);
      return {
        success: true,
        payload: keys,
      };
    }),
});

OpenAPI procedures require explicit .input() and .output() schemas for proper API documentation generation.

REST Endpoint Structure

All REST endpoints are available at:

https://your-app.com/api/<path>

Where <path> is defined in the OpenAPI metadata of each procedure.

Example Endpoints

EndpointMethodDescriptionAuth Required
/api/api-keysGETList user's API keysYes
/api/api-keysPOSTCreate new API keyYes
/api/api-keys/:idDELETEDelete API keyYes
/api/healthGETHealth checkNo

Authentication

Protected endpoints require authentication via Bearer token in the Authorization header.

Getting an API Key

Users can generate API keys through the dashboard:

  1. Navigate to /dashboard/api-keys
  2. Click "Create API Key"
  3. Copy the generated key
  4. Use the key in API requests

Using Bearer Token

curl -H "Authorization: Bearer YOUR_API_KEY" \
  https://your-app.com/api/api-keys

Public Endpoints

Some endpoints may be public (no authentication required) by setting protect: false in the OpenAPI metadata:

healthCheck: publicProcedure
  .meta({
    openapi: {
      enabled: true,
      method: "GET",
      path: "/health",
      protect: false, // No auth required
      tags: ["System"],
      summary: "Health check",
    },
  })
  .input(z.object({}))
  .output(z.object({ status: z.string() }))
  .query(() => ({ status: "ok" }))

Request/Response Format

Request Headers

Authorization: Bearer YOUR_API_KEY
Content-Type: application/json

Success Response

All endpoints return the standard ActionResponse format:

{
  "success": true,
  "message": "Operation completed successfully",
  "payload": {
    "id": "123",
    "name": "My Resource"
  }
}

Error Response

{
  "success": false,
  "message": "Validation failed",
  "errors": [
    {
      "path": ["name"],
      "message": "Name is required"
    }
  ]
}

Rate Limiting

All API endpoints are rate-limited based on the procedure metadata:

.meta({
  rateLimit: "QUERY",  // or "MUTATION"
  // ... openapi config
})

Rate limits:

  • QUERY: 100 requests per minute
  • MUTATION: 20 requests per minute

Exceeded limits return HTTP 429 with:

{
  "success": false,
  "message": "Rate limit exceeded. Try again later."
}

OpenAPI Specification

The full OpenAPI specification is automatically generated and available at:

https://your-app.com/api/openapi.json

Viewing Documentation

Interactive API documentation (Swagger UI) is available during development at:

http://localhost:3000/api/docs

The Swagger UI is only available in development mode. In production, clients should use the OpenAPI JSON spec to generate their own documentation.

Error Handling

The API layer uses consistent error handling:

HTTP StatusDescription
200Success
400Bad request / Validation
401Unauthorized
403Forbidden
404Not found
429Rate limit exceeded
500Internal server error

Errors include detailed messages and validation errors when applicable:

{
  "success": false,
  "message": "Validation failed",
  "errors": [
    {
      "path": ["email"],
      "message": "Invalid email format"
    },
    {
      "path": ["age"],
      "message": "Must be at least 18"
    }
  ]
}

Testing REST Endpoints

Using cURL

# GET request
curl -X GET \
  -H "Authorization: Bearer YOUR_API_KEY" \
  https://your-app.com/api/api-keys

# POST request
curl -X POST \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name": "My API Key"}' \
  https://your-app.com/api/api-keys

Using Postman

  1. Set method and URL
  2. Add header: Authorization: Bearer YOUR_API_KEY
  3. Set body (for POST/PUT): JSON format
  4. Send request

Using JavaScript/TypeScript

const response = await fetch("https://your-app.com/api/api-keys", {
  method: "GET",
  headers: {
    "Authorization": "Bearer YOUR_API_KEY",
    "Content-Type": "application/json",
  },
});

const data = await response.json();

Next Steps

  • OpenAPI Configuration - Detailed OpenAPI setup
  • REST Endpoints - Using REST endpoints
  • tRPC Procedures - Creating procedures
  • Authentication - Authentication flows

On this page

Overview
Key Features
Architecture
Enabling REST Endpoints
REST Endpoint Structure
Example Endpoints
Authentication
Getting an API Key
Using Bearer Token
Public Endpoints
Request/Response Format
Request Headers
Success Response
Error Response
Rate Limiting
OpenAPI Specification
Viewing Documentation
Error Handling
Testing REST Endpoints
Using cURL
Using Postman
Using JavaScript/TypeScript
Next Steps