@insightcreativewebs/api
v1.0.9
Published
ICW API - Framework Node.js para APIs REST com TypeScript
Maintainers
Readme
@insightcreativewebs/api
Framework Node.js moderno para APIs REST com TypeScript
🚀 Características
- ✨ TypeScript First: Totalmente tipado com TypeScript
- 🏗️ Arquitetura Modular: Controller, Service, Rules pattern
- 🔒 Type-Safe: Validação de dados com schema tipado
- 📝 Auto-documentação: Geração automática de
.enve.env.example - 🎯 Context Global: Sistema de contexto similar ao Nullstack
- 🔌 Extensível: Sistema de plugins e middlewares configuráveis
- 📦 ORM Agnostic: Desacoplado de ORMs específicos
- 🛠️ CLI Tools: Scripts para gerar módulos e configurar ambiente
- 📊 Logger Avançado: Sistema de logging com persistência
- 🌍 Timezone Management: Gerenciamento centralizado de datas
📦 Instalação
npm install @insightcreativewebs/api
# ou
yarn add @insightcreativewebs/api
# ou
pnpm add @insightcreativewebs/api🎯 Quick Start
1. Criar novo projeto
npx create-icw-api minha-api
cd minha-api
npm install2. Configurar variáveis de ambiente
O framework gera automaticamente o arquivo .env baseado no envSchema:
// src/server.ts
import { Application, defineEnv } from '@insightcreativewebs/api';
import dotenv from 'dotenv';
dotenv.config();
export const envSchema = defineEnv({
PORT: {
type: 'number',
default: 3000,
description: 'Porta do servidor',
group: 'Servidor',
},
NODE_ENV: {
type: 'enum',
values: ['development', 'production', 'test'],
default: 'development',
description: 'Ambiente de execução',
group: 'Servidor',
},
});
const app = new Application({
envSchema,
timezone: 'America/Sao_Paulo',
});
app.start().catch(console.error);3. Criar seu primeiro módulo
npm run generate:module userIsso cria:
src/modules/user/user.controller.tssrc/modules/user/user.service.tssrc/modules/user/user.rules.tssrc/modules/user/user.module.ts
📚 Documentação
Application
A classe principal do framework:
import { Application, defineEnv } from '@insightcreativewebs/api';
const app = new Application({
envSchema: defineEnv({ /* ... */ }),
port: 3000,
timezone: 'America/Sao_Paulo',
modulesPath: 'src/modules',
plugins: {
storage: new MyStorageManager(),
mailer: new MyMailerService(),
},
});
app.start();Controllers
import { Request } from 'express';
import { ok, created, BaseController } from '@insightcreativewebs/api';
import { UserService } from './user.service';
import { createUserRules, updateUserRules } from './user.rules';
import { Validation } from '@insightcreativewebs/api';
export class UserController extends BaseController {
constructor(private userService: UserService) {
super();
}
async list(req: Request) {
const users = await this.userService.findAll();
return ok(users);
}
async create(req: Request) {
const validation = new Validation();
const rules = createUserRules();
rules.validate(req.body, validation);
if (!validation.isValid()) {
return {
status: 400,
errors: validation.getFormatted(),
};
}
const user = await this.userService.create(req.body);
return created(user);
}
}Services
import { BaseService } from '@insightcreativewebs/api';
import { getContext } from '@insightcreativewebs/api';
export class UserService extends BaseService {
async findAll() {
const context = getContext();
// Acessa database, logger, config, etc via context
return [];
}
async create(data: any) {
// Implementar lógica aqui
return data;
}
}Validation Rules
import { required, email, schema, InputOf } from '@insightcreativewebs/api';
export const createUserRules = schema({
name: [required('Nome é obrigatório')],
email: [required('Email é obrigatório'), email('Email inválido')],
age: [required('Idade é obrigatória'), numeric('Idade deve ser um número')],
});
export const updateUserRules = schema({
name: [required('Nome é obrigatório')],
email: [email('Email inválido')],
});
export type CreateUserInput = InputOf<typeof createUserRules>;
export type UpdateUserInput = InputOf<typeof updateUserRules>;Modules
import { createModule } from '@insightcreativewebs/api';
import { UserController } from './user.controller';
import { UserService } from './user.service';
const controller = new UserController(new UserService());
export default createModule(
'/users',
UserController,
[], // middlewares opcionais
{
name: 'User',
description: 'Módulo de usuários',
tags: ['users'],
}
).routes((route) => [
route.get('/', 'list'),
route.get('/:id', 'show'),
route.post('/', 'create'),
route.put('/:id', 'update'),
route.delete('/:id', 'delete'),
]);Application Context
Acesse recursos globais em qualquer lugar:
import { getContext } from '@insightcreativewebs/api';
const context = getContext();
// Acessa database (se configurado)
context.database?.query('SELECT * FROM users');
// Acessa logger
context.logger.info('Mensagem de log');
// Acessa config
const port = context.config.get('PORT');
// Acessa plugins customizados
const storage = context.getPlugin('storage');Date Helper
Gerenciamento centralizado de datas:
import { dateHelper, configureTimezone } from '@insightcreativewebs/api';
// Configura timezone (feito automaticamente no Application)
configureTimezone('America/Sao_Paulo');
// Usa helper
const now = dateHelper().toDB(); // Converte para UTC para salvar no banco
const local = dateHelper().fromDB(now); // Converte de UTC para localQuery Filter
Filtros funcionais para queries:
import { filter, conditionalFilter } from '@insightcreativewebs/api';
// Filtro simples
const where = filter({
name: 'John',
age: 25,
});
// Filtro condicional
const where = conditionalFilter({
name: search ? { $like: `%${search}%` } : undefined,
status: status || undefined,
});Logger
Sistema de logging avançado:
import { logger } from '@insightcreativewebs/api';
logger.info('Informação');
logger.warn('Aviso');
logger.error('Erro');
logger.debug('Debug (só aparece se DEBUG_MODE=true)');
logger.success('Sucesso');
logger.http('Requisição HTTP');
// Com persistência
logger.info('Log importante', { persist: true });
// Consultar logs
const errors = logger.getErrors();
const stats = logger.getStats();🛠️ CLI Scripts
Gerar módulo
npm run generate:module <nome> [opções]
# Opções:
# --no-controller Não cria controller
# --no-service Não cria service
# --no-rules Não cria rules
# --prefix=/custom Define prefix customizadoGerar arquivos de ambiente
# Gera .env e .env.example
npm run generate:env
# Apenas .env.example
npm run generate:env:example
# Força regerar .env (sobrescreve valores existentes)
npm run generate:env:force⚙️ Configuração
TypeScript Configuration
Para evitar problemas com imports em desenvolvimento, use a seguinte configuração no tsconfig.json do seu projeto:
{
"compilerOptions": {
"target": "ES2020",
"module": "commonjs",
"lib": ["ES2020"],
"outDir": "./dist",
"rootDir": "./",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"resolveJsonModule": true,
"declaration": true,
"experimentalDecorators": true,
"emitDecoratorMetadata": true,
"moduleResolution": "node",
"allowSyntheticDefaultImports": true,
"forceConsistentCasingInFileNames": true
},
"include": ["**/*.ts"],
"exclude": ["node_modules", "dist"]
}✨ Importante sobre imports sem extensão:
O comportamento depende da versão do TypeScript:
TypeScript 4.9.x ou anterior:
- ✅ Permite imports sem extensão normalmente
import { UserService } from './user.service'; import { createUserRules } from './user.rules';
TypeScript 5.0+ (mais rigoroso):
- ⚠️ Exige extensões
.jsnos imports relativos (mesmo que o arquivo seja.ts) import { UserService } from './user.service.js'; import { createUserRules } from './user.rules.js';
Por quê TypeScript 5.0+ exige extensões?
- Quando o TypeScript compila, os arquivos
.tsviram.js - O TypeScript precisa saber qual será o caminho final em runtime
- Isso garante que os imports funcionem corretamente após a compilação
Soluções:
Usar TypeScript 4.9.x (mantém comportamento antigo):
npm install --save-dev [email protected]Usar extensões
.jsnos imports (recomendado para TypeScript 5.0+):import { UserService } from './user.service.js';Em desenvolvimento com
tsxouts-node:- O
tsx/ts-noderesolve corretamente os imports com.jsmesmo que o arquivo seja.ts - Funciona perfeitamente em desenvolvimento e produção
- O
⚙️ Configuração Avançada
Variáveis de Ambiente
O framework suporta as seguintes variáveis:
Servidor
PORT: Porta do servidor (padrão: 3000)NODE_ENV: Ambiente (development/production/test)TIMEZONE: Timezone da aplicação (padrão: America/Sao_Paulo)
Logger
LOGGING: Habilita/desabilita logging (padrão: true)DEBUG_MODE: Habilita modo debug (padrão: false)LOG_PERSIST_MODE: Modo de persistência (none/memory/file/both)LOG_DIRECTORY: Diretório dos logs (padrão: logs)MAX_MEMORY_LOGS: Máximo de logs em memória (padrão: 100)
Request Logging
LOG_REQUEST_LEVEL: Nível de log (none/all/errors)
🔌 Plugins
Registre serviços customizados no Application Context:
const app = new Application({
plugins: {
storage: new S3StorageManager(),
mailer: new SendGridMailer(),
cache: new RedisCache(),
},
});
// Acesse em qualquer lugar
const context = getContext();
const storage = context.getPlugin('storage');🎨 Middlewares Customizados
Error Middleware
import { createErrorMiddleware } from '@insightcreativewebs/api';
const customErrorMiddleware = createErrorMiddleware({
handlers: {
MyCustomError: (err, req, res) => {
res.status(500).json({ error: 'Custom error' });
},
},
});
const app = new Application({
middlewareConfig: {
errorMiddleware: customErrorMiddleware,
},
});CORS Middleware
import { createCorsMiddleware } from '@insightcreativewebs/api';
const cors = createCorsMiddleware({
origins: ['https://example.com', 'https://app.example.com'],
credentials: true,
});
const app = new Application({
middlewareConfig: {
corsMiddleware: cors,
},
});📖 Exemplos
Veja mais exemplos na documentação completa.
🤝 Contribuindo
Contribuições são bem-vindas! Por favor, abra uma issue ou pull request.
📄 Licença
MIT © 2025 Aylon Muramatsu
🔗 Links
Feito com ❤️ por Insight Creative Webs
