A Layman’s Guide for Data Scientists to create APIs in minutes
By: Rahul Agarwal
Tags: Machine Learning, Data Science, Editors Pick, Artificial Intelligence, Programming

How to write an API with FastAPI?

One of the most common use cases for Data Science is how to create an API for getting a model’s prediction? Let us assume that we have a Titanic Survival model in place that predicts if a person will survive or not. And, it needs a person’s age and sex as input params to predict. We will create this API using FastAPI in two ways: GET and PUT. Don’t worry; I will explain each as we go.

What is GET? — In a GET request, we usually try to retrieve data using query parameters that are embedded in the query string itself. For example, in the OMDB API, we use the GET request to specify the movie id and access key as part of the query itself.

What is PUT? — An alternative to the GET request is the PUT request, where we send parameters using a payload, as we will see in the second method. The payload is not part of the query string, and thus PUT is more secure. It will become more clear when you see the second part.

But before we go any further, we need to install FastAPI and uvicorn ASGI server with:

pip install fastapi

pip install uvicorn

1. The GET Way:

A simple FastAPI method to writing a GET API for our titanic model use case is as follows:

from fastapi import FastAPI app = FastAPI() @app.get("/predict")

def predict_complex_model(age: int,sex:str):

# Assume a big and complex model here. For this test I am using a simple rule based model

if age<10 or sex=='F':

return {'survived':1}

else:

return {'survived':0}

Save the above code in a file named fastapiapp.py and then you can run it using the below command on terminal.

$ uvicorn fastapiapp:app --reload

The above means that your API is now running on your server, and the --reload flag indicates that the API gets updated automatically when you change the fastapiapp.py file. This is very helpful while developing and testing, but you should remove this --reload flag when you put the API in production. Now you can visit the below path in your browser, and you will get the prediction results:

What happens is as you hit the command in your browser, it calls the http://127.0.0.1:8000/predict endpoint which in turn calls the associated method predict_complex_model with the with params age=10 and sex='M'

So, it allows us to use our function from a browser, but that’s still not very helpful. Your developer friend needs to use your predict function to show output on a frontend website. How can you provide him with access to this function?

It is pretty simple. If your developer friend also uses Python, for example, he can use the requests module like below:

import requests age = 15

sex = "F"

output = response.json() response = requests.get(f" http://127.0.0.1:8000/predict?age={age}&sex={ sex}")output = response.json()

So we can get the output from the running API(on the server) into our Python Program. A Javascript user would use Javascript Request Library, and a nodeJS developer will use something similar to do this in nodeJS. We will just need to provide them with the endpoint and parameters required.

To test your API, you could also go to the:

Where you will find a GUI way to test your API.

But as we said earlier, THIS IS NOT SECURE as GET parameters are passed via URL. This means that parameters get stored in server logs and browser history. This is not intended. Further, this toy example just had two input parameters, so we were able to do it this way, think of a case where we need to provide many parameters to our predict function.

In such a case or I dare say in most of the cases, we use the PUT API.

2. The PUT Way

Using the PUT API, we can call any function by providing a payload to the function. A payload is nothing but a JSON dictionary of input parameters that doesn’t get appended to the query string and is thus much more secure than GET.

Here is the minimal example where we do that same thing as before using PUT. We just change the content of fastapiapp.py to:

from fastapi import FastAPI

from pydantic import BaseModel class Input(BaseModel):

age : int

sex : str app = FastAPI()

def predict_complex_model(d:Input):

if d.age<10 or d.sex=='F':

return {'survived':1}

else:

return {'survived':0} @app .put("/predict")def predict_complex_model(d:Input):if d.age<10 or d.sex=='F':return {'survived':1}else:return {'survived':0}

note that we use app.put here in place of app.get previously. We also needed to provide a new class Input , which uses a library called pydantic to validate the input data types that we will get from the API end-user while previously in GET, we validated the inputs using the function parameter list. Also, this time you won’t be able to see your content using a URL on the web. For example, using the browser to point to the endpoint location gives:

So, we can check using the programmatic way using requests in Python again:



payload = json.dumps({

"age": 10,

"sex": "F"

})

response = requests.put("

response.json() import requests,jsonpayload = json.dumps({"age": 10,"sex": "F"})response = requests.put(" http://127.0.0.1:8000/predict ",data = payload)response.json()

Notice that we use requests.put here and we provide the payload using the data param in the requests.put function and we also make use of json library to convert our payload to JSON from a dict object.

We could also have used the GUI way as before using:

And, we are done with creating our API. It was simple for a change.

FastAPI makes the API creation, which used to be one of the dreaded parts of the Data Science process, much more intuitive, easy, and Fast.

You can find the code for this post as well as all my posts at my GitHub repository.

Also as a lot of people asked me in the comments “how to deploy the FastAPI API on ec2 and how to use images data rather than simple strings, integers, and floats as input to the API?” , I wrote a successor to this post. Do take a look if you find it interesting,