Criando um Procedure

Publicado em

08/03/2025

Criando uma procedure com o Igniter.js no SaaS Boilerplate

Procedures no Igniter são funções de middleware poderosas que permitem implementar preocupações transversais como autenticação, validação, tratamento de erros e registro de logs. Eles podem ser aplicados a ações individuais do controlador ou globalmente ao seu roteador.

Criando um Procedure

Para criar um Procedure no Igniter, você usa a função igniter.procedure(). Aqui está um exemplo básico:

// src/procedures/auth.procedure.ts
import { igniter } from '@/igniter'
import { verifyToken } from '@/utils/jwt'

export const auth = igniter.procedure({
  handler: async (input, ctx) => {
    // Get the authorization header
    const authHeader = ctx.headers.authorization
    
    if (!authHeader || !authHeader.startsWith('Bearer ')) {
      return ctx.response.unauthorized('Missing or invalid authorization token')
    }
    
    const token = authHeader.split(' ')[1]
    
    try {
      // Verify the token
      const user = await verifyToken(token)
      
      // Add the user to the context
      ctx.user = user
      
      // Continue to the next middleware or handler
      return ctx.next()
    } catch (error) {
      return ctx.response.unauthorized('Invalid token')
    }
  }
})

A configuração do Procedure inclui:

  • handler: Uma função que recebe a entrada e o contexto, e retorna uma resposta ou chama ctx.next() para continuar para o próximo middleware ou manipulador

Usando Procedures com Controladores

Procedures podem ser aplicados a ações individuais do controlador:

// src/features/user/controllers/user.controller.ts
import { igniter } from '@/igniter'
import { auth } from '@/procedures/auth.procedure'

export const userController = igniter.controller({
  path: '/users',
  actions: {
    list: igniter.query({
      path: '/',
      use: [auth()], // Apply the auth procedure
      handler: async (ctx) => {
        // This handler will only be called if the auth procedure passes
        const users = await ctx.providers.database.user.findMany()
        return ctx.response.ok(users)
      }
    })
  }
})

Usando Procedures com Roteadores (Em Breve)

Nota: Este recurso está atualmente em desenvolvimento e estará disponível em uma versão futura.

No futuro, Procedures poderão ser aplicados globalmente ao seu roteador:

// src/igniter.router.ts
import { igniter } from '@/igniter'
import { userController } from '@/features/user/controllers/user.controller'
import { logger } from '@/procedures/logger.procedure'
import { errorHandler } from '@/procedures/error-handler.procedure'

export const AppRouter = igniter.router({
  baseURL: 'https://localhost:3000',
  basePATH: '/api/v1',
  controllers: {
    users: userController
  },
  use: [
    logger(), // Applied to all requests (coming soon)
    errorHandler() // Applied to all requests (coming soon)
  ]
})

Padrões Comuns de Procedures

Nota: O Igniter.js tem suporte integrado para validação de entrada em mutations e queries. Os exemplos abaixo focam em outros casos de uso comuns para Procedures.

Tratamento de Erros

// src/procedures/error-handler.procedure.ts
import { igniter } from '@/igniter'

export const errorHandler = igniter.procedure({
  handler: async (_, ctx) => {
    try {
      // Continua para o próximo middleware ou manipulador
      return await ctx.next()
    } catch (error) {
      // Registra o erro
      console.error('Erro de API:', error)
      
      // Retorna uma resposta de erro apropriada
      if (error.name === 'ValidationError') {
        return ctx.response.badRequest(error.message)
      }
      
      if (error.name === 'NotFoundError') {
        return ctx.response.notFound(error.message)
      }
      
      // Resposta de erro padrão
      return ctx.response.internalServerError('Ocorreu um erro inesperado')
    }
  }
})

Registro de Logs

// src/procedures/logger.procedure.ts
import { igniter } from '@/igniter'

export const logger = igniter.procedure({
  handler: async (_, ctx) => {
    const start = Date.now()
    
    // Registra a requisição
    console.log(`${ctx.method} ${ctx.path} - Requisição recebida`)
    
    // Continua para o próximo middleware ou manipulador
    const response = await ctx.next()
    
    // Registra a resposta
    const duration = Date.now() - start
    console.log(`${ctx.method} ${ctx.path} - Resposta enviada (${response.status}) em ${duration}ms`)
    
    return response
  }
})

Encadeando Procedures

Procedures podem ser encadeados para criar um pipeline de middleware:

export const userController = igniter.controller({
  path: '/users',
  actions: {
    create: igniter.mutation({
      path: '/',
      method: 'POST',
      use: [
        logger(), // Primeiro Procedure na cadeia
        auth(), // Segundo Procedure na cadeia
      ],
      handler: async (ctx) => {
        // O manipulador só é chamado se todos os Procedures passarem
      }
    })
  }
})

Melhores Práticas

  1. Mantenha os Procedures Focados: Cada Procedure deve se concentrar em uma única preocupação.

  2. Use Procedures para Preocupações Transversais: Use Procedures para autenticação, validação, registro de logs e outras preocupações transversais.

  3. Encadeie Procedures em uma Ordem Lógica: Ordene seus Procedures logicamente, com Procedures de uso geral (como registro de logs) primeiro e os mais específicos (como validação) depois.

  4. Trate Erros com Elegância: Implemente tratamento adequado de erros em seus Procedures para fornecer mensagens de erro significativas aos clientes.

  5. Compartilhe Contexto Entre Procedures: Use o objeto de contexto para compartilhar dados entre Procedures e manipuladores.

  6. Make Procedures Reusable: Design your procedures to be reusable across different controllers and actions.

PRO

Quer desenvolver um SaaS em um final de semana?

Um único comando no terminal e pronto, você já tem seu projeto criado, com site, blog, central de ajuda, autenticação, onboarding, dashboard, emails... Para resumir, é assim que eu crio os meus SaaS em um Final de Semana.

Conheça minha estratégia

Você também pode gostar