Python: Creating a REST API

How to create a REST API using Flask

👋 Welcome to the Stackhero documentation!

Stackhero offers a ready-to-use Python cloud solution that provides a host of benefits, including:

  • Deploy your application in seconds with a simple git push.
  • Use your own domain name and benefit from the automatic configuration of HTTPS certificates for enhanced security.
  • Enjoy peace of mind with automatic backups, one-click updates, and straightforward, transparent, and predictable pricing.
  • Get optimal performance and robust security thanks to a private and dedicated VM.

Save time and simplify your life: it only takes 5 minutes to try Stackhero's Python cloud hosting solution!

This documentation is a beginner-friendly guide on creating a REST API in Python.

In this example, we use Flask, a lightweight and easy-to-use micro-framework that enables you to quickly create web applications.

Before you begin, ensure your computer is equipped with the following tools:

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

If your development environment isn't set up yet, refer to the Development platform guide for detailed instructions. Alternatively, you can use the online Code-Hero platform. Code-Hero provides an online IDE and terminal, with all the essential tools pre-installed, so you can start coding immediately without any installation.

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

The first step is to create a new project directory. For this guide, we'll name it myRestApi:

mkdir myRestApi
cd myRestApi

Next, set the Python version to the latest available using asdf, and initialize the Git repository:

asdf install python latest \
  && asdf local python latest

echo "__pycache__/" >> .gitignore

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

For this example, we only need one dependency: Flask.

Flask is a lightweight web framework that enables rapid development of web applications. It is designed to be simple and easy to use, allowing developers to build and deploy web services quickly. Built-in support for routing, templating, and handling HTTP requests makes Flask an excellent choice for creating REST APIs.

Install Flask (and python-dotenv) using pip:

pip install Flask python-dotenv

We are installing the Flask and python-dotenv modules here. You will soon see why we use python-dotenv (spoiler: it is for managing environment variables).

After installation, freeze the package versions to a requirements.txt file:

pip freeze > requirements.txt

Freezing your dependencies ensures that your production server or colleagues use the same versions as you. Just a few seconds of work can prevent many future headaches.

Now, let's dive into the code!

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

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

# Load environment variables from the .env file when not in production
if os.environ.get('ENV') != 'production':
    load_dotenv()

# Create the Flask app
app = Flask(__name__)

# Sample data set
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
    }
]

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

# Route '/api/tasks/<task_id>' (GET) to get a specific task by its ID
@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 len(task) == 0:
        return jsonify({'error': 'Task not found'}), 404
    return jsonify({'task': task[0]})

# Route '/api/tasks' (POST) to create a new task
@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

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

To start the server, run:

python app.py

With the host='0.0.0.0' option, you can also access your API using your browser when using Code-Hero. Simply navigate 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 it using cURL. Here are some examples:

  • Retrieve all tasks:

    curl -s http://localhost:8080/api/tasks
    {
      "tasks": [
        {
          "description": "Milk, Cheese, Pizza, Fruits",
          "done": false,
          "id": 1,
          "title": "Buy groceries"
        },
        {
          "description": "Learn Python programming basics",
          "done": false,
          "id": 2,
          "title": "Learn Python"
        }
      ]
    }
    
  • Retrieve task with ID 2:

    curl -s http://localhost:8080/api/tasks/2
    {
      "task": {
        "description": "Learn Python programming basics",
        "done": false,
        "id": 2,
        "title": "Learn Python"
      }
    }
    
  • 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
    {
      "task": {
        "description": "Created with cURL",
        "done": false,
        "id": 3,
        "title": "New task"
      }
    }
    

Tip: Pipe the output to jq to beautify the JSON. For example, curl -s http://localhost:8080/api/tasks/2 | jq produces a more readable result.

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 are vital for protecting sensitive information, such as database credentials or API keys. There are two main benefits to using environment variables:

  1. Your secrets are not stored in your Git repository, ensuring unauthorized individuals cannot access your sensitive data even if they gain access to your source code.
  2. You can use different credentials for different environments (for example, production versus development).

To manage environment variables, we use the python-dotenv module. First, install it if you haven't already:

pip install python-dotenv
pip freeze > requirements.txt

Next, create a .env file at the root of your project and add your development environment variables. For example:

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

Finally, add the .env file to your .gitignore to maintain security:

echo ".env" >> .gitignore

To access these environment variables in Python, simply use os.environ.get():

import os

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

The .env file is used only for the development environment. For staging or production, set the environment variables on the Stackhero dashboard in your Python service configuration.

While this guide uses Flask's built-in development server, for production it is essential to use a production-ready WSGI server such as Gunicorn. Follow these steps:

  1. Install Gunicorn:

    pip install gunicorn
    pip freeze > requirements.txt
    
  2. Start your app using Gunicorn with the app:app argument (where the first app is the filename and the second app is the Flask instance):

    ENV=production gunicorn app:app \
      --error-logfile - \
      -b 0.0.0.0:8080
    
  3. Create a Makefile to simplify switching between development and production modes:

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

You can run your server in development mode using make dev (or simply make), and in production mode using make prod.

The simplest way to deploy your Python project is to use the Stackhero Python cloud hosting service. Key features include:

  • Deployment with a simple git push
  • Customizable domain with automatic TLS certificate management (HTTPS)
  • Runs on a private and dedicated VM for maximum security
  • Supports HTTP/2, TLS 1.3 (HTTPS), WebSockets, GZIP & Brotli compression, ETag, and TCP/UDP port access

To deploy your code to Stackhero, follow these steps:

  1. Retrieve your public key using:

    cat ~/.ssh/id_*.pub
    
  2. In the Stackhero dashboard, go to your "Stackhero for Python" service and click the "Configure" button.

  3. Copy the public key from the first step and paste it into the "SSH public keys" or "Key" field.

  4. Validate the configuration by clicking the "Validate" button at the bottom of the page.

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

Don't have SSH keys? Create them by running:

ssh-keygen -t ed25519

Finally, configure your repository to deploy to Stackhero. In your project folder, add a Git remote using the command provided in your Stackhero service (replace <XXXXXX> with your service's domain):

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

Git remote commandGit remote command

Once everything is configured, deploy your code to production with a single command:

git push stackhero main

Ensure you add and commit your changes before pushing your code to production. In Stackhero Code-Hero, you can quickly commit changes using the Command Palette (press Ctrl+Shift+P on Windows/Linux or Cmd+Shift+P on macOS and type Git: Commit).

After deployment, visit your API URL at https://<XXXXXX>.stackhero-network.com/api/tasks (replace <XXXXXX> with your service's domain) to see your Flask API in action.

By following this guide, you now understand how to create a REST API using Flask. With this knowledge, you can confidently develop and expand your RESTful applications, integrating them with various front-end and back-end services.