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': '[email protected]'},
{'id': 2, 'name': 'Bob', 'email': '[email protected]'}
]
# 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
- REST: HTTP plus resource-oriented URLs
- Flask: lightweight, flexible API servers
- Django REST Framework: batteries-included API toolkit
- Auth: JWT, API keys
- Errors: consistent JSON bodies and correct status codes
Next steps
- [Databases in Python](/en/blog/python-series-14-database/
- [Python web deployment](/en/blog/python-series-15-deployment/
Related posts
- [Flask basics | Get started with the Python web framework](/en/blog/python-series-11-flask-basics/
자주 묻는 질문 (FAQ)
Q. 이 내용을 실무에서 언제 쓰나요?
A. Design RESTful APIs in Python: HTTP verbs, resource URLs, Flask CRUD examples, Django REST Framework, JWT auth, error ha… 실무에서는 위 본문의 예제와 선택 가이드를 참고해 적용하면 됩니다.
Q. 선행으로 읽으면 좋은 글은?
A. 각 글 하단의 이전 글 또는 관련 글 링크를 따라가면 순서대로 배울 수 있습니다. Python 시리즈 목차에서 전체 흐름을 확인할 수 있습니다.
Q. 더 깊이 공부하려면?
A. cppreference와 해당 라이브러리 공식 문서를 참고하세요. 글 말미의 참고 자료 링크도 활용하면 좋습니다.
같이 보면 좋은 글 (내부 링크)
이 주제와 연결되는 다른 글입니다.
- [Flask Basics | Get Started with the Python Web Framework](/en/blog/python-series-11-flask-basics/
- [Django Basics](/en/blog/python-series-12-django-basics/
- [Express REST API Tutorial for Node.js | Routing](/en/blog/nodejs-express-rest-api-tutorial/
- [C++ REST API 서버 완벽 가이드 | Beast 라우팅·JSON·미들웨어 [#31-2]](/en/blog/cpp-series-31-2-rest-api-server/
이 글에서 다루는 키워드 (관련 검색어)
Python, REST API, Flask, Django, Backend, HTTP, JSON 등으로 검색하시면 이 글이 도움이 됩니다.