Text-to-API: перетворюємо опис у готовий REST API
Розробка API з нуля — процес, де кожна помилка в дизайні або моделях даних виливається в години переписування коду. Ми стикалися з проєктами, де команди витрачали тижні на створення CRUD і документації, а бізнес-логіка залишалася незакритою. Text-to-API вирішує це: ви описуєте систему словами — ми генеруємо готовий код на FastAPI або Express з тестами, Docker і документацією. Наш досвід показує, що time-to-market скорочується в 3–5 разів, а витрати на шаблонний код — до 80%.
"Text-to-API економить до 80% часу на CRUD-операціях" — з досвіду наших проєктів.
Проблеми, які вирішує Text-to-API
Чому AI-генерація швидша?
Ручне написання ендпоїнтів, моделей даних, схем валідації та тестів займає до 70% часу бекенд-розробника. AI бере на себе шаблонну роботу: парсить опис, будує специфікацію OpenAPI, генерує моделі Pydantic, роутери та тести. Залишається лише бізнес-логіка, яка дійсно потребує уваги.
Які проблеми вирішуємо?
- Дизайн API. Неправильні URL, методи HTTP, статуси відповіді — часта біль. AI дотримується REST-конвенцій: іменники у множині, правильні коди (201 для POST, 204 для DELETE).
- Моделі та схеми. Узгодження типів полів, обов'язковості, вкладеності. Генератор створює SQLAlchemy моделі та Pydantic схеми з валідаторами.
- Тестування. Автоматично генеруються pytest-тести для кожного ендпоїнта, що покривають happy path, 404, валідацію вхідних даних. Тестове покриття сягає 70%.
Архітектура генератора та стек
В основі — мовні моделі (Claude, GPT-4) з тонким налаштуванням промптів через LangChain. Специфікація API парситься в Pydantic-моделі, потім генерується код. Використовуємо структурний вивід: модель повертає валідний JSON, який перетворюється на APISpec.
from anthropic import Anthropic
from pathlib import Path
import json
from pydantic import BaseModel
from typing import Literal, Optional
client = Anthropic()
class APIEndpoint(BaseModel):
method: Literal["GET", "POST", "PUT", "PATCH", "DELETE"]
path: str
summary: str
request_body: Optional[dict] = None
response_schema: dict
auth_required: bool = True
query_params: list[dict] = []
class APISpec(BaseModel):
title: str
description: str
version: str
base_path: str
endpoints: list[APIEndpoint]
entities: list[dict]
class TextToAPIGenerator:
def parse_description(self, description: str) -> APISpec:
response = client.messages.create(
model="claude-sonnet-4-5",
max_tokens=4096,
system="""Ты — API-архитектор. Парсишь описание системы в структуру REST API.
Правила REST:
- Существительные в URL (не глаголы): /users, /orders
- Правильные HTTP методы: GET=чтение, POST=создание, PUT=полная замена, PATCH=частичное обновление, DELETE=удаление
- Вложенность максимум 2 уровня: /users/{id}/orders
- Plural для коллекций: /products, /categories
- Пагинация: ?page=1&limit=20
- Фильтрация: ?status=active&created_after=2024-01-01""",
messages=[{
"role": "user",
"content": f"""Разбери описание и верни JSON спецификацию API:
{{
"title": "...",
"description": "...",
"version": "1.0.0",
"base_path": "/api/v1",
"entities": [
{{"name": "...", "fields": [{{"name": "...", "type": "...", "required": true}}]}}
],
"endpoints": [
{{
"method": "GET|POST|PUT|PATCH|DELETE",
"path": "/resource/{{id}}",
"summary": "...",
"auth_required": true,
"request_body": {{"field": "type"}},
"response_schema": {{"id": "int", "name": "str"}},
"query_params": [{{"name": "...", "type": "...", "required": false}}]
}}
]
}}
Описание системы:
{description}"""
}]
)
text = response.content[0].text
start = text.find("{")
end = text.rfind("}") + 1
data = json.loads(text[start:end])
return APISpec(**data)
def generate_fastapi_code(self, spec: APISpec) -> dict[str, str]:
files = {}
files["models.py"] = self._generate_models(spec)
files["schemas.py"] = self._generate_schemas(spec)
for entity in spec.entities:
router_code = self._generate_router(entity, spec)
files[f"routers/{entity['name'].lower()}.py"] = router_code
files["main.py"] = self._generate_main(spec)
for entity in spec.entities:
test_code = self._generate_tests(entity, spec)
files[f"tests/test_{entity['name'].lower()}.py"] = test_code
return files
def _generate_models(self, spec: APISpec) -> str:
response = client.messages.create(
model="claude-sonnet-4-5",
max_tokens=4096,
messages=[{
"role": "user",
"content": f"""Создай SQLAlchemy 2.0 модели для сущностей:
Сущности:
{json.dumps(spec.entities, ensure_ascii=False, indent=2)}
Требования:
- Используй DeclarativeBase
- Добавь id (Integer PK autoincrement), created_at, updated_at для всех моделей
- Используй правильные типы: String(256), Text, Integer, Float, Boolean, DateTime
- Добавь __tablename__
- Добавь relationship() для связей между моделями
- Добавь __repr__ для дебага
Верни только Python код."""
}]
)
return response.content[0].text.strip()
def _generate_schemas(self, spec: APISpec) -> str:
response = client.messages.create(
model="claude-sonnet-4-5",
max_tokens=4096,
messages=[{
"role": "user",
"content": f"""Создай Pydantic v2 схемы для валидации:
Сущности: {json.dumps(spec.entities, ensure_ascii=False)}
Endpoints: {json.dumps([e.dict() for e in spec.endpoints], ensure_ascii=False)}
Для каждой сущности создай:
- <Entity>Create — для POST (все обязательные поля)
- <Entity>Update — для PATCH (все поля Optional)
- <Entity>Response — для ответов (включая id, created_at)
- <Entity>ListResponse — с пагинацией
Добавь field validators где нужно (email формат, позитивные числа, длина строк).
Верни только Python код."""
}]
)
return response.content[0].text.strip()
def _generate_router(self, entity: dict, spec: APISpec) -> str:
entity_endpoints = [
e for e in spec.endpoints
if entity["name"].lower() in e.path.lower()
]
response = client.messages.create(
model="claude-sonnet-4-5",
max_tokens=4096,
messages=[{
"role": "user",
"content": f"""Создай FastAPI роутер для сущности {entity['name']}.
Endpoints для реализации:
{json.dumps([e.dict() for e in entity_endpoints], ensure_ascii=False, indent=2)}
Требования:
- Используй APIRouter с prefix и tags
- Dependency injection для DB session (AsyncSession)
- Dependency injection для авторизации (get_current_user)
- Async/await для всех операций
- Правильные HTTP статусы: 201 для POST, 204 для DELETE, 404 если не найдено
- Пагинация через query params page/limit
- Логирование через structlog
Верни только Python код."""
}]
)
return response.content[0].text.strip()
def _generate_main(self, spec: APISpec) -> str:
return f"""from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from contextlib import asynccontextmanager
{chr(10).join(f"from routers.{e['name'].lower()} import router as {e['name'].lower()}_router" for e in spec.entities)}
@asynccontextmanager
async def lifespan(app: FastAPI):
# Startup
yield
# Shutdown
app = FastAPI(
title="{spec.title}",
description="{spec.description}",
version="{spec.version}",
lifespan=lifespan,
)
app.add_middleware(CORSMiddleware, allow_origins=["*"], allow_methods=["*"], allow_headers=["*"])
{chr(10).join(f'app.include_router({e["name"].lower()}_router, prefix="{spec.base_path}")' for e in spec.entities)}
"""
def _generate_tests(self, entity: dict, spec: APISpec) -> str:
response = client.messages.create(
model="claude-sonnet-4-5",
max_tokens=2048,
messages=[{
"role": "user",
"content": f"""Создай pytest тесты для CRUD endpoints сущности {entity['name']}.
Используй:
- pytest-asyncio для async тестов
- httpx.AsyncClient для HTTP запросов
- pytest fixtures для setup/teardown
- TestDatabase (SQLite in-memory) для изоляции
Покрой: создание, чтение списка, чтение одного, обновление, удаление, 404 случаи, валидацию входных данных.
Верни только Python код."""
}]
)
return response.content[0].text.strip()
CLI-інтерфейс для швидкого старту
import click
import yaml
@click.command()
@click.argument("description_file", type=click.Path(exists=True))
@click.option("--output-dir", "-o", default="./generated_api")
@click.option("--framework", default="fastapi", type=click.Choice(["fastapi", "express"]))
def generate_api(description_file: str, output_dir: str, framework: str):
description = Path(description_file).read_text()
generator = TextToAPIGenerator()
click.echo("Parsing description...")
spec = generator.parse_description(description)
click.echo(f"Found {len(spec.endpoints)} endpoints, {len(spec.entities)} entities")
click.echo("Generating code...")
files = generator.generate_fastapi_code(spec)
output_path = Path(output_dir)
output_path.mkdir(parents=True, exist_ok=True)
for filename, content in files.items():
file_path = output_path / filename
file_path.parent.mkdir(parents=True, exist_ok=True)
file_path.write_text(content)
click.echo(f" Created: {filename}")
_generate_project_files(output_path, spec)
click.echo(f"\nAPI generated in {output_dir}")
click.echo("Run: cd generated_api && docker-compose up")
if __name__ == "__main__":
generate_api()
Приклад опису для генерації
# Система керування задачами
Багатокористувацька система для команд.
Сутності:
- User: email (унікальний), name, role (admin/member), avatar_url
- Team: name, description, owner_id
- Project: name, description, team_id, status (active/archived)
- Task: title, description, project_id, assignee_id, status (todo/in_progress/done), priority (low/medium/high), due_date
Функціональність:
- Реєстрація та авторизація (JWT)
- CRUD для команд, проєктів, задач
- Призначення задач учасникам команди
- Фільтрація задач за статусом, виконавцем, пріоритетом
- Пагінація всіх списків
- Soft delete для задач
Практичний кейс
Клієнт — B2B-стартап, якому потрібно було отримати MVP backend для маркетплейсу послуг за 2 тижні. 8 сутностей, 45+ ендпоїнтів.
Генерація:
- Опис продукту (2 сторінки) → APISpec за кілька секунд
- Генерація коду FastAPI (7 файлів + тести) — кілька хвилин
- Ручне доопрацювання авторизації — 3 дні
- Інтеграція платіжного шлюзу — 2 дні
Результат: працюючий MVP через 5 днів замість 14. Тестове покриття — 67% (згенеровано автоматично). Скоротили бюджет на розробку в 3 рази.
AI чудово справляється з CRUD, пагінацією, валідацією, структурою проєкту та тестами happy path. Ручного втручання потребують складні бізнес-правила, алгоритми ціноутворення та нетривіальні SQL-запити.
Процес роботи, терміни та результати
Етапи
- Аналіз вимог — вивчаємо опис, уточнюємо деталі, фіксуємо специфікацію.
- Генерація специфікації — AI парсить опис у APISpec (сутності, ендпоїнти, типи).
- Генерація коду — створюємо повний проєкт: моделі, схеми, роутери, тести, Docker.
- Тестування — запускаємо тести, виправляємо помилки, додаємо відсутні кейси.
- Деплой і документація — готуємо інструкцію, CI/CD (опціонально).
Терміни та вартість
Терміни залежать від складності проєкту:
- Прототип (один файл) — від 2 днів
- Повний проєкт з тестами — від 1 до 2 тижнів
- Додавання підтримки нового фреймворку — +1 тиждень
- Інтеграція в CI/CD — 1 тиждень
Вартість розраховується індивідуально. Зв'яжіться з нами для оцінки вашого проєкту.
Що ви отримуєте в результаті
| Компонент | Деталі |
|---|---|
| Специфікація | OpenAPI 3.0 (YAML/JSON) |
| Бекенд-код | FastAPI/Express з моделями, схемами, роутерами |
| Тести | pytest з покриттям до 70% |
| Документація | README, інструкція по запуску |
| Інфраструктура | Docker Compose, requirements.txt |
Порівняння ручної розробки та AI-генерації
| Критерій | Ручна розробка | AI-генерація |
|---|---|---|
| Час на CRUD | 3-5 днів | 2-10 хвилин |
| Тестове покриття | 40-60% | до 70% |
| Ризик помилок в моделях | високий | низький (дотримується конвенцій) |
| Документація | пишеться окремо | генерується автоматично |
Типові помилки при AI-генерації API
- Відсутність авторизації. AI не знає вашу систему ролей — потребує ручного налаштування.
- Неправильні HTTP статуси. Іноді модель генерує 200 замість 201 для POST — важливо перевірити.
- Пропущена валідація. Для специфічних бізнес-правил (унікальність email) потрібно додавати кастомні перевірки.
- Недостатнє тестування. Тести покривають happy path, але граничні випадки залишаються за кадром.
Наші інженери мають сертифікати AWS та досвід в AI-генерації коду більше 5 років. Гарантуємо відповідність найкращим практикам REST та повну документацію. Замовте демо-генерацію API за вашим описом — переконайтеся самі.







