← Назад к вопросам
Какие знаешь основные принципы RESTful сервиса?
1.3 Junior🔥 221 комментариев
#REST API и HTTP
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Основные принципы RESTful сервиса
REST (Representational State Transfer) — это архитектурный стиль для проектирования сетевых приложений. REST основывается на простых и понятных принципах, которые делают сервисы масштабируемыми и легкими в использовании.
1. Клиент-серверная архитектура
Клиент и сервер — это независимые компоненты, которые взаимодействуют через HTTP:
# Пример Flask сервера
from flask import Flask, jsonify, request
app = Flask(__name__)
@app.route('/api/v1/users', methods=['GET'])
def get_users():
return jsonify([{"id": 1, "name": "Иван"}])
@app.route('/api/v1/users', methods=['POST'])
def create_user():
data = request.get_json()
return jsonify({"id": 2, "name": data["name"]}), 201
2. Ресурсы как основная единица
Всё в API представлено как ресурсы (существительные), не как действия (глаголы):
Правильно (RESTful):
GET /api/v1/users # Список пользователей
POST /api/v1/users # Создать пользователя
GET /api/v1/users/{id} # Получить пользователя
PUT /api/v1/users/{id} # Обновить пользователя
DELETE /api/v1/users/{id} # Удалить пользователя
Неправильно:
GET /api/v1/getUsers # Глагол в URL!
POST /api/v1/createUser # Глагол в URL!
GET /api/v1/deleteUser/{id} # Глагол в URL!
3. Использование HTTP методов правильно
Каждый HTTP метод имеет свою семантику:
from fastapi import FastAPI, HTTPException, status
app = FastAPI()
database = {1: {"id": 1, "name": "Иван", "email": "ivan@example.com"}}
# GET — безопасный, идемпотентный, не изменяет состояние
@app.get("/users/{user_id}")
def read_user(user_id: int):
if user_id not in database:
raise HTTPException(status_code=404, detail="User not found")
return database[user_id]
# POST — создание нового ресурса, не идемпотентный
@app.post("/users", status_code=201)
def create_user(name: str, email: str):
new_id = max(database.keys()) + 1
database[new_id] = {"id": new_id, "name": name, "email": email}
return database[new_id]
# PUT — полное обновление ресурса, идемпотентный
@app.put("/users/{user_id}")
def update_user(user_id: int, name: str, email: str):
if user_id not in database:
raise HTTPException(status_code=404)
database[user_id] = {"id": user_id, "name": name, "email": email}
return database[user_id]
# PATCH — частичное обновление
@app.patch("/users/{user_id}")
def patch_user(user_id: int, name: str = None):
if user_id not in database:
raise HTTPException(status_code=404)
if name:
database[user_id]["name"] = name
return database[user_id]
# DELETE — удаление ресурса, идемпотентный
@app.delete("/users/{user_id}", status_code=204)
def delete_user(user_id: int):
if user_id not in database:
raise HTTPException(status_code=404)
del database[user_id]
4. Stateless (без состояния)
Сервер не должен хранить контекст сессии клиента между запросами. Каждый запрос содержит все необходимо информацию:
# Хорошо — каждый запрос независим
@app.get("/users/{user_id}")
def get_user(user_id: int, authorization: str = Header(None)):
# Верифицируем токен в каждом запросе
if not verify_token(authorization):
raise HTTPException(status_code=401)
return get_user_data(user_id)
# Плохо — сервер помнит состояние
# sessions = {} # Глобальное хранилище!
# @app.get("/users/{user_id}")
# def get_user(user_id, session_id):
# if session_id not in sessions:
# return {"error": "not authenticated"}
5. Кэширование
Ответы должны быть помечены как кэшируемые или некэшируемые:
from fastapi import FastAPI
from fastapi.responses import Response
app = FastAPI()
@app.get("/posts/{post_id}")
def get_post(post_id: int):
# Этот ресурс можно кэшировать на 1 час
response = Response({"id": post_id, "title": "Статья"})
response.headers["Cache-Control"] = "public, max-age=3600"
return response
@app.get("/user-profile")
def get_profile():
# Личные данные не кэшируем
response = Response({"name": "Иван"})
response.headers["Cache-Control"] = "private, no-cache"
return response
6. Использование правильных HTTP статус кодов
from fastapi import FastAPI, HTTPException
app = FastAPI()
@app.post("/users")
def create_user(name: str):
# 201 Created — ресурс создан
return {"id": 1, "name": name}, 201
@app.get("/users/{user_id}")
def get_user(user_id: int):
if user_id == 999:
# 404 Not Found — ресурс не найден
raise HTTPException(status_code=404, detail="User not found")
# 200 OK — успешно
return {"id": user_id, "name": "Иван"}
@app.delete("/users/{user_id}")
def delete_user(user_id: int):
# 204 No Content — успешно, но нет контента
return {}, 204
@app.post("/login")
def login(username: str, password: str):
if not verify_credentials(username, password):
# 401 Unauthorized — не аутентифицирован
raise HTTPException(status_code=401)
# 200 OK с токеном
return {"token": "jwt_token"}
@app.get("/admin")
def admin_panel():
# 403 Forbidden — аутентифицирован, но нет доступа
raise HTTPException(status_code=403, detail="Admin access required")
7. Версионирование API
from fastapi import FastAPI
app = FastAPI()
# v1 API
@app.get("/api/v1/users")
def get_users_v1():
return [{"id": 1, "name": "Иван"}]
# v2 API с другой структурой
@app.get("/api/v2/users")
def get_users_v2():
return [{"id": 1, "name": "Иван", "email": "ivan@example.com", "created_at": "2025-01-01"}]
8. Вложенные ресурсы
# Вложенный ресурс для коллекции
GET /api/v1/users/{user_id}/posts # Посты пользователя
GET /api/v1/users/{user_id}/posts/{id} # Конкретный пост
# Операции над конкретным ресурсом
POST /api/v1/posts/{id}/like # Лайк поста
DELETE /api/v1/posts/{id}/like # Убрать лайк
9. Фильтрация и сортировка
@app.get("/posts")
def list_posts(skip: int = 0, limit: int = 10, sort: str = "date"):
# GET /api/v1/posts?skip=0&limit=10&sort=date
return {"posts": [], "total": 100}
@app.get("/users")
def search_users(q: str = "", role: str = None):
# GET /api/v1/users?q=ivan&role=admin
return {"users": []}
Резюме
- Ресурсы как существительные — /users, не /getUsers
- Правильные HTTP методы — GET, POST, PUT, DELETE, PATCH
- Stateless — сервер не хранит сессии
- Правильные статус коды — 200, 201, 204, 400, 401, 403, 404
- Кэширование — указывай Cache-Control заголовки
- Версионирование — /api/v1/, /api/v2/
- Вложенные ресурсы — /users/{id}/posts
- Фильтрация — query параметры для поиска и сортировки