# Getting started with FastAPI
APIs are developed using a back-end language of which the code runs on a server. The back-end language used for this course is Python. Why?
- Previous knowledge (Programming Essentials)
- Small learning curve (easy to learn)
- More and more often used in IT applications
- Dictionaries (built-in in Python) can be used to create JSON code
In this course, we will make use of a framework on top of Python. A framework is a pre-established toolkit in software development that simplifies the creation of applications. Think of a framework like a toolbox for building computer programs. It's a ready-made set of tools and rules that makes creating applications easier. Instead of starting from scratch every time, you get a solid foundation to work with, saving time and effort.
In full stack development, frameworks are frequently used. They handle common problems, so we don't have to reinvent the wheel. FastAPI is one of these frameworks and it's specifically meant for creating APIs more easily. It's like using a faster and smarter version of basic Python for building an API without all the extra hassle.
# Installation
Create a new Python project in PyCharm (Python version 3.10 or higher).
Creating a Python project
When creating a Python project for this course, always make sure to use Python version 3.10 or higher and create a virtual environment for your project. Have a look at the page about PyCharm to read how you should create a Python project for the Full Stack Essentials course.
Let's install FastAPI including all optional dependencies and features by entering the following command in the terminal:
pip install "fastapi[all]"
This command not only installs FastAPI but also includes uvicorn
, which acts as the superhero server for your FastAPI application. Uvicorn is responsible for bringing your Python code to life. It's like the engine that runs the show, allowing you to share your API with the world. So, now you're not just installing FastAPI; you're also getting the power of uvicorn to run your code smoothly.
Nice to know
You can also install it part by part.
This is what you would probably do once you want to deploy your application to production:
pip install fastapi
Also install uvicorn
to work as the server:
pip install "uvicorn[standard]"
And the same for each of the optional dependencies that you want to use.
# First Steps
The simplest FastAPI file could look like this:
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
def root():
return {"message": "Hello World"}
2
3
4
5
6
7
Copy this code to a new Python file main.py
, which you create in your project.
Run the live server using the following command in the terminal:
uvicorn main:app --reload
Using another port
By default, uvicorn will run on port 8000. In case port 8000 is already taken on your device, you can change the default uvicorn port by adding --port <number>
at the end of the uvicorn command.
For example, if you want to run on port 3210, you would run the uvicorn command in the following way:
uvicorn main:app --reload --port 3210
After a few seconds, you will get a result similar to the lines shown below. If you get an error, check your installation.
INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
INFO: Started reloader process [28720]
INFO: Started server process [28722]
INFO: Waiting for application startup.
INFO: Application startup complete.
2
3
4
5
The command uvicorn main:app --reload
refers to:
- main: the file 'main.py' (the Python "module").
- app: the object created inside of
main.py
with the lineapp = FastAPI()
. - --reload: make the server restart after code changes. Only use this for development purposes.
In the output, there's a line with something like:
INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
That line shows the URL where your app is being served, in your local machine. Open your browser at http://127.0.0.1:8000.
You will see the JSON response as:
{"message": "Hello World"}
# Interactive API documentation (docs)
Now go to http://127.0.0.1:8000/docs (opens new window).
You will see the automatic interactive API documentation (provided by Swagger UI (opens new window)):
localhost
You could replace the IP address 127.0.0.1 by localhost in the link given above, accessing the interactive documentation with the following URL: http://localhost:8000/docs (opens new window)
This also applies anywhere else. You can always replace the IP address 127.0.0.1 by localhost and vice versa.
Changing the default endpoint for API documentation
In some cases, you might want the API documentation to be accessible using another link. In that case, we should add a parameter to the function that creates our FastAPI instance. In the parameter we add, we indicate at which endpoint the documentation should be available (leaving out http://127.0.0.1:8000
).
Let's say we want our documentation to be available at http://127.0.0.1:8000/information (opens new window). This would be the code we need:
from fastapi import FastAPI
app = FastAPI(docs_url="/information")
@app.get("/")
def root():
return {"message": "Hello World"}
2
3
4
5
6
7
In case we do not want the documentation to be available at all, we can pass the value False
to the docs_url
parameter.
from fastapi import FastAPI
app = FastAPI(docs_url=False)
@app.get("/")
def root():
return {"message": "Hello World"}
2
3
4
5
6
7
# OpenAPI
FastAPI generates a "schema" with all your API using the OpenAPI standard for defining APIs. A "schema" is a definition or description of something. Not the code that implements it, but just an abstract description:
- API "schema" In this case, OpenAPI (opens new window) is a specification that dictates how to define a schema of your API. This schema definition includes your API paths, the possible parameters they take, etc.
- Data "schema" The term "schema" might also refer to the shape of some data, like a JSON content. In that case, it would mean the JSON attributes, and data types they have, etc.
In essence, OpenAPI defines an API schema for your API. And that schema includes definitions (or "schemas") of the data sent and received by your API using JSON data schemas.
What is OpenAPI for ?
The OpenAPI schema is what powers the interactive documentation system included. And there are dozens of alternatives, all based on OpenAPI. You could easily add any of those alternatives to your application built with FastAPI. You could also use it to generate code automatically, for clients that communicate with your API. For example, frontend, mobile or IoT applications.
Check the openapi.json
If you are curious about how the raw OpenAPI schema looks like, FastAPI automatically generates a JSON (schema) with the descriptions of the entire API.
You can consult it directly at: http://127.0.0.1:8000/openapi.json (opens new window).
It will show a JSON starting with something like this:
{
"openapi":"3.0.2",
"info":{
"title":"FastAPI",
"version":"0.1.0"
},
"paths":{
"/":{
"get":{
"summary":"Root",
"operationId":"root__get",
"responses":{
"200":{
"description":"Successful Response",
"content":{
"application/json":{
"schema":{
}
}
}
}
}
}
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# A Hello-world API, step by step
We will be creating our first API in 5 general steps, learning along the way:
- Import
FastAPI
- Create an instance of the
app
- Write a path operation decorator, like
@app.get("/")
- Write a path operation function, like
def root(): ...
- Run the development server, like
uvicorn main:app --reload
# Step 1: Import FastAPI
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
def root():
return {"message": "Hello World"}
2
3
4
5
6
7
8
FastAPI
is a Python class that provides all the functionality for your API. We import it from the fastapi module (= FastAPI framework).
# Step 2: Create a FastAPI
app instance
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
def root():
return {"message": "Hello World"}
2
3
4
5
6
7
8
Here the app
variable will be an "instance" of the class FastAPI
. This will be the main point of interaction to create your API. This app
is the same one referred by uvicorn
in the command:
$ uvicorn main:app --reload
INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
2
3
Changing the instance name
It is possible to change the name of the instance. For example, if you create your app as such:
from fastapi import FastAPI
my_awesome_api = FastAPI()
@my_awesome_api.get("/")
def root():
return {"message": "Hello World"}
2
3
4
5
6
7
8
And put it in a file main.py
, then you would call uvicorn
like:
$ uvicorn main:my_awesome_api --reload
INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
2
3
As highlighted in the code above, if you change the name of the instance, you should also change the instance name in the decorator of your path operation decorator.
# Step 3: Create a path operation
With path operation we refer to a combination of a path and an HTTP operation.
# Theoretical background
"Path" here refers to the last part of the URL starting from the first /
.
So, in a URL like:
https://www.example.com/items/foo
...the path would be:
/items/foo
Endpoints?
A "path" is also commonly called an "endpoint" or a "route".
"Operation" here refers to one of the HTTP "methods". One of:
POST
GET
Beware that many more HTTP methods exist, but only GET and POST are treated within this course.
In the HTTP protocol, you can communicate to each path using one (or more) of these "methods". In OpenAPI, each of the HTTP methods is called an "operation".
When building APIs, you normally use these specific HTTP methods to perform a specific action:
POST
: to create data.GET
: to read data.
# Define an @decorator for a path operation
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
def root():
return {"message": "Hello World"}
2
3
4
5
6
7
8
The @app.get("/")
is a Python decorator which tells FastAPI that the function right below is in charge of handling requests that go to:
- the path
/
- using an HTTP
GET
operation
If you are writing a POST request, you would write this line as follows: @app.post("/")
For example the @app.post("/course")
would be a Python decorator which tells FastAPI that the function right below it is in charge of handling requests that go to:
- the path
/course
- using an HTTP
POST
operation
What is this @decorator?
That @something
syntax in Python is called a "decorator".
You put it on top of a function.
A "decorator" takes the function below and does something with it.
In our example, this decorator tells FastAPI that the function below corresponds to the path /
with an operation get
.
It is the "path operation decorator".
# Step 4: Define the path operation function
This is our path operation function:
- path:
/
. - operation:
GET
. - function: is the function below the "@decorator", i.e. below
@app.get("/")
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
def root():
return {"message": "Hello World"}
2
3
4
5
6
7
8
This is a simple Python function.
Here it will be called by FastAPI whenever it receives a request to the URL /
using a GET
operation.
For now the function is filled out with a return of a simple, hard coded JSON object.
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
def root():
return {"message": "Hello World"}
2
3
4
5
6
7
8
You can return a dict
, list
, singular values as str
, int
, etc.
Usually, a dictionary is returned. FastAPI will automatically convert this Python dictionary to the JSON format.
# Step 5: Run the development server
$ uvicorn main:app --reload
INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
2
3
Try out the API!
# Recap
So we have done the following to create the most basic API:
- Import
FastAPI
- Create an instance of the
app
- Write a path operation decorator, like
@app.get("/")
- Write a path operation function, like
def root(): ...
- Run the development server, like
uvicorn main:app --reload
# Warm-up exercise
Create a new Python project. Create a new file called main.py
within that project. In this file, create a dictionary which contains your favorite song. The dictionary should contain both the name of the artist and the title of the song. Next, ask one of your neighbours what his/her favorite song is. Create a new dictionary containing this song (artist + title).
Create a GET request that will return your favourite song and which can be addressed in the following manner:
http://localhost:8000/song/me
The returned JSON should have the following structure:
{
"artist": "Against The Current",
"title": "Weapon"
}
2
3
4
Create another GET request that will return the favorite song of your neighbour in the same JSON structure. You should address it using the following url:
http://localhost:8000/song/neighbour
The returned JSON should have the following structure, similar to the structure of the first GET request:
{
"artist": "Dua Lipa",
"title": "Physical"
}
2
3
4
Make sure that each GET request returns a different song.
Test your solution using Postman by performing a GET request to both endpoints.
Testing the endpoint /song/me
would give a result similar to the following: