Anasayfa / Software / Build a Simple REST API with Python Flask – Step‑by‑Step Guide

Build a Simple REST API with Python Flask – Step‑by‑Step Guide

Flask API

In today’s micro‑service world, a lightweight REST API is often the first building block of a larger application. Python’s Flask framework makes it surprisingly easy to spin up an API that can handle JSON payloads, route requests, and integrate with databases—all with just a few lines of code. This guide walks you through the entire process, from setting up a virtual environment to testing your endpoints with curl. By the end, you’ll have a functional API you can extend, deploy, and showcase in your portfolio.

What You'll Need

  • Python 3.8 or newer installed on your machine
  • Basic knowledge of Python syntax and HTTP concepts
  • A terminal or command prompt with administrative rights
  • Virtual environment tools (venv or virtualenv)
  • Text editor or IDE (VS Code, PyCharm, etc.)

Step 1: Set Up a Clean Project Workspace

Start by creating a dedicated folder for your API. Open a terminal and run:

mkdir flask_api_demo && cd flask_api_demo

Next, initialise a Python virtual environment to keep dependencies isolated:

python -m venv venv

Activate the environment:

# On Windows
venvScriptsactivate
# On macOS/Linux
source venv/bin/activate

With the environment active, install Flask and a helper library called Flask‑RESTful, which simplifies route handling:

pip install Flask Flask-RESTful

Verify the installation by checking the package list:

pip list

Step 2: Create the Core Application File

Inside your project folder, create a file named app.py. This file will hold the Flask application instance and the API resources.

touch app.py

Open app.py in your editor and paste the following skeleton:

from flask import Flask, request, jsonify
from flask_restful import Resource, Api

app = Flask(__name__)
api = Api(app)

class HelloWorld(Resource):
def get(self):
return {"message": "Hello, World!"}, 200

api.add_resource(HelloWorld, "/api/hello")

if __name__ == "__main__":
app.run(debug=True)

This minimal app defines a single GET endpoint at /api/hello that returns a JSON greeting. The debug=True flag enables live reloading—handy while you develop.

Step 3: Add CRUD Endpoints for a Simple Resource

Let’s build a more realistic example: a tiny to‑do list API that supports Create, Read, Update, and Delete (CRUD) operations. First, decide on the data structure. For this tutorial we’ll keep items in an in‑memory Python list, which means the data resets when the server restarts—perfect for learning purposes.

Replace the previous HelloWorld class with the following code in app.py:

todos = []

class TodoList(Resource):
def get(self):
return jsonify(todos)

def post(self):
data = request.get_json(force=True)
if not data.get("task"):
return {"error": "'task' field is required"}, 400
todo = {"id": len(todos) + 1, "task": data["task"], "done": False}
todos.append(todo)
return todo, 201

class TodoItem(Resource):
def get(self, todo_id):
todo = next((t for t in todos if t["id"] == todo_id), None)
if not todo:
return {"error": "Todo not found"}, 404
return todo, 200

def put(self, todo_id):
todo = next((t for t in todos if t["id"] == todo_id), None)
if not todo:
return {"error": "Todo not found"}, 404
data = request.get_json(force=True)
todo["task"] = data.get("task", todo["task"])
todo["done"] = data.get("done", todo["done"])
return todo, 200

def delete(self, todo_id):
global todos
todos = [t for t in todos if t["id"] != todo_id]
return {"message": "Deleted"}, 200

api.add_resource(TodoList, "/api/todos")
api.add_resource(TodoItem, "/api/todos/")

Explanation of each method:

  • GET /api/todos – Returns the full list of to‑do items.
  • POST /api/todos – Accepts JSON {"task": "Buy milk"} and creates a new entry.
  • GET /api/todos/<id> – Retrieves a single item by its numeric ID.
  • PUT /api/todos/<id> – Updates the task or done fields.
  • DELETE /api/todos/<id> – Removes the item from the list.

Save the file and restart the server (Ctrl‑C then python app.py). You should see Flask listening on http://127.0.0.1:5000.

Step 4: Test Your API with curl

Open a second terminal window and run a series of curl commands to verify each endpoint works as expected.

Create a new to‑do:

curl -X POST -H "Content-Type: application/json" -d '{"task": "Write documentation"}' http://127.0.0.1:5000/api/todos

Fetch the list:

curl http://127.0.0.1:5000/api/todos

Update the first item to mark it as done:

curl -X PUT -H "Content-Type: application/json" -d '{"done": true}' http://127.0.0.1:5000/api/todos/1

Delete the item:

curl -X DELETE http://127.0.0.1:5000/api/todos/1

If any command returns an error, double‑check the JSON payload and the route spelling. The responses should be valid JSON objects with appropriate HTTP status codes (200, 201, 400, 404, etc.).

Step 5: Add Basic Error Handling and Input Validation

Flask‑RESTful provides a convenient abort function, but for clarity we’ll implement simple checks ourselves. Update the post method in TodoList to use abort when the payload is malformed:

from flask_restful import abort

def abort_if_missing(field, data):
if field not in data:
abort(400, message=f"'{field}' is required")

class TodoList(Resource):
def post(self):
data = request.get_json(force=True)
abort_if_missing('task', data)
# rest of the method stays the same

Similarly, wrap the lookup logic in a helper function to avoid repetition:

def find_todo(todo_id):
todo = next((t for t in todos if t["id"] == todo_id), None)
if not todo:
abort(404, message="Todo not found")
return todo

Replace each direct next(...) call with find_todo(todo_id). This makes the code cleaner and guarantees consistent error messages.

Step 6: Prepare for Production – Configuration and WSGI Server

Running app.run(debug=True) is fine for development, but a production environment should use a robust WSGI server like gunicorn. First, install it inside your virtual environment:

pip install gunicorn

Then create a new file called wsgi.py that simply imports the Flask app:

from app import app

if __name__ == "__main__":
app.run()

Start the server with:

gunicorn --bind 0.0.0.0:8000 wsgi:app

Gunicorn will manage worker processes, handle concurrent requests, and provide better performance. Remember to set debug=False in app.py before deploying.

Common Mistakes to Avoid

1. Hard‑coding the port or host. Using 0.0.0.0 lets the app accept external traffic; 127.0.0.1 restricts it to localhost only.
2. Storing data in a global list. It works for demos but will lose data on restart. For real projects, switch to a database like SQLite or PostgreSQL.
3. Neglecting content‑type headers. Clients must send Content-Type: application/json for POST/PUT; otherwise request.get_json() returns None.
4. Returning plain Python dicts without jsonify. Flask will convert them, but jsonify also sets the correct MIME type.
5. Running the app with debug=True in production. It exposes the interactive debugger, which is a security risk.

Tips and Tricks

• Use flask‑script or Flask CLI to manage commands like database migrations.
• Leverage Flask’s @app.errorhandler decorator to centralise error responses.
• Enable CORS with the flask‑cors extension if your API will be called from browsers on different domains.
• Structure larger projects with blueprints: each resource lives in its own module, keeping app.py tidy.
• Write unit tests with pytest and Flask’s test client to catch regressions early.

Frequently Asked Questions

Do I need a database for a Flask API?

Not for a simple prototype. An in‑memory list suffices for learning, but production‑grade APIs should persist data in a relational (PostgreSQL, MySQL) or NoSQL (MongoDB) store.

Can I secure my API with authentication?

Yes. Flask‑HTTPAuth or Flask‑JWT‑Extended are popular extensions that let you add token‑based authentication, OAuth, or API key checks with minimal code.

How do I deploy the API to the cloud?

Package your code in a Docker container, push it to a registry, and run it on services like AWS Elastic Beanstalk, Google Cloud Run, or Azure App Service. The gunicorn command shown earlier works inside the container as the entrypoint.

Conclusion

Building a REST API with Flask is a straightforward yet powerful exercise that introduces you to core web concepts—routing, JSON handling, error management, and production deployment. By following the six steps above, you now have a functional API that you can expand with authentication, a real database, and automated testing. Keep iterating, explore Flask extensions, and soon you’ll be comfortable crafting full‑featured micro‑services for any modern application.

Photo by Raghav Bhasin on Unsplash

Etiketlendi: