Python: Creating a REST API

Step-by-step guide to building a REST API with Flask in Python

👋 Welcome to the Stackhero documentation!

Stackhero offers a ready-to-use Python cloud solution designed to simplify your deployments:

  • Deploy your application to production within seconds using a simple git push.
  • Use your own domain name, with automatic HTTPS certificate setup for secure connections managed on your behalf.
  • Take advantage of automatic backups, one-click updates, and predictable pricing, so you can focus on your code rather than infrastructure management.
  • Benefit from high performance and security on a private, dedicated infrastructure. Your environment is isolated and protected.

Save time and streamline your workflow: your code can be up and running with Stackhero's Python cloud hosting in just 5 minutes.

This guide will show you how to create a simple REST API using Python and Flask. Flask is a lightweight micro-framework that makes it easy to quickly build web applications and APIs.

Before you begin, ensure you have the following tools installed:

  1. Python
  2. pip
  3. git
  4. asdf

If you need assistance setting up your environment, refer to the Development platform guide. Alternatively, you can start coding straight away with the online Code-Hero platform. Code-Hero provides an online IDE and terminal, with all essential tools pre-installed. This allows you to focus on your code rather than installation and configuration.

Python REST API running in Code-Hero, accessible directly from the browserPython REST API running in Code-Hero, accessible directly from the browser

Begin by creating a new project directory. In this example, the project is called myRestApi:

mkdir myRestApi
cd myRestApi

Set the Python version to the latest available with asdf, then initialise a Git repository:

asdf install python latest \
  && asdf local python latest

echo "__pycache__/" >> .gitignore

git init
git add -A .
git commit -m "First commit"

You only need one main dependency for this example: Flask.

Flask is designed to be simple and fast, so you can build and deploy web APIs without unnecessary overhead. It includes built-in support for routing, templating, and HTTP request handling, enabling you to go from idea to working API in just a few minutes.

You can install Flask and python-dotenv using pip:

pip install Flask python-dotenv

We include python-dotenv to manage environment variables securely and conveniently. You will see how to use it in the following steps.

After installation, freeze your dependencies to a requirements.txt file:

pip freeze > requirements.txt

Freezing dependencies ensures everyone uses the same package versions. This small step can save you hours of troubleshooting later on.

You are now ready to write your API code.

Create a file named app.py and add the following code:

import os
from dotenv import load_dotenv
from flask import Flask, jsonify, request

# Load environment variables from .env for non-production environments
if os.environ.get('ENV') != 'production':
    load_dotenv()

app = Flask(__name__)

# Example tasks data
tasks = [
    {
        'id': 1,
        'title': 'Buy groceries',
        'description': 'Milk, Cheese, Pizza, Fruits',
        'done': False
    },
    {
        'id': 2,
        'title': 'Learn Python',
        'description': 'Learn Python programming basics',
        'done': False
    }
]

@app.route('/api/tasks', methods=['GET'])
def get_tasks():
    return jsonify({'tasks': tasks})

@app.route('/api/tasks/<int:task_id>', methods=['GET'])
def get_task(task_id):
    task = [task for task in tasks if task['id'] == task_id]
    if not task:
        return jsonify({'error': 'Task not found'}), 404
    return jsonify({'task': task[0]})

@app.route('/api/tasks', methods=['POST'])
def create_task():
    if not request.json or 'title' not in request.json:
        return jsonify({'error': 'Title is required'}), 400
    task = {
        'id': tasks[-1]['id'] + 1,
        'title': request.json['title'],
        'description': request.json.get('description', ""),
        'done': False
    }
    tasks.append(task)
    return jsonify({'task': task}), 201

if __name__ == '__main__':
    if os.environ.get('ENV') == 'production':
        app.run()
    else:
        app.run(host='0.0.0.0', port=8080, debug=True)

You can start the server with:

python app.py

With host='0.0.0.0', your API is accessible via your browser when using Code-Hero. Go to http://<XXXXXX>.stackhero-network.com:8080/api/tasks, replacing <XXXXXX> with your Code-Hero domain.

Once the server is running, you can interact with your API using cURL. Here are some example commands:

  • Retrieve all tasks:

    curl -s http://localhost:8080/api/tasks
    # Output:
    # {
    #   "tasks": [
    #     ...
    #   ]
    # }
    
  • Retrieve a specific task (ID 2):

    curl -s http://localhost:8080/api/tasks/2
    # Output:
    # {
    #   "task": {
    #     ...
    #   }
    # }
    
  • Create a new task:

    curl -s -X POST -H "Content-Type: application/json" \
    -d '{"title": "New task", "description": "Created with cURL"}' \
    http://localhost:8080/api/tasks
    # Output:
    # {
    #   "task": {
    #     ...
    #   }
    # }
    

Tip: For more readable output, you can pipe the result to jq. For example, curl -s http://localhost:8080/api/tasks/2 | jq makes the JSON easier to read.

Example of Python REST API using Flask, running in Stackhero Code-Hero, with the server (1) and the client using cURL (2)Example of Python REST API using Flask, running in Stackhero Code-Hero, with the server (1) and the client using cURL (2)

Environment variables help you protect secrets such as database credentials or API keys. Using them keeps sensitive data out of your codebase and Git history, and makes it easier to use different settings for each environment.

To manage environment variables, you can use the python-dotenv module. If you skipped the earlier installation step, you can install it now:

pip install python-dotenv
pip freeze > requirements.txt

Create a .env file at the root of your project and add your development environment variables:

ENV="development"
DATABASE_PASSWORD="secretPassword"
THIRD_API_PRIVATE_KEY="secretKey"

Add .env to your .gitignore so it is not committed to Git:

echo ".env" >> .gitignore

You can access these variables in Python using os.environ.get():

import os

print(os.environ.get('ENV'))

The .env file is for development only. For production or staging, you can set environment variables directly in your Stackhero dashboard under your Python service configuration.

Flask's built-in server is ideal for development. In production, it is recommended to use a robust WSGI server such as Gunicorn. Here is how to prepare:

  1. Install Gunicorn:

    pip install gunicorn
    pip freeze > requirements.txt
    
  2. Start your application with Gunicorn:

    ENV=production gunicorn app:app \
      --error-logfile - \
      -b 0.0.0.0:8080
    

    Here, app:app refers to your file (app.py) and the Flask application instance (app).

  3. You can add a Makefile to easily switch between development and production modes:

    .DEFAULT_GOAL := dev
    
    # Stackhero for Python runs the "run" rule by default. We override it to run 'prod'.
    run: prod
    
    prod:
    	ENV=production gunicorn app:app \
    	  --error-logfile - \
    	  -b 0.0.0.0:8080
    
    dev:
    	python app.py
    

You can start the server in development mode with make dev (or simply make), or in production mode with make prod.

Stackhero makes cloud deployment simple and secure. You can deploy your Python project using the Python cloud hosting service. Features include:

  • Deployment with a simple git push
  • Automatic TLS (HTTPS) with customisable domains
  • Dedicated infrastructure for security
  • Support for HTTP/2, TLS 1.3, WebSockets, GZIP & Brotli, ETag, and both TCP/UDP port access

To deploy, follow these steps:

  1. Retrieve your public SSH key:

    cat ~/.ssh/id_*.pub
    
  2. In the Stackhero dashboard, open your "Stackhero for Python" service and select "Configure".

  3. Paste your public key into the "SSH public keys" or "Key" field.

  4. Click "Validate" to confirm your configuration.

"Stackhero for Python" public key configuration"Stackhero for Python" public key configuration

If you do not have SSH keys yet, you can generate them with:

ssh-keygen -t ed25519

Add a Git remote to your project using the command provided in your Stackhero service (replace <XXXXXX> with your service domain):

git remote add stackhero ssh://stackhero@<XXXXXX>.stackhero-network.com:222/project.git

Git remote commandGit remote command

When you are ready to deploy, push your code with:

git push stackhero main

Remember to commit your changes before deploying. In Stackhero Code-Hero, you can use the Command Palette (Ctrl+Shift+P or Cmd+Shift+P) and type Git: Commit for quick commits.

After deployment, your API will be available at https://<XXXXXX>.stackhero-network.com/api/tasks. Replace <XXXXXX> with your service domain to access your Flask API.

You now have a working REST API built with Flask. With this foundation, it is straightforward to expand your application, connect to databases, or integrate with other services. Flask gives you the flexibility to move from a simple prototype to a fully-featured production API.