APIs Node.js com Express, Fastify e NestJS
Este guia cobre APIs e backends Node.js publicados pelo Repositório GitHub. A Zenifra instala as dependências com npm ci, executa a build quando configurada e inicia a aplicação com o comando start.
Pré-requisitos
package.jsonepackage-lock.jsonversionados na raiz do repositório- Script
start(ou o comando completo) que inicia o servidor - Conta GitHub conectada à Zenifra
Escutando na porta certa
Leia a porta de uma variável com valor padrão e escute em 0.0.0.0:
const express = require('express');
const app = express();
app.use(express.json());
app.get('/health', (req, res) => res.json({ status: 'ok' }));
app.get('/', (req, res) => res.json({ message: 'Olá da Zenifra' }));
const port = Number(process.env.PORT ?? 3000);
app.listen(port, '0.0.0.0', () => console.log(`Escutando na porta ${port}`));O campo Porta do projeto deve ter o mesmo valor. Se não definir a variável PORT, o padrão 3000 do código é usado.
Valores para o console
| Projeto | build | start |
|---|---|---|
| Express ou Fastify em JavaScript | vazio | node index.js |
| Express ou Fastify em TypeScript | npm run build | node dist/index.js |
| NestJS | npm run build | node dist/main.js |
Use Porta 3000 nos três casos, ou a porta que o código usar.
Sem build, sem devDependencies
Quando o campo build fica vazio, as devDependencies são removidas antes de a aplicação iniciar. Tudo o que o start usa em execução precisa estar em dependencies. Não use ts-node, tsx ou nodemon no start de produção: compile na build e rode o JavaScript gerado.
NestJS
O NestJS compila para dist/ com nest build. Confirme o script:
{
"scripts": {
"build": "nest build",
"start:prod": "node dist/main.js"
}
}O @nestjs/cli pode ficar em devDependencies, porque a build roda com elas instaladas quando o campo build está preenchido.
Para health check com dependências, o pacote @nestjs/terminus expõe uma rota pronta. Mantenha a rota rápida: o health check roda a cada minuto e reinicia a instância em caso de falha.
Migrations
As variáveis do projeto, incluindo DATABASE_URL, existem tanto na build quanto na execução. O jeito mais previsível é aplicar migrations no início do start:
start: npx prisma migrate deploy && node dist/main.jsA ferramenta usada no start precisa estar instalada em execução: em dependencies, ou em devDependencies quando o campo build está preenchido.
Encerramento gracioso
Em cada publicação ou reinício, a instância antiga recebe o sinal SIGTERM. Feche conexões e termine requisições em andamento:
process.on('SIGTERM', () => {
server.close(() => process.exit(0));
});No NestJS, app.enableShutdownHooks() faz isso por você.
WebSockets e Server-Sent Events
Conexões WebSocket e SSE funcionam pela mesma porta HTTP do projeto, inclusive em domínios personalizados. Com várias instâncias, cada conexão fica em uma instância: para enviar mensagens a todos os clientes, use um canal compartilhado, como o cache gerenciado com pub/sub.
Workers e filas
Processos em segundo plano, como consumidores de fila, podem rodar como um projeto separado com o próprio comando start. Veja o exemplo de worker Python e as filas gerenciadas. Se quiser usar o health check em um worker, exponha uma rota /health mínima na porta do projeto.
Problemas comuns
| Sintoma | Correção |
|---|---|
Error: listen EADDRINUSE | Dois servidores tentando a mesma porta. Inicie apenas um processo no start |
| URL pública não responde, logs sem erro | Servidor escutando em localhost. Use 0.0.0.0 |
Cannot find module 'dist/main.js' | Campo build vazio ou outDir diferente no tsconfig.json |
Cannot find module 'ts-node' | Compile na build e rode o JavaScript |
| Erro de CORS no navegador | Configure o domínio do front-end na origem permitida do CORS |
Próximos passos
Última atualização em
Publicar Next.js na Zenifra
Publique uma aplicação Next.js pelo GitHub com build, start, variáveis NEXT_PUBLIC, health check, banco de dados e solução dos erros mais comuns.
Sites estáticos e SPAs (Vite, React, Vue, Astro)
Publique sites estáticos e SPAs feitos com Vite, React, Vue, Angular ou Astro na Zenifra, pelo runtime Node.js ou por uma imagem NGINX oficial.