← Назад к вопросам
Расскажи про архитектуру веб-приложений на примере REST
2.0 Middle🔥 221 комментариев
#REST API и HTTP
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Архитектура веб-приложений на примере REST
REST (Representational State Transfer) — архитектурный стиль для построения масштабируемых веб-приложений, основанный на HTTP протоколе. Рассмотрим основные компоненты архитектуры.
Принципы REST
- Client-Server: клиент и сервер разделены, независимо эволюционируют
- Stateless: каждый запрос содержит всю необходимую информацию
- Cacheable: ответы помечаются как кэшируемые или нет
- Uniform Interface: единообразный интерфейс для взаимодействия
- Layered System: архитектура состоит из слоёв
- Code on Demand (опционально): сервер может отправлять код клиенту
Типичная архитектура REST приложения
Клиент (Frontend/Mobile)
|
v
[HTTP Request]
|
v
API Gateway / Load Balancer
|
v
Web Server (nginx/Apache)
|
v
Application Layer (Django/FastAPI)
|
v
Business Logic Layer (Services)
|
v
Data Access Layer (ORM/Repository)
|
v
Database (PostgreSQL/MySQL)
Слоистая архитектура на примере FastAPI
Presentation Layer (Presentation/API)
Отвечает за обработку HTTP запросов и ответов:
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
app = FastAPI()
class UserCreate(BaseModel):
name: str
email: str
class UserResponse(BaseModel):
id: int
name: str
email: str
@app.post("/api/v1/users", response_model=UserResponse)
async def create_user(user: UserCreate):
# Валидация уже произошла (Pydantic)
result = await user_service.create(user)
return result
Application/Business Logic Layer
Содержит бизнес-логику, использует сервисы:
class UserService:
def __init__(self, repository: UserRepository):
self.repository = repository
async def create(self, user_data: UserCreate) -> User:
# Проверка по email
existing = await self.repository.find_by_email(user_data.email)
if existing:
raise ValueError("Email уже зарегистрирован")
# Хеширование пароля, бизнес-логика
user = User(
name=user_data.name,
email=user_data.email
)
return await self.repository.save(user)
async def get_by_id(self, user_id: int) -> User:
user = await self.repository.find_by_id(user_id)
if not user:
raise UserNotFound(f"User {user_id} not found")
return user
Data Access Layer (Repository Pattern)
Отвечает за работу с БД, скрывает детали реализации:
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select
class UserRepository:
def __init__(self, session: AsyncSession):
self.session = session
async def save(self, user: User) -> User:
self.session.add(user)
await self.session.commit()
await self.session.refresh(user)
return user
async def find_by_id(self, user_id: int) -> User:
query = select(UserModel).where(UserModel.id == user_id)
result = await self.session.execute(query)
return result.scalar_one_or_none()
async def find_by_email(self, email: str) -> User:
query = select(UserModel).where(UserModel.email == email)
result = await self.session.execute(query)
return result.scalar_one_or_none()
HTTP Методы в REST
| Метод | Операция | Идемпотентный | Безопасный |
|---|---|---|---|
| GET | Чтение | Да | Да |
| POST | Создание | Нет | Нет |
| PUT | Замена | Да | Нет |
| PATCH | Обновление | Нет | Нет |
| DELETE | Удаление | Да | Нет |
@app.get("/api/v1/users/{user_id}") # Чтение
async def get_user(user_id: int):
return await user_service.get_by_id(user_id)
@app.post("/api/v1/users") # Создание
async def create_user(user: UserCreate):
return await user_service.create(user)
@app.put("/api/v1/users/{user_id}") # Полное обновление
async def update_user(user_id: int, user: UserUpdate):
return await user_service.update(user_id, user)
@app.patch("/api/v1/users/{user_id}") # Частичное обновление
async def patch_user(user_id: int, user: UserPatch):
return await user_service.patch(user_id, user)
@app.delete("/api/v1/users/{user_id}") # Удаление
async def delete_user(user_id: int):
await user_service.delete(user_id)
return {"status": "deleted"}
Состояние HTTP (статус коды)
- 2xx: Успех (200 OK, 201 Created, 204 No Content)
- 3xx: Редирект (301, 302, 304)
- 4xx: Ошибка клиента (400 Bad Request, 404 Not Found, 401 Unauthorized)
- 5xx: Ошибка сервера (500 Internal Server Error, 503 Service Unavailable)
from fastapi import status
@app.post("/api/v1/users", status_code=status.HTTP_201_CREATED)
async def create_user(user: UserCreate):
return await user_service.create(user)
Обработка ошибок
from fastapi import HTTPException
class UserNotFound(Exception):
pass
@app.exception_handler(UserNotFound)
async def user_not_found_handler(request, exc):
return JSONResponse(
status_code=404,
content={"detail": str(exc)}
)
@app.get("/api/v1/users/{user_id}")
async def get_user(user_id: int):
user = await user_service.get_by_id(user_id)
if not user:
raise UserNotFound(f"User {user_id} not found")
return user
Зависимости и инъекция
from fastapi import Depends
async def get_user_service() -> UserService:
repository = UserRepository(session)
return UserService(repository)
@app.get("/api/v1/users/{user_id}")
async def get_user(user_id: int, service: UserService = Depends(get_user_service)):
return await service.get_by_id(user_id)
Масштабируемость и оптимизация
- Кэширование: Redis для часто используемых данных
- Пагинация: для больших наборов данных
- Асинхронность: async/await для высокой пропускной способности
- Rate limiting: защита от перегрузок
- Версионирование API:
/api/v1/,/api/v2/
from fastapi import Query
@app.get("/api/v1/users")
async def list_users(
skip: int = Query(0, ge=0),
limit: int = Query(10, ge=1, le=100)
):
return await user_service.list(skip=skip, limit=limit)
REST архитектура обеспечивает масштабируемость, простоту интеграции и понятный контракт между клиентом и сервером.