API de encurtamento de URLs com Django e PostgreSQL. Implementa criação, listagem, consulta e exclusão de links, redirecionamento e contador de acessos.
Python, Django, Django REST Framework, PostgreSQL e Docker Compose.
| Método | Caminho | Função | Sucesso |
|---|---|---|---|
| POST | /api/links/ |
Criar um link | 201 |
| GET | /api/links/ |
Listar os links | 200 |
| GET | /api/links/<code>/ |
Consultar um link | 200 |
| DELETE | /api/links/<code>/ |
Excluir um link | 204 |
| GET | /<code>/ |
Redirecionar e registrar um acesso | 302 |
Use a barra final dos caminhos. Os detalhes de entrada, resposta e verificação estão nas seções abaixo.
config/: configurações e rotas gerais do Django.links/: modelo, serializer, view, rotas e testes dos links.manage.py: comandos de gerenciamento do Django.compose.yaml: banco PostgreSQL para desenvolvimento local.
Requer Python 3.14 e Docker com Compose. O Compose inicia somente o PostgreSQL; a API e os testes são executados no Python local pela .venv. Na primeira execução, crie .env a partir de .env.example e substitua DJANGO_SECRET_KEY e POSTGRES_PASSWORD por valores aleatórios. Mantenha os demais valores do exemplo para usar o PostgreSQL na porta 5432.
python3 -m venv .venv
.venv/bin/pip install -r requirements.txt
cp .env.example .envEdite .env antes de iniciar o banco. O arquivo é ignorado pelo Git. Se já existir, não o substitua com cp.
Depois de configurar os valores:
set -a
source .env
set +a
docker compose config --quiet
docker compose up -d db
docker compose exec db sh -c 'pg_isready -U "$POSTGRES_USER" -d "$POSTGRES_DB"'
.venv/bin/python manage.py migrate
.venv/bin/python manage.py showmigrations linksO comando pg_isready deve indicar que o banco aceita conexões antes de aplicar as migrations. Se o banco ainda estiver iniciando, repita esse comando antes de continuar. showmigrations links deve mostrar [X] 0001_initial.
Na raiz do projeto, com o banco iniciado, carregue as variáveis e inicie o servidor local:
set -a
source .env
set +a
.venv/bin/python manage.py runserverPOST /api/links/ recebe original_url. A URL deve usar HTTP ou HTTPS e ter no máximo 2.048 caracteres. O endpoint é público e não exige autenticação.
Com o servidor iniciado, execute em outro terminal:
curl -i -X POST http://127.0.0.1:8000/api/links/ \
-H 'Content-Type: application/json' \
-d '{"original_url":"https://www.djangoproject.com/"}'A resposta de sucesso tem status 201 Created e os campos id, original_url, code, short_url, access_count e created_at. O código tem oito caracteres e o contador começa em zero. Uma entrada inválida retorna 400 Bad Request.
O servidor controla o código, o contador e a data de criação. Cada criação produz um novo link, mesmo quando a URL original já foi cadastrada. O banco garante a unicidade do código; em caso de colisão, a API tenta gerar outro, com limite de cinco tentativas. Se todas colidirem, retorna 500.
O campo short_url usa o endereço da requisição e pode ser acessado para redirecionar à URL original.
Os endpoints são públicos, não exigem autenticação e não recebem corpo:
| Método e caminho | Resultado |
|---|---|
GET /api/links/ |
200 com uma lista de links, dos mais recentes aos mais antigos |
GET /api/links/<code>/ |
200 com os dados do link identificado pelo código |
A listagem retorna todos os registros, sem paginação. Se não houver links, retorna uma lista vazia ([]). Cada registro contém id, original_url, code, short_url, access_count e created_at. A consulta de um código inexistente retorna 404.
Listar ou consultar os dados não incrementa o contador. Somente acessar a URL de redirecionamento registra um acesso. O endereço da consulta individual também aceita exclusão por DELETE; POST, PUT e PATCH retornam 405.
Para verificar no Thunder Client:
- Envie GET para
http://127.0.0.1:8000/api/links/. - Copie um código da resposta e envie GET para
http://127.0.0.1:8000/api/links/<code>/, substituindo<code>pelo valor copiado. - Anote o contador, acesse a
short_urluma vez e consulte os dados novamente. O contador deve aumentar em um; repetir apenas a consulta deve manter esse valor. - Consulte um código inexistente e confirme o status 404.
DELETE /api/links/<code>/ remove definitivamente o registro identificado pelo código, incluindo seu contador e data de criação. A resposta de sucesso é 204 No Content, sem corpo. A página original permanece disponível no seu próprio endereço.
Após excluir, o link deixa de aparecer na listagem e a consulta e o redirecionamento desse código retornam 404. Os demais links permanecem intactos. Excluir um código inexistente ou repetir a exclusão retorna 404. DELETE na coleção /api/links/, sem código, retorna 405.
O endpoint é público, não exige autenticação e não recebe corpo. Qualquer cliente que conheça o código pode excluir o link.
Para verificar no Thunder Client, crie um link de teste e use o código retornado:
| Método e URL | Resultado esperado |
|---|---|
GET http://127.0.0.1:8000/api/links/<code>/ |
200 antes da exclusão |
DELETE http://127.0.0.1:8000/api/links/<code>/ |
204, com corpo vazio |
GET http://127.0.0.1:8000/api/links/<code>/ |
404 após a exclusão |
GET http://127.0.0.1:8000/<code>/ |
404 após a exclusão |
GET http://127.0.0.1:8000/api/links/ |
200, sem o link removido |
Substitua <code> pelo valor criado e mantenha a barra final das URLs.
GET /<code>/ recebe o código criado pela API, incrementa o contador e responde com 302 Found. O cabeçalho Location contém a URL original; navegadores normalmente seguem esse destino automaticamente. O endpoint é público, não exige autenticação e não recebe corpo.
Cada GET válido soma um acesso, inclusive acessos repetidos. O contador registra requisições, não pessoas únicas. O incremento usa uma expressão F() no banco para evitar perda de contagem em acessos simultâneos. A resposta inclui instruções contra armazenamento em cache.
Um código inexistente retorna 404. Métodos diferentes de GET, incluindo POST e HEAD, retornam 405, sem incrementar o contador.
Com o servidor local iniciado:
- Envie o POST de criação e copie a
short_urlretornada. - Desative o seguimento automático de redirecionamentos (Follow Redirects) nas configurações do Thunder Client para observar a resposta da API.
- Envie um GET para a
short_url, sem corpo ou autenticação.
Resultados esperados:
| Requisição | Resultado |
|---|---|
| GET na URL curta existente | 302 e cabeçalho Location com a URL original |
| GET com código inexistente | 404 |
| POST na URL curta | 405 |
Os testes automatizados também verificam a contagem salva no banco. Para experimentar o comportamento no navegador, abra a URL curta; ele deve encaminhar para a página original.
Instale as dependências de desenvolvimento e execute os testes com o PostgreSQL iniciado:
.venv/bin/pip install -r requirements-dev.txt
set -a
source .env
set +a
.venv/bin/python -m pytest -qOs testes de integração verificam criação, validação, campos controlados pelo servidor, colisões de código, listagem, consulta por código, exclusão e seus efeitos nos endpoints, redirecionamento, contagem de acessos e métodos HTTP permitidos. O teste de métodos do redirecionamento mantém a verificação CSRF ativa para reproduzir requisições reais sem token. O pytest-django cria um banco de testes separado; o usuário PostgreSQL precisa ter permissão para criar bancos, como ocorre na configuração local do Compose.
Distribuído sob a licença MIT. Consulte LICENSE.