REST APIs
Not every Flask app needs to serve HTML pages. Sometimes you just want to send and receive data — that's where REST APIs come in. Your Flask app becomes a backend that mobile apps, JavaScript frontends, or other services can talk to. JSON is the language of APIs.
JSON Responses with jsonify
Flask gives you jsonify() to convert Python dictionaries into proper JSON responses with the right content type header.
from flask import jsonify
@app.route('/api/users')
def get_users():
users = User.query.all()
users_list = [{'id': u.id, 'username': u.username, 'email': u.email}
for u in users]
return jsonify(users=users_list)
The jsonify() function handles serialization, sets the Content-Type: application/json header, and returns a proper Response object. You can also pass a list directly or wrap multiple values in a dictionary.
API Route Design
Good API routes are predictable. Use nouns for resources and HTTP methods for actions. GET to read, POST to create, PUT to update, DELETE to remove.
@app.route('/api/posts', methods=['GET', 'POST'])
def posts():
if request.method == 'GET':
# Return all posts
pass
elif request.method == 'POST':
# Create a new post
pass
@app.route('/api/posts/<int:id>', methods=['GET', 'PUT', 'DELETE'])
def post(id):
if request.method == 'GET':
# Return single post
pass
elif request.method == 'PUT':
# Update post
pass
elif request.method == 'DELETE':
# Delete post
pass
HTTP Status Codes
Status codes tell the client what happened. Don't always return 200 — use the right code for the situation.
@app.route('/api/users/<int:id>')
def get_user(id):
user = User.query.get(id)
if user is None:
return jsonify({'error': 'User not found'}), 404
return jsonify({'id': user.id, 'username': user.username}), 200
@app.route('/api/users', methods=['POST'])
def create_user():
data = request.get_json()
if not data or 'username' not in data:
return jsonify({'error': 'Username required'}), 400
user = User(username=data['username'], email=data.get('email', ''))
db.session.add(user)
db.session.commit()
return jsonify({'id': user.id, 'username': user.username}), 201
Common codes: 200 OK, 201 Created, 400 Bad Request, 401 Unauthorized, 404 Not Found, 500 Server Error. Clients rely on these to know how to handle the response.
Reading JSON Input
Use request.get_json() to parse JSON from the request body. It returns a Python dictionary or None if the body isn't valid JSON.
data = request.get_json()
username = data.get('username')
email = data.get('email')
API Authentication
Most APIs need some form of authentication. Token-based auth is common — the client sends a token in the request header, and you verify it on the server.
from functools import wraps
def token_required(f):
@wraps(f)
def decorated(*args, **kwargs):
token = request.headers.get('Authorization')
if not token or not verify_token(token):
return jsonify({'error': 'Invalid token'}), 401
return f(*args, **kwargs)
return decorated
@app.route('/api/profile')
@token_required
def profile():
return jsonify({'message': 'Authenticated!'})
CORS Headers
If your API is accessed from a different domain (like a React frontend on localhost:3000 calling a Flask API on localhost:5000), you need CORS headers. The Flask-CORS extension makes this easy.
from flask_cors import CORS
app = Flask(__name__)
CORS(app) # Enables CORS for all routes
Why REST APIs Are Essential
REST APIs separate your frontend from your backend. Your Flask app becomes a data service that any client — web, mobile, IoT device — can consume. It's the foundation of modern web development and opens up your app to a much wider world.