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 chamactx.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
-
Mantenha os Procedures Focados: Cada Procedure deve se concentrar em uma única preocupação.
-
Use Procedures para Preocupações Transversais: Use Procedures para autenticação, validação, registro de logs e outras preocupações transversais.
-
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.
-
Trate Erros com Elegância: Implemente tratamento adequado de erros em seus Procedures para fornecer mensagens de erro significativas aos clientes.
-
Compartilhe Contexto Entre Procedures: Use o objeto de contexto para compartilhar dados entre Procedures e manipuladores.
-
Make Procedures Reusable: Design your procedures to be reusable across different controllers and actions.
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