Welcome to this blog series where we'll dive into building RESTful APIs using the Flask framework in Python. Flask is a lightweight and flexible microframework that makes it easy to get started with web development, including API creation.
Before we get into the code, let's quickly understand what RESTful APIs are and why they're so popular.
REST (Representational State Transfer) is an architectural style for designing web services. RESTful APIs follow a set of conventions to provide a standardized way for applications to communicate with each other over the internet. They rely on HTTP methods like GET, POST, PUT, DELETE, and PATCH to perform actions on data, using standard HTTP headers and status codes.
Flask offers several advantages for building APIs:
Let's get started with setting up a basic Flask project for our API:
Open your terminal and install Flask using pip:
pip install Flask
Create a Python file (e.g., app.py
) and add the following code:
from flask import Flask
app = Flask(__name__)
@app.route('/')
def index():
return 'Hello, World!'
if __name__ == '__main__':
app.run(debug=True)
Navigate to the directory where your app.py
file is located in your terminal and run the following command:
python app.py
This will start your Flask development server, and you should see the "Hello, World!" message at http://127.0.0.1:5000/
in your browser.
We're now ready to create our first API endpoint. Let's build a simple endpoint that responds to a GET request:
from flask import Flask, jsonify
app = Flask(__name__)
@app.route('/users', methods=['GET'])
def get_users():
users = [
{'id': 1, 'name': 'Alice'},
{'id': 2, 'name': 'Bob'}
]
return jsonify(users)
if __name__ == '__main__':
app.run(debug=True)
In this code:
jsonify
from Flask to easily return JSON responses./users
and specify that it handles GET requests.get_users
function returns a list of users as JSON data.Now, if you visit http://127.0.0.1:5000/users
in your browser, you'll see the user data in JSON format.
Stay tuned for the next part where we'll explore more advanced features like POST requests, database integration, and error handling.
In the previous part, we created a simple GET endpoint to fetch data. Now, let's explore how to handle POST requests to add new data to our API.
For this example, we'll create an endpoint that allows us to create new users. To simplify things, we'll store the users in memory for now.
from flask import Flask, jsonify, request
app = Flask(__name__)
users = []
@app.route('/users', methods=['GET', 'POST'])
def users_route():
if request.method == 'GET':
return jsonify(users)
elif request.method == 'POST':
new_user = request.get_json()
users.append(new_user)
return jsonify({'message': 'User created successfully'}), 201
if __name__ == '__main__':
app.run(debug=True)
Here's what we've done:
request
from Flask to access the request data.users_route
function.request.get_json()
to get the JSON data from the request body. We then append the new user to our users
list and return a success message with HTTP status code 201 (Created).You can test this endpoint using tools like Postman or curl. Here's how you can use curl:
curl -X POST -H "Content-Type: application/json" \
-d '{"id": 3, "name": "Charlie"}' \
http://127.0.0.1:5000/users
This command sends a POST request to /users
with JSON data for a new user. You should receive a 201 Created response with the success message. If you then make a GET request to /users
, you'll see the newly added user in the response.
So far, we've been storing our user data in memory. For a real-world API, we need a persistent data store like a database. Let's integrate a database (like SQLite) into our Flask application.
Install the SQLAlchemy library, which provides an Object Relational Mapper (ORM) for interacting with databases:
pip install SQLAlchemy
Let's define a simple user model using SQLAlchemy:
from flask import Flask, jsonify, request
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///users.db'
db = SQLAlchemy(app)
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(80), unique=True, nullable=False)
def __repr__(self):
return f''
db.create_all()
@app.route('/users', methods=['GET', 'POST'])
def users_route():
if request.method == 'GET':
users = User.query.all()
return jsonify([{'id': user.id, 'name': user.name} for user in users])
elif request.method == 'POST':
data = request.get_json()
new_user = User(name=data['name'])
db.session.add(new_user)
db.session.commit()
return jsonify({'message': 'User created successfully'}), 201
if __name__ == '__main__':
app.run(debug=True)
This code:
users.db
.User
model with id
and name
columns.db.create_all()
.users_route
function to use SQLAlchemy to fetch and add users.Adding error handling to your API is crucial for providing informative responses to clients.
from flask import Flask, jsonify, request
from flask_sqlalchemy import SQLAlchemy
from werkzeug.exceptions import NotFound, BadRequest
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///users.db'
db = SQLAlchemy(app)
# ... (User model) ...
@app.errorhandler(NotFound)
def handle_not_found(e):
return jsonify({'message': 'Resource not found'}), 404
@app.errorhandler(BadRequest)
def handle_bad_request(e):
return jsonify({'message': 'Invalid request data'}), 400
@app.route('/users', methods=['GET', 'POST'])
def users_route():
# ... (GET and POST handling) ...
@app.route('/users/', methods=['GET', 'PUT', 'DELETE'])
def user_route(user_id):
user = User.query.get_or_404(user_id)
if request.method == 'GET':
return jsonify({'id': user.id, 'name': user.name})
elif request.method == 'PUT':
data = request.get_json()
user.name = data['name']
db.session.commit()
return jsonify({'message': 'User updated successfully'})
elif request.method == 'DELETE':
db.session.delete(user)
db.session.commit()
return jsonify({'message': 'User deleted successfully'}), 204
if __name__ == '__main__':
app.run(debug=True)
We've added two error handlers for NotFound
and BadRequest
exceptions, returning appropriate JSON responses and status codes.
We've also created a new endpoint /users/
to handle GET, PUT, and DELETE requests for individual users. Note that this endpoint uses User.query.get_or_404
to retrieve the user based on the user_id
, which automatically raises a NotFound
exception if the user doesn't exist.
Congratulations! You've created a more robust Flask API with database integration and error handling. Keep exploring other features and functionalities of Flask to build even more complex and powerful APIs.