O Back End é a parte da aplicação que roda no servidor, longe do navegador da pessoa, e que fica esperando uma requisição chegar para decidir o que fazer com ela: qual rota (ex: /cursos, /contato e /conta) foi acessada, se o usuário está logado, o que precisa ser lido ou escrito no banco de dados e qual resposta vai voltar. Quando você abre a página de cursos da Origamid, o navegador manda uma requisição, e todo o trabalho de buscar esses cursos no banco de dados e devolver a lista acontece no Back End.

O Back End é feito de algumas peças que aparecem em quase todo projeto, e cada uma delas vem abaixo com um exemplo curto em Node.js. Os exemplos abaixo são um esboço de como cada peça vai ser usada depois de construída, e não um código para copiar e rodar (o código completo geralmente é maior e cabe um curso para ensinar o mesmo). A ideia é você ter a visão geral de como as peças se encaixam antes de construir qualquer uma delas.
O servidor do back end e a porta
A primeira coisa que um back end precisa é de um servidor. Iniciar um servidor significa fazer a sua máquina passar a aceitar conexões numa porta, que é um número que identifica por onde as conexões chegam. O Node tem uma função nativa para isso, a createServer, do módulo node:http:
import { createServer } from "node:http";
const app = createServer((request, response) => {
response.end("Servidor Funcionando");
});
app.listen(3000);
O listen(3000) deixa o servidor escutando qualquer conexão na porta 3000. Com ele rodando (node server.js no terminal), quando você acessa localhost:3000 no navegador, o que aparece na tela é o texto que o servidor enviou, “Servidor Funcionando”. A função passada para o createServer executa a cada requisição que chega, e o response.end() é o que encerra a resposta e manda o conteúdo de volta.
Apenas com esse código já temos um Back End funcionando, o problema é que ele que responde a mesma coisa para qualquer endereço que você acessar, seja /cursos, /login ou qualquer outro. Para responder de forma diferente em cada caminho, você precisa de um router, que registra cada rota e liga ela à função que vai responder.
Rotas e handler
O que é uma rota? É o caminho que a pessoa acessa. Quando ela entra em origamid.com/cursos, /cursos é uma rota, e /login é outra. Para cada rota acessada o back end deve responder de um jeito diferente, e a função que faz essa resposta se chama handler. É dentro dela que você acessa o banco de dados, escreve ou deleta alguma coisa, e faz o que for necessário para aquele caminho.
O router é a peça que registra essas rotas e liga cada uma ao seu handler, para que uma função execute quando a pessoa acessar /cursos, outra quando acessar a raiz e outra para /aulas. O registro de uma rota costuma ter esta forma:
function coursesHandler(request, response) {
response.end("Cursos de Front End e Back End");
}
app.get("/cursos", coursesHandler);
Primeiro vem o método, depois a rota e por último o handler. O método get é o que o navegador usa quando você simplesmente entra numa página, e o post é o que se usa para enviar informações, como os dados de um formulário. É comum também escrever o handler direto, como uma arrow function:
app.get("/cursos", (request, response) => {
response.end("Cursos de Front End e Front End");
});
O createServer do Node não tem esse app.get. Ele entrega toda requisição para a mesma função, e o router é algo que você constrói em cima dela. Os frameworks de back end trazem um pronto, como Express, Fastify ou Honor.
Request e Response
Todo handler recebe dois objetos, o request e o response, e você vai lidar com os dois o tempo inteiro. O request são os dados que vieram com a requisição: o caminho que foi acessado (que é de onde o router tira a rota), o IP do cliente, o corpo da requisição quando um formulário enviou algum dado, e várias outras informações. O response é o que você usa para responder.
Um exemplo de uma rota que cria um curso:
app.post("/criar/curso", (request, response) => {
const { name, lessons } = request.body;
db.createCourse(name, lessons);
response.end("Curso Criado");
});
A pessoa envia um post para /criar/curso com o nome do curso e as aulas no corpo. O handler pega esses dados do request.body, cria o curso no banco de dados e usa o response para avisar que o curso foi criado. Quase toda rota que você vai escrever segue esse mesmo ciclo, que é receber o dado, fazer alguma coisa com ele no banco e devolver uma resposta.
Middleware
Um middleware é uma função que executa antes do handler, ou seja, antes daquela função final que responde a rota. Quase sempre existem outros processos que precisam acontecer antes da resposta, e o exemplo mais comum é a autenticação. Quando a pessoa acessa /cursos, antes de mostrar o curso ou liberar uma aula, eu quero saber se ela está logada. Essa verificação é o middleware, e ele tem esse nome porque roda no meio, entre a requisição e a resposta.
function auth(req) {
return db.validateSession(req.cookie);
}
app.get(
"/cursos",
(req, res) => {
res.end("Cursos de Front End e Back End");
},
[auth]
);
A rota continua com o seu handler, e agora ganha uma array com a lista de middlewares que executam antes da resposta final. Neste exemplo, request e response viraram req e res só para encurtar, porque são parâmetros da função e podem ter o nome que você quiser.
O caminho completo de uma requisição até a resposta fica assim:

O body chega em pedaços
No exemplo de criar curso, o request.body aparece prontinho, mas no Node.js ele não vem assim. O corpo da requisição não chega de uma vez, ele chega de parte em parte (é uma stream). Pense num arquivo grande sendo enviado: a internet funciona como um cano, e o dado passa em pedaços, nunca tudo junto. Por isso o back end precisa receber esses pedaços, juntar todos eles, transformar em string e só depois fazer o parse com JSON.parse:
async function bodyParser(req) {
const chunks = [];
for await (const chunk of req) {
chunks.push(chunk);
}
const body = Buffer.concat(chunks).toString("utf-8");
return JSON.parse(body);
}
O for await funciona porque o objeto da requisição no Node é uma stream que pode ser lida aos poucos. Cada chunk é um pedaço do corpo, o Buffer.concat junta todos eles e o toString("utf-8") transforma o resultado em texto. Esse é um dos pontos em que o Node puro te obriga a entender o que está acontecendo, porque nada disso é automático.
Banco de Dados e Sessão
O back end precisa de uma forma de se conectar a um banco de dados para ler, escrever e atualizar o que for necessário. Nos exemplos o banco é o SQLite, e o Node já traz um módulo nativo para ele, o node:sqlite. Com a conexão aberta, você executa os seus comandos SQL, como SELECT, INSERT, UPDATE e CREATE TABLE, direto do Node:
import { Database } from "node:sqlite";
const db = new Database("./db.sqlite");
db.prepare('SELECT * FROM "users" WHERE "id" = ?').get(1);
O prepare prepara a consulta e o get(1) executa trocando o ? pelo valor 1, devolvendo a primeira linha encontrada, que nesse caso é o usuário de id 1.
Com o banco funcionando, dá para autenticar o usuário através de sessões. A sessão é criada no primeiro login, quando a pessoa manda o e-mail e a senha: o back end gera um cookie (que é apenas um pequeno texto) na máquina do usuário e um registro no banco de dados. Nas próximas vezes que ela acessar o site ou a API, você não precisa pedir login e senha de novo, porque o navegador manda o cookie automaticamente e o back end só confere no banco se aquele cookie é válido para liberar a sessão.
app.post("/login", (req, res) => {
const { email, password } = req.body;
createSession(email, password);
res.end("logged");
});
app.get("/session", (req, res) => {
validateSession(req.cookies);
res.end("valid");
});
É essa validação de sessão que o middleware auth faz antes de liberar a rota de cursos.
Validação de Dados
Outra peça é a validação dos dados. O dado vem do usuário, e o back end não confia nele, porque a pessoa pode mandar qualquer coisa. Você valida se o e-mail tem mesmo cara de e-mail, com arroba e ponto, e não é um texto qualquer só para gerar um cadastro de spam no seu banco. Valida também se a senha cumpre os padrões que você definiu, por exemplo ter mais de 10 caracteres, pelo menos um número, um caractere especial e uma letra maiúscula:
app.post("/login", (req, res) => {
const email = validate.email(req.body.email);
const password = validate.password(req.body.password);
});
Outras Funções
O que vimos até aqui ocupa mais de 80% do que o Back End faz, porém nada é tão simples. Nele você vai precisar lidar também com disparo de emails (a pessoa esqueceu a senha), filas (requisições pesadas, por exemplo uma exportação grande de dados, geralmente entram em uma fila que é executada automaticamente pelo servidor, e apenas depois notifica o usuário), rate-limit (limitar quantas vezes uma máquina pode acessar por segundo uma rota específica) e mais.
