{"id":31762263,"url":"https://github.com/talesitf/hookinator","last_synced_at":"2026-05-14T12:32:52.251Z","repository":{"id":298262544,"uuid":"999378293","full_name":"talesitf/hookinator","owner":"talesitf","description":"Servidor assíncrono de webhooks em OCaml, com foco em programação funcional, modularidade e arquitetura reativa.","archived":false,"fork":false,"pushed_at":"2025-07-25T03:03:57.000Z","size":18,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-07-25T08:22:01.707Z","etag":null,"topics":["async","demo","functional-programming","http-server","lwt","ocaml","sqlite","webhook"],"latest_commit_sha":null,"homepage":"","language":"OCaml","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/talesitf.png","metadata":{"files":{"readme":"ReadMe.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-06-10T06:56:04.000Z","updated_at":"2025-07-25T03:32:53.000Z","dependencies_parsed_at":"2025-06-10T08:34:14.494Z","dependency_job_id":null,"html_url":"https://github.com/talesitf/hookinator","commit_stats":null,"previous_names":["talesitf/hookinator"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/talesitf/hookinator","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/talesitf%2Fhookinator","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/talesitf%2Fhookinator/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/talesitf%2Fhookinator/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/talesitf%2Fhookinator/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/talesitf","download_url":"https://codeload.github.com/talesitf/hookinator/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/talesitf%2Fhookinator/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":279002123,"owners_count":26083307,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-09T02:00:07.460Z","response_time":59,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["async","demo","functional-programming","http-server","lwt","ocaml","sqlite","webhook"],"created_at":"2025-10-09T22:17:29.886Z","updated_at":"2025-10-09T22:17:32.687Z","avatar_url":"https://github.com/talesitf.png","language":"OCaml","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Hookinator\n\n\u003c!-- Linha 1 — visibilidade geral --\u003e\n![GitHub Repo stars](https://img.shields.io/github/stars/talesitf/hookinator?style=social)\n![GitHub forks](https://img.shields.io/github/forks/talesitf/hookinator?style=social)\n\n\u003c!-- Linha 2 — build, cobertura e licença --\u003e\n![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)\n![OCaml 5.2](https://img.shields.io/badge/OCaml-5.2%2B-orange.svg)\n![Lwt](https://img.shields.io/badge/Lwt-async-blueviolet)\n![Last commit](https://img.shields.io/github/last-commit/talesitf/hookinator)\n\n**Hookinator** é um projeto desenvolvido em **OCaml**, utilizando a biblioteca `Lwt` para construir um servidor assíncrono robusto de webhooks. Seu objetivo é demonstrar como a **programação funcional** pode ser aplicada para tornar a comunicação via webhooks HTTP mais eficiente e robusta, promovendo boas práticas de desenvolvimento.\n\nO projeto simula todo o ciclo de vida de um webhook: recepção via HTTP, validação rigorosa de payloads, persistência de transações em **SQLite** e envio de notificações baseadas em eventos. Boas práticas de arquitetura funcional, logging estruturado e modularização tornam o Hookinator um exemplo prático de como estruturar sistemas reativos com OCaml, facilitando manutenção e evolução do código.\n\n## Funcionalidades\n\n- 🔄 **Processamento de Webhooks**: Recebe e processa webhooks HTTP de forma assíncrona\n- 💾 **Persistência de Dados**: Armazena transações em banco de dados SQLite para auditoria\n- 📧 **Sistema de Notificações**: Envia notificações personalizáveis baseadas nos eventos recebidos\n- ✅ **Validação Robusta**: Valida dados de entrada com verificação de integridade e tipos de eventos\n- 🔧 **Configuração Automática**: Carregamento automático de variáveis de ambiente via arquivo `.env`\n- 🚀 **Alta Performance**: Construído com Lwt para programação assíncrona eficiente\n- 📊 **Logging Estruturado**: Sistema de logs detalhado para monitoramento e debug\n- 🧪 **Testes Integrados**: Suite completa de testes unitários com Alcotest\n\n## Arquitetura\n\nO sistema segue uma arquitetura modular baseada em componentes funcionais:\n\n```\n┌─────────────────┐    ┌──────────────────┐    ┌─────────────────┐\n│   HTTP Client   │───▶│   Hookinator     │───▶│   Database      │\n│   (Webhook)     │◀———│   Server         │    │   (SQLite)      │\n└─────────────────┘    └──────────────────┘    └─────────────────┘\n                              │\n                              ▼\n                       ┌──────────────┐\n                       │ Notification │\n                       │   System     │\n                       └──────────────┘\n```\n\n## Estrutura do Projeto\n\n```\nhookinator/\n├── bin/                    # Executável principal\n│   ├── dune                # Configuração do executável\n│   └── main.ml             # Ponto de entrada da aplicação\n├── lib/                    # Biblioteca principal\n│   ├── config.ml           # Configurações e carregamento do .env\n│   ├── database.ml         # Interface com banco de dados SQLite\n│   ├── dune                # Configuração da biblioteca\n│   ├── handlers.ml         # Manipuladores de requisições HTTP\n│   ├── hookinator.ml       # Módulo principal e API pública\n│   ├── notification.ml     # Sistema de notificações\n│   ├── transaction.ml      # Lógica de transações e modelos\n│   ├── types.ml            # Definições de tipos compartilhados\n│   └── validation.ml       # Validação de dados e schemas\n├── test/                   # Testes\n│   ├── dune                # Configuração de testes\n│   └── test_hookinator.ml  # Testes unitários\n├── .env                    # Configurações de ambiente (criado pelo usuário)\n├── dune-project            # Configuração do projeto Dune\n├── hookinator.opam         # Metadados do pacote OPAM\n├── webhook_transactions.db # Banco de dados SQLite\n└── LICENSE                 # Licença MIT\n```\n\n### Descrição dos Módulos\n\n- **[`bin/main.ml`](bin/main.ml)**: Ponto de entrada que inicializa o servidor HTTP\n- **[`lib/hookinator.ml`](lib/hookinator.ml)**: API principal e orquestração dos componentes\n- **[`lib/config.ml`](lib/config.ml)**: Gerenciamento de configurações\n- **[`lib/handlers.ml`](lib/handlers.ml)**: Manipuladores de rotas HTTP e processamento de webhooks\n- **[`lib/database.ml`](lib/database.ml)**: Camada de abstração para operações com SQLite\n- **[`lib/transaction.ml`](lib/transaction.ml)**: Modelos de dados e lógica de transações\n- **[`lib/notification.ml`](lib/notification.ml)**: Sistema de envio de notificações\n- **[`lib/validation.ml`](lib/validation.ml)**: Validação robusta de payloads e eventos\n- **[`lib/types.ml`](lib/types.ml)**: Tipos de dados compartilhados entre módulos\n\n## Início Rápido\n\n### Pré-requisitos\n\n- **OCaml** \u003e= 5.2.0\n- **Dune** \u003e= 3.0\n- **OPAM** \u003e= 2.1\n\n#### Dependências OCaml\n\nAs dependências são gerenciadas pelo arquivo [`hookinator.opam`](hookinator.opam).\n\n### Instalação\n\n1. **Clone o repositório**:\n\n   ```bash\n   git clone \u003crepository-url\u003e\n   cd hookinator\n   ```\n\n2. **Configure o ambiente OCaml**:\n\n   ```bash\n   # Se necessário, crie um switch local\n   opam switch create . 5.2.0\n\n   # Instale as dependências\n   opam install . --deps-only --with-test\n   ```\n\n3. **Compile o projeto**:\n\n   ```bash\n   dune build\n   ```\n\n### Configuração\n\n#### Arquivo .env\n\nO Hookinator carrega automaticamente as configurações do arquivo `.env`. Crie um arquivo `.env` na raiz do projeto baseado no exemplo:\n\n```bash\n# Copie o arquivo de exemplo\ncp .env.example .env\n\n# Edite com suas configurações\nnano .env\n```\n\n### Executando\n\n#### Subir variáveis de ambiente\n\nPara iniciar o servidor, você pode definir as variáveis de ambiente diretamente ou usar um arquivo `.env` com o arquivo `env_setup.sh`:\n\n```bash\nsource env_setup.sh\n```\n\n#### Iniciar o Servidor\n\n```bash\n# Executar diretamente\ndune exec hookinator\n\n# Em modo de desenvolvimento (com logs verbosos)\nHOOKINATOR_LOG_LEVEL=debug dune exec hookinator\n\n# Especificar porta customizada (sobrescreve .env)\nHOOKINATOR_PORT=8080 dune exec hookinator\n```\n\nO servidor estará disponível em `http://localhost:3000` (ou na porta especificada).\n\n#### Variáveis de Ambiente\n\n| Variável | Padrão | Descrição |\n|----------|--------|-----------|\n| `HOOKINATOR_PORT` | `3000` | Porta do servidor HTTP |\n| `HOOKINATOR_DB_PATH` | `webhook_transactions.db` | Caminho do banco SQLite |\n| `HOOKINATOR_LOG_LEVEL` | `info` | Nível de log (`debug`, `info`, `warn`, `error`) |\n| `HOOKINATOR_TOKEN` | *(obrigatório)* | Token de autenticação para webhooks |\n| `HOOKINATOR_EXPECTED_AMOUNT` | `49.90` | Valor esperado para validação |\n| `HOOKINATOR_EXPECTED_CURRENCY` | `BRL` | Moeda esperada para validação |\n| `HOOKINATOR_CONFIRM_URL` | `http://localhost:8000/confirmar` | URL de confirmação |\n| `HOOKINATOR_CANCEL_URL` | `http://localhost:8000/cancelar` | URL de cancelamento |\n| `HOOKINATOR_MAX_PAYLOAD_SIZE` | `1048576` | Tamanho máximo do payload (bytes) |\n| `HOOKINATOR_MIN_TRANSACTION_ID_LENGTH` | `5` | Tamanho mínimo do ID da transação |\n\n### Webhooks\n\n#### Exemplo de Payload de Webhook\n\n```json\n{ \n  \"event\": \"payment_success\",\n  \"transaction_id\": \"abc123\",\n  \"amount\": \"49.90\",\n  \"currency\": \"BRL\",\n  \"timestamp\": \"2024-01-01T12:00:00Z\" \n}\n```\n\n#### Eventos Válidos\n\nO sistema valida rigorosamente os tipos de eventos aceitos:\n\n- `payment_success` - Pagamento processado com sucesso\n- `payment_failed` - Falha no processamento do pagamento\n- `payment_pending` - Pagamento pendente de confirmação\n- `subscription_created` - Nova assinatura criada\n- `subscription_cancelled` - Assinatura cancelada\n- `refund_processed` - Reembolso processado\n\n#### Endpoints Disponíveis\n\n- `POST /webhook` - Receber webhooks (requer token de autenticação)\n- `GET /health` - Status do serviço\n- `GET /metrics` - Métricas básicas (opcional)\n\n## Testando\n\n### Testes Unitários\n\nO projeto inclui uma suíte completa de testes que carrega automaticamente as configurações do `.env`:\n\n```bash\n# Executar todos os testes\ndune test\n\n# Executar com saída verbosa\ndune test --verbose\n\n# Executar testes específicos\ndune exec test/test_hookinator.exe\n```\n\nOs testes cobrem:\n\n- Validação de payloads válidos e inválidos\n- Verificação de tipos de eventos\n- Autenticação de transações\n- Validação de configurações\n\n### Teste de Integração\n\nO projeto inclui um script Python para testar o endpoint de webhook:\n\n```bash\n# Certifique-se de que o servidor está rodando\ndune exec hookinator \u0026\n\n# Execute o teste\npython test_webhook.py\n\n# Parar o servidor\nkill %1\n```\n\n### Teste Manual com cURL\n\n```bash\n# Testar endpoint de webhook com evento válido\ncurl -X POST http://localhost:3000/webhook \\\n  -H \"Content-Type: application/json\" \\\n  -H \"Authorization: Bearer seu-token-secreto-aqui\" \\\n  -d '{\n    \"event\": \"payment_success\",\n    \"transaction_id\": \"test123\",\n    \"amount\": \"49.90\",\n    \"currency\": \"BRL\",\n    \"timestamp\": \"2024-01-01T12:00:00Z\"\n  }'\n\n# Testar com evento inválido\ncurl -X POST http://localhost:3000/webhook \\\n  -H \"Content-Type: application/json\" \\\n  -H \"Authorization: Bearer seu-token-secreto-aqui\" \\\n  -d '{\n    \"event\": \"invalid_event\",\n    \"transaction_id\": \"test123\",\n    \"amount\": \"49.90\",\n    \"currency\": \"BRL\",\n    \"timestamp\": \"2024-01-01T12:00:00Z\"\n  }'\n\n# Verificar saúde do serviço\ncurl http://localhost:3000/health\n```\n\n## Monitoramento\n\n### Logs\n\nO Hookinator utiliza logging estruturado com diferentes níveis de verbosidade. Os logs incluem:\n\n- Requisições recebidas\n- Transações processadas\n- Validações de eventos\n- Erros de validação\n- Notificações enviadas\n- Carregamento de configurações\n\n### Persistência de Dados\n\nO banco de dados SQLite ([`webhook_transactions.db`](webhook_transactions.db)) armazena:\n\n- Histórico de todas as transações\n- Timestamps de processamento\n- Status de processamento\n- Metadados dos webhooks\n\n## Segurança\n\n- **Validação de token**: Autenticação obrigatória via header Authorization\n- **Validação de eventos**: Apenas eventos predefinidos são aceitos\n- **Limitação de payload**: Tamanho máximo configurável\n- **Sanitização de dados**: Validação rigorosa de tipos e formatos\n- **Logs de auditoria**: Registro completo de todas as operações\n- **Configuração segura**: Carregamento automático de variáveis sensíveis via `.env`\n\n## Contribuição\n\nContribuições são bem-vindas! Para contribuir:\n\n1. Fork o projeto\n2. Crie uma branch para sua feature (`git checkout -b feature/AmazingFeature`)\n3. Commit suas mudanças (`git commit -m 'Add some AmazingFeature'`)\n4. Push para a branch (`git push origin feature/AmazingFeature`)\n5. Abra um Pull Request\n\n### Padrões de Código\n\n- Use `dune fmt` para formatação\n- Execute `dune test` antes de commits\n- Siga as convenções de naming do OCaml\n- Documente funções públicas\n- Mantenha o arquivo `.env.example` atualizado\n- Adicione testes para novas funcionalidades\n\n## Licença\n\nEste projeto está licenciado sob a Licença MIT - veja o arquivo [LICENSE](LICENSE) para detalhes.\n\n---\n\n⭐ Se este projeto foi útil, considere dar uma estrela no GitHub!\n\n\u003e O Hookinator foi idealizado como uma demonstração técnica para explorar, de forma aplicada, conceitos aprendidos em sala de aula sobre programação funcional, concorrência assíncrona e arquitetura de sistemas distribuídos.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftalesitf%2Fhookinator","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftalesitf%2Fhookinator","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftalesitf%2Fhookinator/lists"}