Hey, welcome back for part 2! 👋 In Chapter 1, we got cozy with Python basics. Today? We're leveling up and building something real—your very first REST API using Flask. By the end, you'll have an actual backend service running on your computer. Let's dive in!
What Even Is a REST API? 🤔
Think of a REST API as a waiter in a restaurant:
- Clients (like your React app) are hungry customers who place orders (send requests)
- Your API receives those orders, heads to the kitchen (your database/business logic), and returns with the food (data)
It's just a way for different applications to talk to each other over the internet. Nothing scary!
Why Flask? 💡
Flask is Python's lightweight web framework that doesn't force you into complicated patterns. It's:
- Minimalist: No bloated features you don't need
- Flexible: Build exactly what you want
- Beginner-friendly: Start small, grow big
Plus, companies like Netflix, LinkedIn, and Uber use Flask for some of their services. You're in good company!
Setting Up Your Environment 🛠️
First, let's create a dedicated space for our project:
# Create a project folder
mkdir flask_api_project
cd flask_api_project
# Create and activate a virtual environment
python -m venv venv
# On Windows
venv\Scripts\activate
# On macOS/Linux
source venv/bin/activate
# Install Flask
pip install flask
Your First Flask API 🎉
Create a file called app.py
and add this code:
from flask import Flask, jsonify
# Initialize Flask app
app = Flask(__name__)
# Sample data - imagine this is your database
books = [
{"id": 1, "title": "Python Crash Course", "author": "Eric Matthes"},
{"id": 2, "title": "Automate the Boring Stuff", "author": "Al Sweigart"},
{"id": 3, "title": "Fluent Python", "author": "Luciano Ramalho"}
]
# Root route
@app.route('/')
def hello():
return jsonify({"message": "Welcome to our bookstore API!"})
# Get all books
@app.route('/api/books', methods=['GET'])
def get_books():
return jsonify({"books": books})
# Get a specific book
@app.route('/api/books/', methods=['GET'])
def get_book(book_id):
book = next((book for book in books if book["id"] == book_id), None)
if book:
return jsonify({"book": book})
return jsonify({"message": "Book not found"}), 404
# Run the server
if __name__ == '__main__':
app.run(debug=True)
Let's break down what's happening:
- We import Flask and create our app
- We define some sample data (in a real app, this would come from a database)
- We create three "routes" (endpoints):
-
/
→ Returns a welcome message -
/api/books
→ Returns all books -
/api/books/
→ Returns a specific book by ID
-
Running Your API 🏃♀️
From your terminal:
python app.py
You should see something like:
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
* Restarting with stat
* Debugger is active!
Congrats! Your API is alive! 🎉 You did it!
Testing Your API Endpoints 🧪
Open your browser and visit:
- http://localhost:5000/ → See the welcome message
- http://localhost:5000/api/books → See all books
- http://localhost:5000/api/books/1 → See the first book
Or use a tool like Postman for more advanced testing.
Making It Interactive: POST, PUT, DELETE 🔄
Let's upgrade our API to allow creating, updating, and deleting books. Update your app.py
:
from flask import Flask, jsonify, request
# Initialize Flask app
app = Flask(__name__)
# Sample data
books = [
{"id": 1, "title": "Python Crash Course", "author": "Eric Matthes"},
{"id": 2, "title": "Automate the Boring Stuff", "author": "Al Sweigart"},
{"id": 3, "title": "Fluent Python", "author": "Luciano Ramalho"}
]
# Root route
@app.route('/')
def hello():
return jsonify({"message": "Welcome to our bookstore API!"})
# Get all books
@app.route('/api/books', methods=['GET'])
def get_books():
return jsonify({"books": books})
# Get a specific book
@app.route('/api/books/', methods=['GET'])
def get_book(book_id):
book = next((book for book in books if book["id"] == book_id), None)
if book:
return jsonify({"book": book})
return jsonify({"message": "Book not found"}), 404
# Create a new book
@app.route('/api/books', methods=['POST'])
def add_book():
if not request.json or not 'title' in request.json or not 'author' in request.json:
return jsonify({"message": "Please provide title and author"}), 400
# Find the highest existing ID and increment by 1
new_id = max(book["id"] for book in books) + 1
new_book = {
"id": new_id,
"title": request.json["title"],
"author": request.json["author"]
}
books.append(new_book)
return jsonify({"book": new_book}), 201
# Update a book
@app.route('/api/books/', methods=['PUT'])
def update_book(book_id):
book = next((book for book in books if book["id"] == book_id), None)
if not book:
return jsonify({"message": "Book not found"}), 404
book["title"] = request.json.get("title", book["title"])
book["author"] = request.json.get("author", book["author"])
return jsonify({"book": book})
# Delete a book
@app.route('/api/books/', methods=['DELETE'])
def delete_book(book_id):
global books
book = next((book for book in books if book["id"] == book_id), None)
if not book:
return jsonify({"message": "Book not found"}), 404
books = [book for book in books if book["id"] != book_id]
return jsonify({"message": "Book deleted"})
# Run the server
if __name__ == '__main__':
app.run(debug=True)
Now your API can:
- GET /api/books → Read all books
- GET /api/books/1 → Read a specific book
- POST /api/books → Create a new book
- PUT /api/books/1 → Update a book
- DELETE /api/books/1 → Delete a book
This completes the CRUD operations (Create, Read, Update, Delete) that most APIs need!
Testing the New Endpoints 🧪
For POST, PUT, and DELETE, you'll need a tool like Postman or curl.
Example POST request using curl:
curl -X POST http://localhost:5000/api/books \
-H "Content-Type: application/json" \
-d '{"title": "Learn Python the Hard Way", "author": "Zed Shaw"}'
Making Your API Production-Ready 🚦
In a real-world scenario, you'd want to:
- Connect to a Database: Replace our list with a proper database like SQLite, PostgreSQL, or MongoDB.
- Add Authentication: Implement JWT tokens or API keys
- Structure Your Code: Split into modular files (routes, models, etc.)
- Add Validation: Ensure data is properly formatted
- Add Error Handling: More robust error messages
- Deploy: Host on platforms like Heroku, AWS, or DigitalOcean
Next Steps 🚀
Ready to level up? Try these challenges:
- Add a search feature: Filter books by title or author
- Add pagination: Return only 10 books at a time
- Add reviews: Create a nested resource for book reviews
- Connect to a database: Switch from a list to SQLite using Flask-SQLAlchemy
Conclusion 🎯
You did it! You've built your first REST API with Flask. What seemed like complex backend magic is now something you understand and can build yourself!
Remember, this is just the beginning. RESTful APIs are the backbone of modern web applications, and you've just taken your first steps into that world. Keep experimenting, keep building, and most importantly, have fun with it!
About the Author: I'm Marco, and I built my first Flask API to track my ever-growing collection of unread programming books. Ironically, I've added more books than I've read. I write at Dev.to about Python, Typescript, AI, DBs, APIs, Programming, and more.
P.S. Questions about your API? Hit me up in the comments or on Twitter. The Python community is super helpful! 🐍