Published on 2025-03-08

App Router

Published on

2025-03-08

App Router

The Igniter App Router is a central component that connects your controllers to your HTTP framework. It provides a clean, type-safe way to define your API routes and handle incoming requests.

Setting Up the App Router

The first step is to initialize your router by connecting it to your controllers:

typescript
// src/igniter.router.ts
import { igniter } from '@/igniter'
import { userController } from '@/features/user/controllers/user.controller'
import { notesController } from '@/features/notes/controllers/notes.controller'
import { authController } from '@/features/auth/controllers/auth.controller'

/**
 * @description Initialize the Igniter Router
 * @see https://github.com/felipebarcelospro/igniter-js
 */
export const AppRouter = igniter.router({
  baseURL: process.env.IGNITER_APP_URL || 'http://localhost:3000',
  basePATH: process.env.IGNITER_APP_BASE_PATH || '/api/v1',
  controllers: {
    users: userController,
    notes: notesController,
    auth: authController
  }
})

The router configuration includes:

  • baseURL: The base URL of your application (e.g., http://localhost:3000)
  • basePATH: The base path for your API routes (e.g., /api/v1)
  • controllers: An object mapping controller names to their implementations

Integrating with HTTP Frameworks

The Igniter App Router can be integrated with various HTTP frameworks. Here are examples for common frameworks:

Express

typescript
// src/server.ts
import express from 'express'
import { AppRouter } from '@/igniter.router'

const app = express()

// Use the Igniter router with Express
app.use(async (req, res) => {
  const response = await AppRouter.handler(req)
  res.status(response.status).json(response)
})

app.listen(3000, () => {
  console.log('Server running on http://localhost:3000')
})

Next.js Route Handlers

typescript
// src/app/api/v1/[[...all]]/route.ts
import { AppRouter } from '@/igniter.router'
import { nextRouteHandlerAdapter } from '@igniter-js/core/adapters/next'

export const { GET, POST, PUT, DELETE } = nextRouteHandlerAdapter(AppRouter)

Bun

typescript
// src/server.ts
import { AppRouter } from '@/igniter.router'

Bun.serve({
  fetch: AppRouter.handler
})

Route Handling

The App Router automatically handles routing based on the path and method defined in your controllers. For example, if you have a controller with the following actions:

typescript
const userController = igniter.controller({
  path: '/users',
  actions: {
    list: igniter.query({
      path: '/',
      handler: async (ctx) => {
        // Handle GET /api/v1/users
      }
    }),
    get: igniter.query({
      path: '/:id',
      handler: async (ctx) => {
        // Handle GET /api/v1/users/:id
      }
    }),
    create: igniter.mutation({
      path: '/',
      method: 'POST',
      handler: async (ctx) => {
        // Handle POST /api/v1/users
      }
    })
  }
})

The App Router will automatically create the following routes:

  • GET /api/v1/users - Handled by the list action
  • GET /api/v1/users/:id - Handled by the get action
  • POST /api/v1/users - Handled by the create action

Type Safety

One of the key benefits of the Igniter App Router is type safety. The router provides full type inference for your API routes, ensuring that your client code is always in sync with your server code.

typescript
// The router type can be used to infer types for your API client
import { AppRouter } from '@/igniter.router'
import { createIgniterClient } from '@igniter-js/core/client'

export const api = createIgniterClient(AppRouter)

// Now your API client has full type inference
const result = await api.users.get.call({ params: { id: '123' } })
// result is fully typed based on the return type of your handler

Error Handling

The App Router includes built-in error handling. If an error occurs in your controller action, the router will automatically catch it and return an appropriate error response.

typescript
const errorHandler = igniter.procedure({
  handler: async (_, ctx) => {
    try {
      return await ctx.next()
    } catch (error) {
      // Log the error
      console.error('API Error:', error)
      
      // Return a friendly error response
      if (error instanceof ValidationError) {
        return ctx.response.badRequest(error.message)
      }
      
      if (error instanceof NotFoundError) {
        return ctx.response.notFound(error.message)
      }
      
      // Default error response
      return ctx.response.internalServerError('An unexpected error occurred')
    }
  }
})

// Use the error handler in your router
export const AppRouter = igniter.router({
  baseURL: 'http://localhost:3000',
  basePATH: '/api/v1',
  controllers: {
    users: userController
  },
  use: [errorHandler()]
})

Advanced Configuration

Middleware

You can add global middleware to your router using the use option:

typescript
export const AppRouter = igniter.router({
  baseURL: 'http://localhost:3000',
  basePATH: '/api/v1',
  controllers: {
    users: userController
  },
  use: [
    logger(),
    rateLimiter(),
    cors()
  ]
})

Custom Response Transformers

You can customize how responses are transformed before they are sent to the client:

typescript
export const AppRouter = igniter.router({
  baseURL: 'http://localhost:3000',
  basePATH: '/api/v1',
  controllers: {
    users: userController
  },
  transformResponse: (response) => {
    // Add a timestamp to all responses
    return {
      ...response,
      timestamp: new Date().toISOString()
    }
  }
})

Best Practices

  1. Organize Controllers by Feature: Group related controllers together based on features or domains.

  2. Use Consistent Naming: Use consistent naming conventions for your controllers and actions.

  3. Leverage Type Safety: Take advantage of TypeScript's type system to ensure your API is type-safe.

  4. Implement Error Handling: Always implement proper error handling to provide meaningful error messages to clients.

  5. Use Environment Variables: Store configuration values like baseURL and basePATH in environment variables for flexibility across different environments.

  6. Keep the Router Simple: The router should be a thin layer that connects controllers to HTTP frameworks. Complex logic should be in controllers or procedures.

AD

Quick Tip

Always implement proper error handling and reconnection logic in your SSE clients to ensure a robust user experience.

You might also like