본문으로 건너뛰기 Python REST APIs | Build API Servers with Flask and Django

Python REST APIs | Build API Servers with Flask and Django

Python REST APIs | Build API Servers with Flask and Django

이 글의 핵심

Design RESTful APIs in Python: HTTP verbs, resource URLs, Flask CRUD examples, Django REST Framework, JWT auth, error handling, and production-minded tips.

Introduction

“The backbone of backend work”

REST APIs are the standard way to connect frontends and backends.

1. REST API fundamentals

RESTful design

Resource-oriented routes:
GET    /api/users       - list users
GET    /api/users/1     - get user 1
POST   /api/users       - create user
PUT    /api/users/1     - replace user 1
DELETE /api/users/1     - delete user 1

2. REST API with Flask

CRUD API

from flask import Flask, jsonify, request
app = Flask(__name__)
users = [
    {'id': 1, 'name': 'Alice', 'email': 'alice@example.com'},
    {'id': 2, 'name': 'Bob', 'email': 'bob@example.com'}
]
# List (GET)
@app.route('/api/users', methods=['GET'])
def get_users():
    return jsonify({'users': users, 'count': len(users)})
# Single resource (GET)
@app.route('/api/users/<int:user_id>', methods=['GET'])
def get_user(user_id):
    user = next((u for u in users if u['id'] == user_id), None)
    if user:
        return jsonify(user)
    return jsonify({'error': 'User not found'}), 404
# Create (POST)
@app.route('/api/users', methods=['POST'])
def create_user():
    data = request.get_json()
    
    if not data or 'name' not in data or 'email' not in data:
        return jsonify({'error': 'Invalid data'}), 400
    
    new_user = {
        'id': max(u['id'] for u in users) + 1 if users else 1,
        'name': data['name'],
        'email': data['email']
    }
    users.append(new_user)
    return jsonify(new_user), 201
# Update (PUT)
@app.route('/api/users/<int:user_id>', methods=['PUT'])
def update_user(user_id):
    user = next((u for u in users if u['id'] == user_id), None)
    if not user:
        return jsonify({'error': 'User not found'}), 404
    
    data = request.get_json()
    user.update(data)
    return jsonify(user)
# Delete (DELETE)
@app.route('/api/users/<int:user_id>', methods=['DELETE'])
def delete_user(user_id):
    global users
    users = [u for u in users if u['id'] != user_id]
    return ', 204
if __name__ == '__main__':
    app.run(debug=True)

3. Django REST Framework

Installation

pip install djangorestframework

Serializers

# blog/serializers.py
from rest_framework import serializers
from .models import Post
class PostSerializer(serializers.ModelSerializer):
    class Meta:
        model = Post
        fields = ['id', 'title', 'content', 'author', 'created_at']
        read_only_fields = ['id', 'created_at']

ViewSet

# blog/views.py
from rest_framework import viewsets
from .models import Post
from .serializers import PostSerializer
class PostViewSet(viewsets.ModelViewSet):
    queryset = Post.objects.all()
    serializer_class = PostSerializer

URL routing

# blog/urls.py
from rest_framework.routers import DefaultRouter
from .views import PostViewSet
router = DefaultRouter()
router.register(r'posts', PostViewSet)
urlpatterns = router.urls

4. Authentication and permissions

JWT authentication

pip install djangorestframework-simplejwt
# settings.py
REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': [
        'rest_framework_simplejwt.authentication.JWTAuthentication',
    ],
}
# urls.py
from rest_framework_simplejwt.views import (
    TokenObtainPairView,
    TokenRefreshView,
)
urlpatterns = [
    path('api/token/', TokenObtainPairView.as_view()),
    path('api/token/refresh/', TokenRefreshView.as_view()),
]

5. Error handling

Custom JSON errors

from flask import jsonify
@app.errorhandler(404)
def not_found(error):
    return jsonify({
        'error': 'Not Found',
        'message': 'The requested resource could not be found'
    }), 404
@app.errorhandler(500)
def internal_error(error):
    return jsonify({
        'error': 'Internal Server Error',
        'message': 'An unexpected server error occurred'
    }), 500

6. Practical example

Full Flask API sketch

from flask import Flask, jsonify, request
from functools import wraps
app = Flask(__name__)
# Simple API key check
API_KEY = "secret-key-123"
def require_api_key(f):
    @wraps(f)
    def decorated(*args, **kwargs):
        api_key = request.headers.get('X-API-Key')
        if api_key != API_KEY:
            return jsonify({'error': 'Unauthorized'}), 401
        return f(*args, **kwargs)
    return decorated
# In-memory store instead of a database
posts = []
@app.route('/api/posts', methods=['GET'])
def get_posts():
    page = request.args.get('page', 1, type=int)
    per_page = request.args.get('per_page', 10, type=int)
    
    start = (page - 1) * per_page
    end = start + per_page
    
    return jsonify({
        'posts': posts[start:end],
        'page': page,
        'total': len(posts)
    })
@app.route('/api/posts', methods=['POST'])
@require_api_key
def create_post():
    data = request.get_json()
    
    required_fields = ['title', 'content']
    if not all(field in data for field in required_fields):
        return jsonify({'error': 'Missing required fields'}), 400
    
    post = {
        'id': len(posts) + 1,
        'title': data['title'],
        'content': data['content'],
        'author': data.get('author', 'Anonymous')
    }
    posts.append(post)
    
    return jsonify(post), 201
if __name__ == '__main__':
    app.run(debug=True)

Practical tips

API design best practices

# Use nouns, not verbs
GET /api/users  # OK
GET /api/getUsers  # Avoid
# Prefer plural collection names
GET /api/users  # OK
GET /api/user  # Avoid
# Hierarchical resources
GET /api/users/1/posts  # posts belonging to user 1
# Meaningful HTTP status codes
200 OK           # success
201 Created      # created
400 Bad Request  # bad input
401 Unauthorized # auth required
404 Not Found    # missing resource
500 Server Error # server failure

Summary

Key takeaways

  1. REST: HTTP plus resource-oriented URLs
  2. Flask: lightweight, flexible API servers
  3. Django REST Framework: batteries-included API toolkit
  4. Auth: JWT, API keys
  5. Errors: consistent JSON bodies and correct status codes

Next steps



Frequently Asked Questions (FAQ)

Q. When would I use this in practice?

A. Design RESTful APIs in Python: HTTP verbs, resource URLs, Flask CRUD examples, Django REST Framework, JWT auth, error ha…

Q. What should I read before this?

A. Follow the previous article or related articles links at the bottom of each post to learn in sequence. See the Python series index for the full picture.

Q. Where can I study this more deeply?

A. Check cppreference and the relevant library’s official documentation. The reference links at the end of the article are also worth using.


Other articles related to this topic.


Keywords Covered in This Article (Related Search Terms)

This article covers Python, REST API, Flask, Django, Backend, HTTP, JSON.