Python REST APIs with FastAPI, CRUD application
Tags: python, fastapi, rest, crud
Published: 2021-03-01 19:02:28


Originally posted on [my blog](https://www.ousseynoudiop.com/python-rest-api-with-fastapi)

## Introduction

FastAPI is a modern, fast (high-performance), web framework for building APIs with Python 3.6+ based on standard Python type hints.

Why you should use FastApi for your next project?

- Fast: Very high performance, on par with NodeJS and Go (thanks to Starlette and Pydantic). [One of the fastest Python frameworks available.](https://fastapi.tiangolo.com/#performance)

- Fast to code: Increase the speed to develop features by about 200% to 300%. *

- Fewer bugs: Reduce about 40% of human (developer) induced errors. *
- Intuitive: Great editor support. Completion everywhere. Less time debugging.
- Easy: Designed to be easy to use and learn. Less time reading docs.
- Short: Minimize code duplication. Multiple features from each parameter declaration. Fewer bugs.
- Robust: Get production-ready code. With automatic interactive documentation.
- Standards-based: Based on (and fully compatible with) the open standards for APIs: OpenAPI (previously known as Swagger) and JSON Schema.

## Project Setup

Start by creating a new folder to hold your project called "fastapi-blog":

```bash
mkdir fastapi-blog && cd fastapi-blog
```

Next, create and activate a virtual environment(we will use pipenv):

Learn how to use pipenv [here](https://www.ousseynoudiop.com/python-how-to-setup-your-virtualenv-correctly)

Install dependencies

```bash
pipenv install fastapi uvicorn
```

```bash
✔ Successfully created virtual environment!
Virtualenv location: /Users/rosie/.local/share/virtualenvs/fastapi-blog-FXGAPIoM
Creating a Pipfile for this project...
Installing fastapi...
Adding fastapi to Pipfile's [packages]...
✔ Installation Succeeded
Installing uvicorn...
Adding uvicorn to Pipfile's [packages]...
✔ Installation Succeeded
Pipfile.lock not found, creating...
Locking [dev-packages] dependencies...
Locking [packages] dependencies...
Building requirements...
Resolving dependencies...
✔ Success!
Updated Pipfile.lock (d74721)!
Installing dependencies from Pipfile.lock (d74721)...
  🐍   ▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉ 0/0 — 00:00:00
To activate this project's virtualenv, run pipenv shell.
Alternatively, run a command inside the virtualenv with pipenv run
```

Run `pipenv shell` to activate your environment.

Create a new file and call it `app.py` we will put all codes in this file.

```bash
touch app.py
```

In this article we will use a Python list as a database, we will not use a real database.

Inside app.py file put this:

```python
# app.py
from fastapi import FastAPI

app = FastAPI()

@app.get("/")
def read_root():
  return {"home": "Home page"}

```

Open your terminal then run the server

```bash
$ uvicorn app:app

INFO:     Started server process [19004]
INFO:     Waiting for application startup.
INFO:     Application startup complete.
INFO:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
```

The first app is the name of the file and the second one is the name of our application `app = FirstAPI`.

Head up at [http://127.0.0.1:8000](http://127.0.0.1:8000)

Learn more about uvicorn [here](https://www.uvicorn.org/)

Let's create our fake database to store posts.

```python
# app.py
from fastapi import FastAPI
from pydantic import BaseModel
from typing import Optional, Text
from datetime import datetime

app = FastAPI()

postdb = []

# post model
class Post(BaseModel):
    id: int
    title: str
    author: str
    content: Text
    created_at: datetime = datetime.now()
    published_at: datetime
    published: Optional[bool] = False

@app.get("/")
def read_root():
  return {"home": "Home page"}
```

Here we create a simple Python class with type annotations using [Pydantic](https://pydantic-docs.helpmanual.io/) and Python [types module](https://docs.python.org/3/library/types.html).

For every blog post we store:

```md
- the title
- the author
- the content
- the date we created it
- the date we published it
- and the status of the post
```

We use `equal symbol(=)` to add a default value.

Now, create a new route to view all posts.

```python
# app.py
...
@app.get("/blog")
def get_posts():
    return postdb
```

Restart your server then open [http://127.0.0.1:8000](http://127.0.0.1:8000) you will see an empty `list []`.

Let's add our first post.

```python
...
@app.post("/blog")
def add_post(post: Post):
    postdb.append(post.dict())
    return postdb[-1]

```

One of the things I really love about FastAPI is the auto-generated docs.

Head up at [http://localhost:8000/docs](http://localhost:8000/docs).

Let's create our first post.
Click on `Try it out` then put this:

```json
{
  "id": 1,
  "title": "Getting started with Django",
  "author": "Ousseynou DIOP",
  "content": "Hello Django",
  "created_at": "2021-03-01T18:17:45.194020",
  "published_at": "2021-03-01T18:17:58.887Z",
  "published": true
}
```

Create more posts then go to [http://localhost:8000/blog](http://localhost:8000/blog)

Let's get a single post by its ID.

```python
# app.py
...
@app.get("/blog/{post_id}")
def get_post(post_id: int):
    post = post_id - 1
    return postdb[post]
```

The last two pieces of the CRUD are Update and Delete.

Let's begin by updating a post.

```python
# app.py
...
@app.post("/blog/{post_id}")
def update_post(post_id: int, post: Post):
    postdb[post_id] = post
    return {"message": "Post has been updated succesfully"}

```

Add now you can update a post easily.

To be able to delete a post, you need to add this.

```python
# app.py
...
@app.delete("/blog/{post_id}")
def delete_post(post_id: int):
    postdb.pop(post_id-1)
    return {"message": "Post has been deleted succesfully"}

```

### Wrap up

In this article, we've learned the basic building blocks of FastAPI by creating a simple CRUD application.
Let me know if you want to learn how to integrate a database with FastAPI.

See you in the next tutorial.