FastAPI by A Python Beginner (1)

Intro & Environment Setup

Leo Lin (leocantthinkofaname)
5 min readOct 4, 2023

This is a multiparter journey. I don’t know where it’s going to ends. You’re always welcome if you’re interested in this topic or want to join this step-by-step journey.

FastAPI by A Python Beginner

5 stories

Intro

I’ve been thinking about pick up another programming language for very long time. I’m a frontend developer, JavaScript has been a blessing and a curse for me, because it’s such a versatile language. With the power of Node, I can do almost everything with it. I’m fully aware of the situation that every time when I start doing something, I begin with…

“Ok, so I can solve it with this JavaScript library.” or “I can just write a simple script and execute it with node.”

And this is like a perfect definition of “If all you have is a hammer, everything looks like a nail.

There are quite a few languages I’d like to learn. And Python is one of them. I know Machine Learning, AI, web scraping etc… is where Python really shines. But I don’t want to be overwhelmed by all the technologies that I have no prior knowledge of while learning a new language. So, I decide to build a web service with it. And after some research online, I choose to go with FastAPI because of its simplicity. It’s a high-level framework that provides a good amount of tools to build a fully functional web API service. Then I don’t have to scratch my head the whole night try to figure out how to make things work. Because my priority is Python itself, not the other way around.

Disclaimers

  • This is not a tutorial from someone who already knew everything about Python & FastAPI. It’s a learning process.
  • FastAPI is still a new kid on the block in Python web development. I’m not here to promote this framework. Do properly evaluate its performance and capabilities before you start using it.

Environment Setup

Although I do use runtime version manger (currently asdf is my go-to choice). But this time I decide to give container a go. I think it’s a good fit for someone who just want to start coding without mess up their computer just because they’re not sure what they really need.

I’m using Docker to run and setup my container. If anyone want to follow alone and doesn’t have Docker installed on your computer, you can go https://www.docker.com/ and install it. The installation steps should be fairly straightforward and user-friendly enough.

Since I’m going to use container as my development environment. The first thing is going to create a Python image with all the dependencies installed.

The conventional way to manage Python dependencies is by using a requirements.txt file.

fastapi==0.103.1
pydantic==2.3.0
uvicorn==0.23.2

These are the minimum dependency requirements for now.

Now what I need to do is copy this file into my image, and run pip install to install those dependencies.

FROM python:3.11
WORKDIR /usr/src/app
COPY ./requirements.txt /usr/src/requirements.txt
RUN pip install --no-cache-dir --upgrade -r /usr/src/requirements.txt

Here I created a dockerfile in the project root. Inside the dockerfile I use the official Python 3.11 image as my base image. I didn’t try to use the latest Python 3.12 one. Because it just released days ago, I’m not sure about its compatibility.

And next is tell docker to copy the requirements.txt file from my local project root into /usr/src inside the container. And then run pip install --no-cache-dir --upgrade -r /usr/src/requirements.txt to install the dependencies.

Now I need a compose file to specify other aspects of this container. It’s time to create a docker-compose.yml file in the project root directory.

version: "3.9"
services:
fastapi:
container_name: fastapi
build: .
working_dir: /usr/src/app
command: uvicorn main:app --host=0.0.0.0 --port=8000 --reload
environment:
DEBUG: 1
volumes:
- ./app:/usr/src/app
ports:
- "80:8000"
restart: on-failure

At this point, I still not sure what I’m going to make. So, I just keep the service name and container name as FastAPI.

All the other settings are pretty straightforward. I tell docker to build the image from the dockerfile in the current directory. And run the command uvicorn main:app --host=0.0.0.0 --port=8000 --reload that make uvicorn execute app inside the main module and start hosting this app on 0.0.0.0:8000 . The --reload flag makes uvicorn reload itself every time there’s any code changes. And mount the app directory into container’s /usr/src/app. Lastly, map my local 80port to container’s 8000 port. So once the app start working, I can just go to http://localhost from my browser and see the response from the server.

And now just create an app folder which is going to be my working directory basically. Then create a __init__.py and main.py file under the app directory.

In Python, each folder is a package, and each .py file is a module. The __init__.py is not mandatory, but it allows us to use a simpler way to import modules. It also serves other purposes, but for now I’ll just leave it empty.

After all the steps, now the project folder should look like something below.

app
├── __init__.py
├── main.py
dockerfile
docker-compose.yml
requirements.txt

The Very Original “Hello World”

If all the setup is correct, we can start our app with docker-compose up command. It could take a while for Docker to pull the base Python image and run all the install commands.

Once the installation is completed. You should be able to see the log complaining about app not found in module main.

fastapi | ERROR: Error loading ASGI app. Attribute "app" not found in module "main".

Which is perfectly normal. Because we don’t have app in our main.py yet.

To initialize a FastAPI server, we first need to import the module in our main.py.

from fastapi import FastAPI

As a frontend developer, this syntax kind of bugs me a little bit. It's totally opposite of JavaScript’s import x from y.

Then we have to use it by declare the app and call the FastAPI we just imported

app = FastAPI()

After this step, our app should be able to take requests and send the response to the client. If you open the browser and go to http://localhost, you should be able to see {"detail": "Not Found"} with 404 status code.

Now, it’s time to say the infamous “Hello World”.

from fastapi import FastAPI

app = FastAPI()


@app.get("/")
async def root():
return {"Hello": "World!"}

We tell FastAPI to take all the get request of / to the following async function root, which returns a JSON {"Hello": "World!"}.

It’s just that simple. And this is basically why I choose FastAPI framework as my first taste of Python. Everything feels nature if you already have prior experiences of making an API service in other languages.

Time to call it a day.

All the source code can be found on my github: https://github.com/LeoCantThinkOfAName/newbie-fastapi

--

--