Creating a RESTful API with Flask is a pretty cool way to whip up some web services. And guess what? When you pair it up with SQLAlchemy for handling databases, it becomes even more rad. So, if you’re looking to delve into this world, here’s a newbie-friendly guide to get you rolling.
Alright, first off, why go with Flask? Well, for starters, it’s a Python microframework that’s both lightweight and super easy to get a hang of. Sure, it might not be packed with the same bells and whistles as some other, heftier frameworks, but that’s what makes it so user-friendly, especially for RESTful APIs. Plus, there’s a huge and lively community around Python and Flask, so you’re never too far from some solid advice and help.
Now, to get started with your Flask project, you’ve gotta set it up first, right? Create a new directory for your project and use pip to install Flask. Simple and sweet.
mkdir my_flask_api
cd my_flask_api
pip install flask
Next up, you’ll need an app.py
file to kick things off. This file is where you’ll initialize your Flask application.
from flask import Flask, jsonify, request
app = Flask(__name__)
@app.route('/')
def home():
return 'Welcome to my Flask API'
if __name__ == '__main__':
app.run(debug=True)
Run the application with:
python app.py
Piece of cake, right? Now that the basic setup is done, you can move on to creating RESTful endpoints.
So, let’s make some endpoints to manage a collection of people. This is where things get fun.
from flask import Flask, jsonify, request
app = Flask(__name__)
people = [
{'lname': 'Doe', 'fname': 'John', 'age': 30},
{'lname': 'Smith', 'fname': 'Jane', 'age': 25}
]
@app.route('/api/people', methods=['GET'])
def get_people():
return jsonify(people)
@app.route('/api/people', methods=['POST'])
def add_person():
new_person = request.get_json()
people.append(new_person)
return '', 204
@app.route('/api/people/<lname>', methods=['GET'])
def get_person(lname):
person = next((p for p in people if p['lname'] == lname), None)
if person is None:
return jsonify({'error': 'Person not found'}), 404
return jsonify(person)
@app.route('/api/people/<lname>', methods=['PUT'])
def update_person(lname):
person = next((p for p in people if p['lname'] == lname), None)
if person is None:
return jsonify({'error': 'Person not found'}), 404
updated_person = request.get_json()
person.update(updated_person)
return '', 204
@app.route('/api/people/<lname>', methods=['DELETE'])
def delete_person(lname):
person = next((p for p in people if p['lname'] == lname), None)
if person is None:
return jsonify({'error': 'Person not found'}), 404
people.remove(person)
return '', 204
if __name__ == '__main__':
app.run(debug=True)
You gotta love how clean and simple that is. But hey, if you’re thinking of using this for real-world applications, you’ll definitely need something more solid than just in-memory storage. That’s where SQLAlchemy comes in.
SQLAlchemy is an awesome ORM (Object-Relational Mapping) tool for Python that makes database interactions a breeze. First, get SQLAlchemy and Flask-SQLAlchemy installed.
pip install sqlalchemy flask-sqlalchemy
Then, configure SQLAlchemy for your app.
from flask import Flask, jsonify, request
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///people.db'
db = SQLAlchemy(app)
class Person(db.Model):
lname = db.Column(db.String(80), primary_key=True)
fname = db.Column(db.String(80), nullable=False)
age = db.Column(db.Integer, nullable=False)
def __repr__(self):
return f"Person('{self.lname}', '{self.fname}', {self.age})"
@app.route('/api/people', methods=['GET'])
def get_people():
people = Person.query.all()
return jsonify([{'lname': p.lname, 'fname': p.fname, 'age': p.age} for p in people])
@app.route('/api/people', methods=['POST'])
def add_person():
new_person = Person(**request.get_json())
db.session.add(new_person)
db.session.commit()
return '', 204
@app.route('/api/people/<lname>', methods=['GET'])
def get_person(lname):
person = Person.query.get(lname)
if person is None:
return jsonify({'error': 'Person not found'}), 404
return jsonify({'lname': person.lname, 'fname': person.fname, 'age': person.age})
@app.route('/api/people/<lname>', methods=['PUT'])
def update_person(lname):
person = Person.query.get(lname)
if person is None:
return jsonify({'error': 'Person not found'}), 404
updated_person = request.get_json()
person.lname = updated_person.get('lname', person.lname)
person.fname = updated_person.get('fname', person.fname)
person.age = updated_person.get('age', person.age)
db.session.commit()
return '', 204
@app.route('/api/people/<lname>', methods=['DELETE'])
def delete_person(lname):
person = Person.query.get(lname)
if person is None:
return jsonify({'error': 'Person not found'}), 404
db.session.delete(person)
db.session.commit()
return '', 204
if __name__ == '__main__':
db.create_all()
app.run(debug=True)
Talk about leveling up, huh? This sets you up with a solid foundation using a SQLite database.
Alright, let’s make things even more user-friendly. How about using Connexion and Swagger UI for API documentation? This can really streamline everything and make your life easier.
First, install Connexion.
pip install connexion
Then, you can define your API endpoints using a YAML file. Here’s an example:
openapi: 3.0.0
info:
title: People API
description: API to manage people
version: 1.0.0
paths:
/api/people:
get:
summary: Get all people
responses:
200:
description: List of people
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/Person'
post:
summary: Add a new person
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/Person'
responses:
204:
description: Person added successfully
/api/people/{lname}:
get:
summary: Get a person by last name
parameters:
- in: path
name: lname
schema:
type: string
required: true
description: Last name of the person
responses:
200:
description: Person details
content:
application/json:
schema:
$ref: '#/components/schemas/Person'
404:
description: Person not found
put:
summary: Update a person by last name
parameters:
- in: path
name: lname
schema:
type: string
required: true
description: Last name of the person
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/Person'
responses:
204:
description: Person updated successfully
delete:
summary: Delete a person by last name
parameters:
- in: path
name: lname
schema:
type: string
required: true
description: Last name of the person
responses:
204:
description: Person deleted successfully
components:
schemas:
Person:
type: object
properties:
lname:
type: string
fname:
type: string
age:
type: integer
Then, let Connexion run your API.
import connexion
app = connexion.App(__name__, specification_dir='.')
app.add_api('api.yaml')
if __name__ == '__main__':
app.run(debug=True)
With these steps, there’s Swagger UI documentation right at your fingertips. Super handy for both devs and users.
Next up, how about getting your API all set up in Docker? This makes deployment a cinch. Create a Dockerfile
.
FROM python:3.9-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY . .
CMD ["python", "app.py"]
Build your Docker image and run it.
docker build -t my_flask_api .
docker run -p 5000:5000 my_flask_api
This right here is the magic of containerization.
Finally, securing your API is a must. You could use Auth0 to add some authentication, or even just a basic method within Flask for now. Here’s a quick example:
from flask import Flask, jsonify, request
from functools import wraps
app = Flask(__name__)
def requires_auth(f):
@wraps(f)
def decorated(*args, **kwargs):
auth = request.authorization
if not auth or auth.username != 'username' or auth.password != 'password':
return jsonify({'error': 'Unauthorized'}), 401
return f(*args, **kwargs)
return decorated
@app.route('/api/people', methods=['GET'])
@requires_auth
def get_people():
people = Person.query.all()
return jsonify([{'lname': p.lname, 'fname': p.fname, 'age': p.age} for p in people])
if __name__ == '__main__':
app.run(debug=True)
It’s a starting point, but in real-world applications, you’d probably go for JWT tokens or similar.
So, there you have it! Building a RESTful API with Flask is not only straightforward but also scalable with tools like SQLAlchemy, Connexion, and Docker. And let’s not forget the all-important step of securing your API. Flask’s flexibility means you can whip up anything from basic APIs to more complex setups. Happy coding!