Criei meu próprio web framework do zero! (e ele roda com o bun)

Recentemente, numa entrevista de emprego, me deparei com o seguinte desafio: criar um framework web do zero, com o menor número possível de dependências. Esse foi um dos processos mais divertidos e educativos que já passei e, mesmo depois de terminada a fase de testes, segui trabalhando no projeto que resultou no unicorn.web: meu próprio web framework.

Sobre o Bun…

Depois de finalizar o processo, optei por trocar o interpretador por baixo do framework do node para o bun. Primeiro porque queria experimentar esse novo e tão falado interpretador, mas também porque ele prometia aumentar em até 5x a performance de qualquer aplicação javascript e isso muito me interessava.

A primeira coisa que notei foi como a experiência de desenvolvimento com o bun é superior à do node. Com ele você pode rodar arquivos typescript nativamente, sem nenhuma configuração adicional. Possui um resolvedor de módulos realmente fenomenal, que facilita muito a vida na hora de importar e exportar arquivos e uma documentação bastante objetiva e de fácil absorção. Além de já vir com um módulo de testes muito semelhante ao Jest (mas infinitamente mais rápido). Ainda que o Bun não entregasse a performance que ele promete só essas características já o fariam valer a pena e me economizaram algumas horas de trabalho de setup.

Além disso, sua performance é realmente impressionante, sua inicialização extremamente rápida e um teste de carga simples mostrou a capacidade de segurar até 40 mil requests por segundo na minha máquina.

Sobre o framework

Só para ficar claro… este não é um framework para ser usado em um ambiente de produção (ainda). A ideia aqui era escrever algo simples, muito fácil de aprender e utilizar. Um framework leve, para testar conceitos e desenvolver pequenos projetos.

Na prática, isso significava que o usuário deveria ser capaz de subir uma API com apenas 3 ou 4 linhas e esse objetivo foi alcançado! Depois de installar o Bun e adicionar o framework como dependência, com apenas três linhas você consegue criar uma rota GET simples.

bun add @unicorn.web/core
import { UnicornServer } from '@unicorn.web/core'

const server = new UnicornServer();
server.get('/health', () => new Response("I'm working!"));
server.serve(3000);

Se você precisar de rotas mais complexas, basta adicionar a lógica dentro do callback. Também é possível extrair dados da request (query, body, params e headers) adicionando um parâmetro Context

import { UnicornServer } from '@unicorn.web/core'

const server = new UnicornServer();
server.get('/hi', (ctx: Context) => {
  return new Reponse(`Hi ${ctx.query.name}!`);
});
server.serve(3000);

Por fim, para rodar sua aplicação, um simples bun run index.ts resolve todos os seus problemas.

Conclusão Mais do que tracionar o framework, o objetivo aqui foi entender de vez o que roda por baixo dos frameworks que eu utilizo no trabalho e no dia a dia. Entender como subir um servidor web “cru”, como processar os requests que esse servidor recebe, onde buscar as informações contidas nestas requests e muito mais.

Desafios surgiram no caminho. Um bom exemplo: como fazer matching das rotas que possuem patterns em suas definições (Exemplo: GET /pessoa/:id) e extrair seus parâmetros? Uma aula de regex e estruturas de dados como tries.

Certamente, me aventurar nesse universo mais “baixo nível” e abandonar as abstrações que frameworks como nest ou adonis nos proporcionam foi muito positivo e me ensinou muita coisa. Como uma desenvolvedora backend, hoje entendo melhor como os servidores web funcionam, o que de fato é o protocolo HTTP e o que está por trás de todo o processo de comunicação entre clientes e servidores no universo web.

Se alguém quiser dar sugestões e contribuir com o projeto, ele é completamente open source, fiquem à vontade para abrir issues e enviar pull requests (ou comentar aqui mesmo rs).

Precisamos de mais pessoas fazendo isso.

Eu também criei algumas bibliotecas voltadas para o frontend e conheço algumas outras que foram criadas para fins semelhantes.

Saber como as coisas funcionam por trás dos lençois é a chave para realmente entender o que fazemos.

Eu desenvolvi o IARES: https://www.npmjs.com/package/iares

IARES é uma biblioteca voltada a construir aplicações (SPA) reativas e que te ajuda a aplicar com eficiencia DRY, YAGNI, KISS etc...

Também conheço outras bibliotecas que de inicio foram criadas para ajudar a aprender e agora são usadas para desenvolver soluções reais.

1 - JAILS - https://jails-js.org/ 2 - BEMTV - https://bemtv.gitbook.io/bemtvjs/

Eu acho incrível a capacidade criativa que temos para aplicar e construir soluções tão originais. Muito bacana sua iniciativa.

Sinto que nos acostumamos muito a ter tudo na palma das mão com os novos frameworks, isso faz com que alguns negligênciem uma das partes fundamentais, na minha humilde opinião, do caminho para ser um bom desenvolvedor: entender, nem que seja o básico, dos processos envolvidos. Ultimamente, em meus estudos, acabei sentindo que dependia muito de ferramentas prontas, e que sempre recorria a elas até mesmo para tarefas simples. Uma das formas que encontrei pra tentar limpar esse mal hábito foi buscar por como essas ferramentas, ou alguns dos conceitos que elas utilizam, de fato funcionam. Acredito que é essa visão é algo que vem com o tempo, ou quando há a necessidade de resovolver um problema específico, que necessita de um conhecimento mais profundo.

Que leegaal, amei o seu projeto 💅.

Eu ainda não tive a oportunidade de experimentar o bun, estou doida para isso.

E sobre criar um framework do zero: Eu estou trabalhando em um projeto super legal, e lá implementamos um servidor completo no node.js com sistema de autenticação, sistemas de segurança voltados para API... e MAIS UM MONTEEEEE de coisas ✨ E se não fosse por essas coisas, eu não teria o conhecimento que tenho hoje, implementar tudo isso me fez aprender muito sobre os fluxos. Detalhe: Agora definitivamente não sou mais dependente do auth0. Mas ainda sou viciada no JWT 🙁💖.