19.09.25 12 060 просмотров
Привет, фанаты Roblox! Ищешь рабочий и бесплатный скрипт для 99 Ночей в Лесу на ...
Создание REST API — одна из самых востребованных задач в веб-разработке. Однако разработать API, которое будет эффективным, безопасным и удобным для использования — это целое искусство. В этой статье мы разберём универсальные подходы к созданию REST API, а также покажем, как реализовать их на различных фреймворках, включая Laravel (PHP), Django (Python) и Express.js (Node.js).
Используйте kebab-case для удобства чтения.


URL должен представлять ресурс, а не действие.


Маршрутизация — основа любого REST API. Она должна быть логичной и предсказуемой для разработчиков. Придерживайтесь принципов REST:
GET, POST, PUT, DELETE.Route::apiResource('users', UserController::class);from django.urls import path
from .views import UserList, UserDetail
urlpatterns = [
path('users/', UserList.as_view()),
path('users/<int:id>/', UserDetail.as_view()),
]const express = require('express');
const app = express();
app.get('/users', getUsers);
app.post('/users', createUser);
app.get('/users/:id', getUserById);Единый формат данных помогает фронтенд-разработчикам эффективно обрабатывать ответы REST API. Используйте JSON и придерживайтесь стандарта.
{
"status": "success",
"data": {
"id": 1,
"name": "John Doe",
"email": "john@example.com"
}
}Защищайте API от несанкционированного доступа. Для этого чаще всего используются токены.
$user = Auth::user();
$token = $user->createToken('API Token')->plainTextToken;
return response()->json(['token' => $token]);from rest_framework_simplejwt.tokens import RefreshToken
def get_tokens_for_user(user):
refresh = RefreshToken.for_user(user)
return {
'refresh': str(refresh),
'access': str(refresh.access_token),
}const jwt = require('jsonwebtoken');
const token = jwt.sign(
{
id: user._id
},
'your_secret_key',
{
expiresIn: '1h'
}
);
res.json({ token });Возвращайте понятные и стандартизированные ошибки.
return response()->json([
'error' => 'Resource not found'
], 404);from rest_framework.views import exception_handler
def custom_exception_handler(exc, context):
response = exception_handler(exc, context)
if response:
response.data['status'] = 'error'
return responseapp.use((err, req, res, next) => {
res.status(err.status || 500).json({
error: err.message || 'Internal Server Error'
});
});Кэширование значительно ускоряет работу API, особенно при работе с большими объёмами данных.
django-cache.$users = Cache::remember('users', 60, function () {
return User::all();
});from django.core.cache import cache
users = cache.get_or_set('users', User.objects.all(), 60)const cache = {};
app.get('/users', (req, res) => {
if (cache['users']) {
return res.json(cache['users']);
}
const users = getUsersFromDb();
cache['users'] = users;
res.json(users);
});Документация необходима для удобства использования API. Популярные инструменты:
const swaggerJsDoc = require('swagger-jsdoc');
const swaggerUi = require('swagger-ui-express');
const swaggerOptions = {
swaggerDefinition: {
info: {
title: 'API Documentation',
version: '1.0.0',
},
},
apis: ['app.js'],
};
const swaggerDocs = swaggerJsDoc(swaggerOptions);
app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerDocs));Пишите тесты, чтобы убедиться, что изменения в коде не нарушают работу REST API.
$response = $this->getJson('/api/users');
$response->assertStatus(200);from rest_framework.test import APITestCase
class UserApiTest(APITestCase):
def test_get_users(self):
response = self.client.get('/api/users/')
self.assertEqual(response.status_code, 200)test('GET /users', async () => {
const response = await request(app).get('/users');
expect(response.status).toBe(200);
});Версионирование позволяет поддерживать старые версии API, не нарушая работу текущих клиентов.
Route::prefix('api/v1')->group(function () {
Route::get('users', [UserController::class, 'index']);
});app.use('/api/v1', v1Routes);Чтобы защитить API от DDoS-атак и избыточной нагрузки, необходимо ограничивать количество запросов от одного клиента за определённое время.
Представленный ниже код ограничивает клиента до 60 запросов в минуту.
Route::middleware('throttle:60,1')->group(function () {
Route::get('users', [UserController::class, 'index']);
});from django_ratelimit.decorators import ratelimit
@ratelimit(key='ip', rate='10/m', method=['GET'])
def get_users(request):
# Логика обработки
passconst rateLimit = require('express-rate-limit');
const limiter = rateLimit({
windowMs: 1 * 60 * 1000, // 1 минута
max: 60, // максимум 60 запросов
});
app.use(limiter);CORS (Cross-Origin Resource Sharing) позволяет клиентам с других доменов отправлять запросы к вашему API. Это особенно важно для SPA или мобильных приложений.
protected $middleware = [
\Fruitcake\Cors\HandleCors::class,
];pip install django-cors-headersINSTALLED_APPS += ['corsheaders']
MIDDLEWARE += ['corsheaders.middleware.CorsMiddleware']
CORS_ALLOW_ALL_ORIGINS = Trueconst cors = require('cors');
app.use(cors());Безопасность — одна из самых критических частей разработки REST API. Вот несколько основных рекомендаций:
$request->validate([
'email' => 'required|email',
'password' => 'required|min:8',
]);from rest_framework import serializers
class UserSerializer(serializers.Serializer):
email = serializers.EmailField()
password = serializers.CharField(min_length=8)const { body, validationResult } = require('express-validator');
app.post('/register', [
body('email').isEmail(),
body('password').isLength({ min: 8 })
], (req, res) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({ errors: errors.array() });
}
});
Хорошая статья, да ещё и с примерами