# Write your first RESTful API in FastAPI

A REST API is an API that conforms to the constrains of REST architecture and style. REST stands for representational state transfer. It was created by Roy Fielding. The cool thing about REST APIs is that they're cacheable, stateless and consistent. You can read more about it [here](https://www.redhat.com/en/topics/api/what-is-a-rest-api).
A simple way to look at an API is viewing it as an interpreter between the computer resources, or web services and a client, or user. It's also a way for organizations to share information securely. Say you want to get the ten most rated movies from IMDB. IMDB can share this information to you through an API, without disclosing sensitive information. Check out the [imdb API](https://imdb-api.com/api).

Today we'll  use FastAPI framework to build our first web API. [FastAPI](https://fastapi.tiangolo.com) is written in Python, and is just one of the python web frameworks. Two of the more known python frameworks would be [Django](https://www.djangoproject.com) and [Flask](https://flask.palletsprojects.com).

Let's get to it!

What we'll cover: <br>
* [Prerequisites](#pre) <br>
* [What is FastAPI?](#intro) <br>
* [Hello World in FastAPI](#hello) <br>
* [FastAPI basics](#basics) <br>
* [Build a working API](#code) <br>
* [Swagger UI](#swagger) <br>



#### <div id="pre">Prerequisites</div>
If you just want to read, then you can just follow along.
If you want to code along, here's what we're going to need:

  * [Python](https://www.python.org/) installed on your machine. If you're on linux, it's already installed :)
  * A virtual environment. It's not required, but it's good practice. Run the following command to install:<br>
    <div id="virtual"></div>
```bash
sudo apt install python3-pip && sudo pip3 install virtualenv 
``` 
* A code editor. I'm using VS Code. You can download it [here](https://code.visualstudio.com/download). You'll need the python extension for more productivity. Just click on the Extensions > Search 'Python', and ensure you install the Microsoft's version.

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1627808056692/HXbWHffTv.png)




#### <div id="intro">What is FastAPI?</div>
FastAPI is a high performance, easy to learn, fast to code, ready for production python framework.
It first showed up in 2019, created by Sebastian Ramírez. It improves the deveoper experience by having self-documenting APIs, and at the same time reduces boilerpate code.


#### <div id="hello">Hello World in FastAPI</div>
Let's see how easy it is to use FastAPI: 

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1627809777899/L1FaYd2rC.png)

Here's what I've done: <br>


1. ```from fastapi import FastAPI``` imports the FastAPI 
2. ```app = FastAPI()``` creates an instance of fastapi for us to use
3. ```@app.get("/")``` is a decorator that uses the http get method from FastAPI.
4. ```def index()``` <- Here we define a method that returns a hello world message 
<br>


#### <div id="basics">FastAPI basics</div>
Most important things to understand while working with FastAPI: <br>
* Typehints

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1627815614158/ivEQuwlgR.png)
Although typehints are built into python, they're crucial when working with FastAPI. As you can see in the example above, you will need to explicitely define the data type for all your variables ie: ```name: str```. This will apply for all data types say ```str```, ```int```, ```list```, ```dict``` etc.

* Path and Path Parameters

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1627810061715/qaJ8yEbc-.png)
The ```"/books"``` inside the parenthesis is a path. This means that when user goes to the path say example.com/books, they will be accessing this "/books" resource path

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1627810185491/VBBu4Mo0Z.png)
The ```"{book_id}"``` is called a path parameter. Path parameters are enclosed inside of  curly braces ```{}```. They offer a way to control specific resources. Say for instance you want to get a specific book, then you might want to add a path parameter with that book's id.

* Query Parameters
![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1627810829358/4XVf728uo.png)
These are not required. All parameters outside of the path are considered as query parameters.
Note the ```start: int``` and ```end: int``` on the ```all_read_books``` function. Those are the two query parameters that our API will expect.
The query is represented in a key-value pair, comes after a question mark ```?``` and is separated by an ampersand ```&```.
In our case, the query would be something similar to ```https://example.com/books/?start=0&end=12```

* Request Body
![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1627811486909/uCBdbb35T.png)

A request body is what the client will send to our API.
In our example, we've created a ```Book``` class, and parsed it to the ```add_a_book``` function as a ```book``` parameter. This will send an instance of a ```Book``` with the post method to our API.


#### <div id="code">Build a working API</div>

Now let's build a working API in FastAPI: <br>
* Create an empty directory anywhere: 
```bash
mkdir fastapi && cd fastapi
``` 
* Create a virtual environment and activate it:
```bash
virtualenv venv && source venv/bin/activate
``` 
* Install FastAPI: 
```bash
pip install fastapi uvicorn
``` 
* Now open the in your editor:
```bash
code .
``` 

* Let's write our first endpoint! 
   Get all books.
 Copy the code below:

```python
from fastapi import FastAPI

app = FastAPI()

db = []

@app.get("/books")
def get_all_books():
    return db
``` 
Line 3 creates an empty list to act as our in-memory data storage. the ```/books``` path will return whatever is inside the db. Save the file as ```main.py``` (This is important)

* To view it, go back to the terminal window and run the following command:
```bash
uvicorn main:app --reload
``` 

This calls the ```app``` variable inside of the ```main.py``` script. The ```--reload``` ensures that the server will refresh each time we save the file.
Now head over to [localhost:8000/books](http://localhost:8000/books)

You should see something similar to this: <br>

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1627813304505/D09BGFcTi.png)

* Add a book to our ```db```: <br>

First we'll need a ```Book```. For that, we'll create a ```Book``` class to act as our Response Model. Import ```BaseModel```:<br>
```python
from pydantic import BaseModel
```
Add the ```Book``` class and ```add_a_book``` function: <br>
```python
class Book(BaseModel):
    title: str

@app.post("/books")
def add_a_book(book: Book):
    return db.append(book)

``` 
Here, we send the ```book``` request (Our book ```title```) to the API.

* Delete a ```Book``` from ```db```: <br>
To delete a book, we'll just use an ordinary pop() method <br>
Notice we're using ```book_id``` as a path parameter: 

```python
@app.delete("/books/{book_id}")
def delete_a_book(book_id: int):
    return db.pop(book_id)
``` 
* Get a specific ```Book```
To get one book, we'll need the ```book```'s id on the list. Here's how to do it:

```python

@app.get("/books/{book_id}")
def get_a_book(book_id: int):
    return db[book_id]
``` 
Here we use the list index as our ```book_id``` and parse it as our path parameter.

Get entire code on my [Github](https://github.com/waWanjohi/fastapi-demo) or [BitBucket](https://bitbucket.org/gekthee/fastapi-demo/) repo.

#### <div id="swagger">Swagger UI</div>
To test out our API, we'll use the inbuilt documentation for FastAPI.
Head over to your browser and open the link [http://localhost:8000/docs](http://localhost:8000/docs). You should be greeted by this page: 

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1627817228787/IPUVp4cbr.png)

Let's test the methods:
* Expand ```Get All Books```, click ```try it out``` then ```Excecute```:
![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1627818720604/ZCQOAM5EU.png)

* We'll do the same for ```Add A Book```:
![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1627818790652/0M_5uD77W.png)
Add several books so that we have something to test with. As you can see, I've added four:

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1627818266033/DM83Ai9UV.png)

* ```Get A Book```, it requires us to enter a ```book_id```, and returns a book in that index in our ```db```

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1627818564863/5SoH1M-d7.png)

* ```Delete A Book``` is similar to ```Get A Book```

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1627818634030/kuh9jNoxF.png)

