git clone git@github.com:boundlessend/shorto.git
cd shortomacOS / linux:
python3 -m venv venv
source venv/bin/activatewin powershell:
python -m venv venv
.\venv\Scripts\Activate.ps1python -m pip install --upgrade pip
python -m pip install -r requirements.txtuvicorn app.main:app --reloadпосле старта сервис будет тут:
- API:
http://127.0.0.1:8000 - Swagger UI:
http://127.0.0.1:8000/docs
pytest .POST /links
пример тела запроса:
{
"original_url": "https://example.com/very/long/path",
"custom_code": "my-link",
"expires_in_seconds": 3600
}поля:
original_url— обязательный URL;custom_code— опциональный кастомный код;expires_in_seconds— опциональный TTL в секундах.
пример успешного ответа:
{
"original_url": "https://example.com/very/long/path",
"code": "my-link",
"short_url": "http://127.0.0.1:8000/my-link",
"created_at": "2026-03-25T10:00:00Z",
"expires_at": "2026-03-25T11:00:00Z",
"is_active": true
}GET /{code}
- если ссылка существует и активна — происходит редирект;
- если ссылка не найдена —
404; - если срок жизни истек —
410; - если ссылка деактивирована —
410.
GET /links/{code}
пример ответа:
{
"original_url": "https://example.com/very/long/path",
"code": "my-link",
"created_at": "2026-03-25T10:00:00Z",
"expires_at": "2026-03-25T11:00:00Z",
"clicks": 3,
"is_active": true,
"is_deleted": false
}DELETE /links/{code}
пример ответа:
{
"message": "Ссылку деактивировали, всё ок.",
"code": "my-link",
"is_active": false
}GET /links
возвращает массив всех ссылок с базовой информацией.
ответ ошибки приходит единообразно:
{
"error": {
"code": "validation_error",
"message": "Request validation failed.",
"details": [
{
"type": "url_parsing",
"loc": ["body", "original_url"],
"msg": "Input should be a valid URL"
}
]
}
}примеры кодов ошибок:
validation_errorcustom_code_already_existslink_not_foundlink_expiredlink_inactive
curl -X POST "http://127.0.0.1:8000/links" \
-H "Content-Type: application/json" \
-d '{
"original_url": "https://example.com/long/path"
}'curl -X POST "http://127.0.0.1:8000/links" \
-H "Content-Type: application/json" \
-d '{
"original_url": "https://example.com/custom",
"custom_code": "my-custom-code"
}'curl -X POST "http://127.0.0.1:8000/links" \
-H "Content-Type: application/json" \
-d '{
"original_url": "https://example.com/temp",
"expires_in_seconds": 60
}'curl "http://127.0.0.1:8000/links/my-custom-code"curl -i "http://127.0.0.1:8000/my-custom-code"curl -X POST "http://127.0.0.1:8000/links" \
-H "Content-Type: application/json" \
-d '{
"original_url": "https://example.com/another",
"custom_code": "my-custom-code"
}'ожидается 409 Conflict.
curl -X DELETE "http://127.0.0.1:8000/links/my-custom-code"
curl -i "http://127.0.0.1:8000/my-custom-code"после деактивации ожидается 410 Gone.
- мб постоянное хранилище (
PostgreSQL/Redis). - добавляем rate limiting
- хз, добавить удаление просроченных ссылок фоном
- добавить owner/user и авторизацию
- добавить более гибкий фильтр и пагинацию для списка ссылок
- Добавить конфигурацию через
.env - Добавить логирование и middleware для request-id