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.

SaaS Boilerplate

Acelere seu desenvolvimento

Construa aplicações SaaS completas em minutos com nosso boilerplate moderno. Autenticação, pagamentos, gerenciamento de usuários e muito mais!

Conheça o SaaS Boilerplate

Você também pode gostar