From an AI algorithm to a fully functional API

Ismail Mebsout
October 23, 2024
10 min

As a data scientist, when working on a complex project along with other developers, you, very often, need to package your AI algorithm into what we call an API which can be called by the backend in order to coordinate your app. Using an API has several advantages making your predictions more efficient and less time-consuming.

In this article, we will go through the definition of an API in general with a deep dive into RESTful ones, then we will create an API using python through the modules Flask and FastAPI. Finally, we will see how to communicate with it using a HTTP protocol via either Curls or via the software Postman.

The summary is as follows:

  1. API & RESTful API
  2. HTTP protocol & CURL & Postman
  3. Data Science model
  4. Flask
  5. FastAPI

API & RESTful API

An API, for Application Programming Interface, is a computer tool that allows packaging your code into a service that is easy and efficient to communicate with.
It can be seen as a step of transforming your developments into a black box with pre-defined communication codes allowing you as a provider to expose it readily to clients or consumers who can be Front & Back-end developers within your team.

Concept of an API

There exist many free APIs (Weather, Flight search, Football,…) which can be explored on RapidAPI.
There are many types of APIs:

  • Public or Open APIs: having no restrictions
  • Private or Internal APIs: used within the same company
  • Partner APIs: requires a license to get access to

If APIs enable two applications to communicate, Web Service APIs, as for them, enable the interaction between two machines on a given network. It is a system that uses an url on the World Wide Web to provide access to its services.
There are many types of web service APIs such as SOAP, JSON-RPC, XML-RPC,...etc. In this article, we will focus mainly on REST ones which are of a different kind.
Unlike the other web service APIs that are protocols, REST, for REprentational State Transfer, is a set of 5 major architectural principles making the RESTful web service light, efficient, scalable, and simple to use:

  • Client-server architecture: when the client is communicating with the server, it should either accept his request and send a response or reject it and notify him
  • Statelessness: consists of not storing any information on the server. It also implies that the client should make sure that all the needed data is in the request
  • Cacheability: is implemented on the client’s end in order to return a faster response when sending an old request
  • Layered system: is the ability to overlay additional layers, for instance, a security layer or a load balancer without affecting the client-server exchanges
  • Uniform interface: in simple words, is the use of URIs, for Uniform Resource Identifiers, to expose the structure of the repository. Combined with HTTP methods, it allows efficient XML or JSON exchanges with the server.
API's concept detailled

HTTP protocol & CURL & Postman

• HTTP protocol

Once you have created your web service API, you will need to communicate with it and that’s when HTTP comes into play.
HTTP, for HyperText Transfer Protocol, is a network communication protocol used to exchange data on the web. It was designed to facilitate the communication between web servers and web navigators such as Google Chrome and Safari. It is a stateless protocol that follows the client-server architecture making it easy to integrate with RESTful APIs.

HTTP protocol

Below, some of the most used methods of the protocol:

  • POST: creates a resource on the server
  • GET: accesses a resource on the server
  • PUT: updates a resource on the server
  • DELETE: deletes a resource on the server

• CURL

Very often, when working on a virtual machine, you only have access to a command line interface since there is no graphical interface and hence no navigator.
CURL, for Client URL Request Library and previously named httpget, is a command-line tool used to get and send resources to a server connected to a certain network. It supports many protocols including HTTP.
There are many curl options but in this article, we will focus on one specifically for our RESTful API:

  • -X: determines the HTTP method used when communicating with the server

• Postman

Postman is a software or a platform that simplifies the development and testing of APIs.
Through its user-friendly interface, it enables a very simple way of sending requests by:

  • Choosing the HTTP method
  • Entering the URL and the port on which the API is listening
  • Selecting the arguments, which will automatically update the HTTP request
  • Sending the request to the API

The response can be visualized at the bottom of the page in the body section.

Postman app

Data Science Model

For the sake of illustration, we will consider the Iris dataset which ML task consists of classifying the irises into three classes (Setosa, Versicolour, and Virginica) using four variables (Sepal Length, Sepal Width, Petal Length, and Petal Width).

The iris dataset will be downloaded from Sklearn and we will use a random forest classifier for training

import numpy as np
import pandas as pd

from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import train_test_split
from sklearn.metrics import confusion_matrix
from sklearn.metrics import accuracy_score
from sklearn.datasets import load_iris
from matplotlib import pyplot as plt
import joblib

%matplotlib inline
WEIGHTS_DIR="weights/"

iris = load_iris()

df=pd.DataFrame(iris.data, columns=iris.feature_names)
df["species"]=iris.target

X = df[iris.feature_names]
y = df['species']

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.20, random_state=42)

clf = RandomForestClassifier(max_depth=2, random_state=42)
clf.fit(X_train, y_train)
y_pred = clf.predict(X_test)

print("Confusion matrix: \n", confusion_matrix(y_test, y_pred))
print("Accuracy score: ", accuracy_score(y_test, y_pred, normalize=True) )

joblib.dump(clf, WEIGHTS_DIR+"clf_iris.joblib")

In the following paragraphs we will make the prediction on the following dataset:

Predicition dataset

Flask

Flask is a python module developed to create APIs and expose their services on a given network. It can be installed using the following command line:

pip install flask

In the following code, I will create a flask API that uses the previously trained model to predict the class of the irises given the four variables as inputs.

• Initializing the API

#%%
from flask import Flask, request, jsonify
import pandas as pd
import joblib
import json
WEIGHTS_DIR = "weights/"
FLASK_API = Flask(__name__)

• Loading the model

def get_iris_model():
    loaded_clf = joblib.load(WEIGHTS_DIR + "clf_iris.joblib")
    return loaded_clf
loaded_clf = get_iris_model()
def str_to_float_list(arg):
    arg = arg.split(",")
    arg = [float(x) for x in arg]
    return arg

• Routing

When creating an API, Routes are used to expose its functions and services. In flask, there are added using decorators.

- predict_class_postman
We create the route through which we will make the prediction. This route returns a json response with the corresponding class for each set of variables. When using Postman, we extract the variables using the args parameter of the request.

#%%Postman
def get_params_postman(request):
    sep_length = str_to_float_list(request.args.get("sepLen"))
    sep_width = str_to_float_list(request.args.get("sepWid"))
    pet_length = str_to_float_list(request.args.get("petLen"))
    pet_width = str_to_float_list(request.args.get("petWid"))
    return (sep_length, sep_width, pet_length, pet_width)
@FLASK_API.route("/predict_class_postman", methods=["GET", "POST"])
def predict_class_postman():
    (sep_length, sep_width, pet_length, pet_width) = get_params_postman(request)
    new_row = pd.DataFrame(
        {
            "sepal length (cm)": [float(x) for x in sep_length],
            "sepal width (cm)": [float(x) for x in sep_width],
            "petal length (cm)": [float(x) for x in pet_length],
            "petal width (cm)": [float(x) for x in pet_width],
        }
    )
    y_pred = list(loaded_clf.predict(new_row))
    y_pred = [str(x) for x in y_pred]
    response = {"y_pred": ",".join(y_pred)}
    return jsonify(response)

- predict_class_curl
We create another route this time to communicate with the CURL command. We extract the variables from the command-line using the method form.get of the sent request.

#%%CURL
def get_params_curl(request):
    request_input = request.form.get("input")
    request_input = json.loads(request_input)
    sep_length = str_to_float_list(request_input["sepLen"])
    sep_width = str_to_float_list(request_input["sepWid"])
    pet_length = str_to_float_list(request_input["petLen"])
    pet_width = str_to_float_list(request_input["petWid"])
    return (sep_length, sep_width, pet_length, pet_width)
@FLASK_API.route("/predict_class_curl", methods=["GET", "POST"])
def predict_class_curl():
    (sep_length, sep_width, pet_length, pet_width) = get_params_curl(request)
    new_row = pd.DataFrame(
        {
            "sepal length (cm)": [float(x) for x in sep_length],
            "sepal width (cm)": [float(x) for x in sep_width],
            "petal length (cm)": [float(x) for x in pet_length],
            "petal width (cm)": [float(x) for x in pet_width],
        }
    )
    y_pred = list(loaded_clf.predict(new_row))
    y_pred = [str(x) for x in y_pred]
    response = {"y_pred": ",".join(y_pred)}
    return jsonify(response)

• Starting the service

Once we have defined all the elements above, we start the service of the API by adding the following code:

#%%
if __name__ == "__main__":
    FLASK_API.debug = True
    FLASK_API.run(host="0.0.0.0", port="8080")
  • The debug mode can be useful to instantly visualize the changes
  • We can choose the URL and port on which the API is exposed:

To launch the API, type:

python flask_api.py

Where flask_api.py is the file hosting all the code developed above.

We get the following response:

>>> * Serving Flask app "flask_api" (lazy loading)
>>> * Environment: production
WARNING: This is a development server. Do not use it in a production deployment.
Use a production WSGI server instead.
>>> * Debug mode: on
>>> * Running on http://0.0.0.0:8080/ (Press CTRL+C to quit)
>>> * Restarting with fsevents reloader
>>> * Debugger is active!
>>> * Debugger PIN: 514-546-929

• Request & Response

+ Postman
Given the HTTP request on Postman

localhost:8080/predict_class_postman?sepLen=1,5&sepWid=2,6&petLen=3,7&petWid=4,8

The response is the following:

{
  "y_pred": "1,2"
}
Postman's API call

+ CURL
We launch the following command-line using a curl to communicate with the API:

curl -F "input={\"sepLen\":\"1,5\",\"sepWid\":\"2,6\",\"petLen\":\"3,7\",\"petWid\":\"4,8\"}" -X POST "http://0.0.0.0:8080/predict_class_curl"

As expected, we get the same results:

Image by Author

HTTP codes: if the request is correct the API returns the HTTP code 200. There exist other codes such as 4xx for client error and 5xx for server error.

Image by Author

You can find the code of the flask API in my GitHub repository.

FastAPI

FastAPI is another python module that enables the development of APIs.
It can be installed using the command line:

pip install fastapi

It is very similar to Flask, yet faster, with minor changes:

  • Query parameters from postman are extracted using request.query_params
  • Form parameters in curls are obtained using eval(input) where input: str = Form(...)
#%%
import pandas as pd
import joblib
import json
from fastapi import FastAPI, Form, Request
import uvicorn

WEIGHTS_DIR = "weights/"
FASTAPI_API = FastAPI()

#%%
def get_iris_model():
    loaded_clf = joblib.load(WEIGHTS_DIR + "clf_iris.joblib")
    return loaded_clf


def str_to_float_list(arg):
    arg = arg.split(",")
    arg = [float(x) for x in arg]
    return arg


loaded_clf = get_iris_model()

#%%Postman
def get_params_postman(query_params):
    sep_length = str_to_float_list(query_params["sepLen"])
    sep_width = str_to_float_list(query_params["sepWid"])
    pet_length = str_to_float_list(query_params["petLen"])
    pet_width = str_to_float_list(query_params["petWid"])
    return (sep_length, sep_width, pet_length, pet_width)


@FASTAPI_API.post("/predict_class_postman")
def predict_class_postman(request: Request):
    query_params = dict(request.query_params)
    (sep_length, sep_width, pet_length, pet_width) = get_params_postman(query_params)
    new_row = pd.DataFrame(
        {
            "sepal length (cm)": [float(x) for x in sep_length],
            "sepal width (cm)": [float(x) for x in sep_width],
            "petal length (cm)": [float(x) for x in pet_length],
            "petal width (cm)": [float(x) for x in pet_width],
        }
    )
    y_pred = list(loaded_clf.predict(new_row))
    y_pred = [str(x) for x in y_pred]

    response = {"y_pred": ",".join(y_pred)}
    return response


#%%CURL
def get_params_curls(input_var):
    sep_length = str_to_float_list(input_var["sepLen"])
    sep_width = str_to_float_list(input_var["sepWid"])
    pet_length = str_to_float_list(input_var["petLen"])
    pet_width = str_to_float_list(input_var["petWid"])
    return (sep_length, sep_width, pet_length, pet_width)


@FASTAPI_API.post("/predict_class_curl")
def predict_class_curl(input: str = Form(...)):
    input_var = eval(input)
    (sep_length, sep_width, pet_length, pet_width) = get_params_curls(input_var)
    new_row = pd.DataFrame(
        {
            "sepal length (cm)": [float(x) for x in sep_length],
            "sepal width (cm)": [float(x) for x in sep_width],
            "petal length (cm)": [float(x) for x in pet_length],
            "petal width (cm)": [float(x) for x in pet_width],
        }
    )
    y_pred = list(loaded_clf.predict(new_row))
    y_pred = [str(x) for x in y_pred]

    response = {"y_pred": ",".join(y_pred)}
    return response


#%%
if __name__ == "__main__":
    uvicorn.run(FASTAPI_API, host="0.0.0.0", port=8080)

The FastAPI is run using Uvicorn. It is a lightning-fast ASGI server implementation, based on uvloop and httptools where uvloop is a Cython-based replacement for asyncio’s event loop allowing 2–4 times faster than the default event loop.
Uvicorn can be installed using the following command line:

pip install uvicorn

To launch the API, type:

python fastapi_api.py

Where fastapi_api.py is the file hosting all the code developed above.

We get the following response:

>>> INFO:     Started server process [50003]
>>> INFO:     Waiting for application startup.
>>> INFO:     Application startup complete.
>>> INFO:     Uvicorn running on http://0.0.0.0:8080 (Press CTRL+C to quit)

• Request & Response

+ Postman
Given the HTTP request on Postman:

localhost:8080/predict_class_postman?sepLen=1,5&sepWid=2,6&petLen=3,7&petWid=4,8

The response is the following:

{  "y_pred": "1,2"}
Image by Author

+ CURL
We launch the following command-line using a curl to communicate with the API:

curl -F "input={\"sepLen\":\"1,5\",\"sepWid\":\"2,6\",\"petLen\":\"3,7\",\"petWid\":\"4,8\"}" -X POST "http://0.0.0.0:8080/predict_class_curl"

As expected, we get the same results with a 200 HTTP code::

{  
"y_pred": "1,2"
}

You can find the code of the FastAPI API in my GitHub repository.

Conclusion

APIs are very powerful tools that allow you to expose your work to services and facilitate communication with it. When working in a team of developers, mastering these technologies becomes crucial for the progress of the project.

Get In Touch

Have any questions? We'd love to hear from you.

Thank you! We will get back in touch with you within 48 hours.
Oops! Something went wrong while submitting the form.

From an AI algorithm to a fully functional API

How to simply and efficiently expose your AI algorithm as an API
Ismail Mebsout
Author
October 23, 2024
-
10 min

As a data scientist, when working on a complex project along with other developers, you, very often, need to package your AI algorithm into what we call an API which can be called by the backend in order to coordinate your app. Using an API has several advantages making your predictions more efficient and less time-consuming.

In this article, we will go through the definition of an API in general with a deep dive into RESTful ones, then we will create an API using python through the modules Flask and FastAPI. Finally, we will see how to communicate with it using a HTTP protocol via either Curls or via the software Postman.

The summary is as follows:

  1. API & RESTful API
  2. HTTP protocol & CURL & Postman
  3. Data Science model
  4. Flask
  5. FastAPI

API & RESTful API

An API, for Application Programming Interface, is a computer tool that allows packaging your code into a service that is easy and efficient to communicate with.
It can be seen as a step of transforming your developments into a black box with pre-defined communication codes allowing you as a provider to expose it readily to clients or consumers who can be Front & Back-end developers within your team.

Concept of an API

There exist many free APIs (Weather, Flight search, Football,…) which can be explored on RapidAPI.
There are many types of APIs:

  • Public or Open APIs: having no restrictions
  • Private or Internal APIs: used within the same company
  • Partner APIs: requires a license to get access to

If APIs enable two applications to communicate, Web Service APIs, as for them, enable the interaction between two machines on a given network. It is a system that uses an url on the World Wide Web to provide access to its services.
There are many types of web service APIs such as SOAP, JSON-RPC, XML-RPC,...etc. In this article, we will focus mainly on REST ones which are of a different kind.
Unlike the other web service APIs that are protocols, REST, for REprentational State Transfer, is a set of 5 major architectural principles making the RESTful web service light, efficient, scalable, and simple to use:

  • Client-server architecture: when the client is communicating with the server, it should either accept his request and send a response or reject it and notify him
  • Statelessness: consists of not storing any information on the server. It also implies that the client should make sure that all the needed data is in the request
  • Cacheability: is implemented on the client’s end in order to return a faster response when sending an old request
  • Layered system: is the ability to overlay additional layers, for instance, a security layer or a load balancer without affecting the client-server exchanges
  • Uniform interface: in simple words, is the use of URIs, for Uniform Resource Identifiers, to expose the structure of the repository. Combined with HTTP methods, it allows efficient XML or JSON exchanges with the server.
API's concept detailled

HTTP protocol & CURL & Postman

• HTTP protocol

Once you have created your web service API, you will need to communicate with it and that’s when HTTP comes into play.
HTTP, for HyperText Transfer Protocol, is a network communication protocol used to exchange data on the web. It was designed to facilitate the communication between web servers and web navigators such as Google Chrome and Safari. It is a stateless protocol that follows the client-server architecture making it easy to integrate with RESTful APIs.

HTTP protocol

Below, some of the most used methods of the protocol:

  • POST: creates a resource on the server
  • GET: accesses a resource on the server
  • PUT: updates a resource on the server
  • DELETE: deletes a resource on the server

• CURL

Very often, when working on a virtual machine, you only have access to a command line interface since there is no graphical interface and hence no navigator.
CURL, for Client URL Request Library and previously named httpget, is a command-line tool used to get and send resources to a server connected to a certain network. It supports many protocols including HTTP.
There are many curl options but in this article, we will focus on one specifically for our RESTful API:

  • -X: determines the HTTP method used when communicating with the server

• Postman

Postman is a software or a platform that simplifies the development and testing of APIs.
Through its user-friendly interface, it enables a very simple way of sending requests by:

  • Choosing the HTTP method
  • Entering the URL and the port on which the API is listening
  • Selecting the arguments, which will automatically update the HTTP request
  • Sending the request to the API

The response can be visualized at the bottom of the page in the body section.

Postman app

Data Science Model

For the sake of illustration, we will consider the Iris dataset which ML task consists of classifying the irises into three classes (Setosa, Versicolour, and Virginica) using four variables (Sepal Length, Sepal Width, Petal Length, and Petal Width).

The iris dataset will be downloaded from Sklearn and we will use a random forest classifier for training

import numpy as np
import pandas as pd

from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import train_test_split
from sklearn.metrics import confusion_matrix
from sklearn.metrics import accuracy_score
from sklearn.datasets import load_iris
from matplotlib import pyplot as plt
import joblib

%matplotlib inline
WEIGHTS_DIR="weights/"

iris = load_iris()

df=pd.DataFrame(iris.data, columns=iris.feature_names)
df["species"]=iris.target

X = df[iris.feature_names]
y = df['species']

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.20, random_state=42)

clf = RandomForestClassifier(max_depth=2, random_state=42)
clf.fit(X_train, y_train)
y_pred = clf.predict(X_test)

print("Confusion matrix: \n", confusion_matrix(y_test, y_pred))
print("Accuracy score: ", accuracy_score(y_test, y_pred, normalize=True) )

joblib.dump(clf, WEIGHTS_DIR+"clf_iris.joblib")

In the following paragraphs we will make the prediction on the following dataset:

Predicition dataset

Flask

Flask is a python module developed to create APIs and expose their services on a given network. It can be installed using the following command line:

pip install flask

In the following code, I will create a flask API that uses the previously trained model to predict the class of the irises given the four variables as inputs.

• Initializing the API

#%%
from flask import Flask, request, jsonify
import pandas as pd
import joblib
import json
WEIGHTS_DIR = "weights/"
FLASK_API = Flask(__name__)

• Loading the model

def get_iris_model():
    loaded_clf = joblib.load(WEIGHTS_DIR + "clf_iris.joblib")
    return loaded_clf
loaded_clf = get_iris_model()
def str_to_float_list(arg):
    arg = arg.split(",")
    arg = [float(x) for x in arg]
    return arg

• Routing

When creating an API, Routes are used to expose its functions and services. In flask, there are added using decorators.

- predict_class_postman
We create the route through which we will make the prediction. This route returns a json response with the corresponding class for each set of variables. When using Postman, we extract the variables using the args parameter of the request.

#%%Postman
def get_params_postman(request):
    sep_length = str_to_float_list(request.args.get("sepLen"))
    sep_width = str_to_float_list(request.args.get("sepWid"))
    pet_length = str_to_float_list(request.args.get("petLen"))
    pet_width = str_to_float_list(request.args.get("petWid"))
    return (sep_length, sep_width, pet_length, pet_width)
@FLASK_API.route("/predict_class_postman", methods=["GET", "POST"])
def predict_class_postman():
    (sep_length, sep_width, pet_length, pet_width) = get_params_postman(request)
    new_row = pd.DataFrame(
        {
            "sepal length (cm)": [float(x) for x in sep_length],
            "sepal width (cm)": [float(x) for x in sep_width],
            "petal length (cm)": [float(x) for x in pet_length],
            "petal width (cm)": [float(x) for x in pet_width],
        }
    )
    y_pred = list(loaded_clf.predict(new_row))
    y_pred = [str(x) for x in y_pred]
    response = {"y_pred": ",".join(y_pred)}
    return jsonify(response)

- predict_class_curl
We create another route this time to communicate with the CURL command. We extract the variables from the command-line using the method form.get of the sent request.

#%%CURL
def get_params_curl(request):
    request_input = request.form.get("input")
    request_input = json.loads(request_input)
    sep_length = str_to_float_list(request_input["sepLen"])
    sep_width = str_to_float_list(request_input["sepWid"])
    pet_length = str_to_float_list(request_input["petLen"])
    pet_width = str_to_float_list(request_input["petWid"])
    return (sep_length, sep_width, pet_length, pet_width)
@FLASK_API.route("/predict_class_curl", methods=["GET", "POST"])
def predict_class_curl():
    (sep_length, sep_width, pet_length, pet_width) = get_params_curl(request)
    new_row = pd.DataFrame(
        {
            "sepal length (cm)": [float(x) for x in sep_length],
            "sepal width (cm)": [float(x) for x in sep_width],
            "petal length (cm)": [float(x) for x in pet_length],
            "petal width (cm)": [float(x) for x in pet_width],
        }
    )
    y_pred = list(loaded_clf.predict(new_row))
    y_pred = [str(x) for x in y_pred]
    response = {"y_pred": ",".join(y_pred)}
    return jsonify(response)

• Starting the service

Once we have defined all the elements above, we start the service of the API by adding the following code:

#%%
if __name__ == "__main__":
    FLASK_API.debug = True
    FLASK_API.run(host="0.0.0.0", port="8080")
  • The debug mode can be useful to instantly visualize the changes
  • We can choose the URL and port on which the API is exposed:

To launch the API, type:

python flask_api.py

Where flask_api.py is the file hosting all the code developed above.

We get the following response:

>>> * Serving Flask app "flask_api" (lazy loading)
>>> * Environment: production
WARNING: This is a development server. Do not use it in a production deployment.
Use a production WSGI server instead.
>>> * Debug mode: on
>>> * Running on http://0.0.0.0:8080/ (Press CTRL+C to quit)
>>> * Restarting with fsevents reloader
>>> * Debugger is active!
>>> * Debugger PIN: 514-546-929

• Request & Response

+ Postman
Given the HTTP request on Postman

localhost:8080/predict_class_postman?sepLen=1,5&sepWid=2,6&petLen=3,7&petWid=4,8

The response is the following:

{
  "y_pred": "1,2"
}
Postman's API call

+ CURL
We launch the following command-line using a curl to communicate with the API:

curl -F "input={\"sepLen\":\"1,5\",\"sepWid\":\"2,6\",\"petLen\":\"3,7\",\"petWid\":\"4,8\"}" -X POST "http://0.0.0.0:8080/predict_class_curl"

As expected, we get the same results:

Image by Author

HTTP codes: if the request is correct the API returns the HTTP code 200. There exist other codes such as 4xx for client error and 5xx for server error.

Image by Author

You can find the code of the flask API in my GitHub repository.

FastAPI

FastAPI is another python module that enables the development of APIs.
It can be installed using the command line:

pip install fastapi

It is very similar to Flask, yet faster, with minor changes:

  • Query parameters from postman are extracted using request.query_params
  • Form parameters in curls are obtained using eval(input) where input: str = Form(...)
#%%
import pandas as pd
import joblib
import json
from fastapi import FastAPI, Form, Request
import uvicorn

WEIGHTS_DIR = "weights/"
FASTAPI_API = FastAPI()

#%%
def get_iris_model():
    loaded_clf = joblib.load(WEIGHTS_DIR + "clf_iris.joblib")
    return loaded_clf


def str_to_float_list(arg):
    arg = arg.split(",")
    arg = [float(x) for x in arg]
    return arg


loaded_clf = get_iris_model()

#%%Postman
def get_params_postman(query_params):
    sep_length = str_to_float_list(query_params["sepLen"])
    sep_width = str_to_float_list(query_params["sepWid"])
    pet_length = str_to_float_list(query_params["petLen"])
    pet_width = str_to_float_list(query_params["petWid"])
    return (sep_length, sep_width, pet_length, pet_width)


@FASTAPI_API.post("/predict_class_postman")
def predict_class_postman(request: Request):
    query_params = dict(request.query_params)
    (sep_length, sep_width, pet_length, pet_width) = get_params_postman(query_params)
    new_row = pd.DataFrame(
        {
            "sepal length (cm)": [float(x) for x in sep_length],
            "sepal width (cm)": [float(x) for x in sep_width],
            "petal length (cm)": [float(x) for x in pet_length],
            "petal width (cm)": [float(x) for x in pet_width],
        }
    )
    y_pred = list(loaded_clf.predict(new_row))
    y_pred = [str(x) for x in y_pred]

    response = {"y_pred": ",".join(y_pred)}
    return response


#%%CURL
def get_params_curls(input_var):
    sep_length = str_to_float_list(input_var["sepLen"])
    sep_width = str_to_float_list(input_var["sepWid"])
    pet_length = str_to_float_list(input_var["petLen"])
    pet_width = str_to_float_list(input_var["petWid"])
    return (sep_length, sep_width, pet_length, pet_width)


@FASTAPI_API.post("/predict_class_curl")
def predict_class_curl(input: str = Form(...)):
    input_var = eval(input)
    (sep_length, sep_width, pet_length, pet_width) = get_params_curls(input_var)
    new_row = pd.DataFrame(
        {
            "sepal length (cm)": [float(x) for x in sep_length],
            "sepal width (cm)": [float(x) for x in sep_width],
            "petal length (cm)": [float(x) for x in pet_length],
            "petal width (cm)": [float(x) for x in pet_width],
        }
    )
    y_pred = list(loaded_clf.predict(new_row))
    y_pred = [str(x) for x in y_pred]

    response = {"y_pred": ",".join(y_pred)}
    return response


#%%
if __name__ == "__main__":
    uvicorn.run(FASTAPI_API, host="0.0.0.0", port=8080)

The FastAPI is run using Uvicorn. It is a lightning-fast ASGI server implementation, based on uvloop and httptools where uvloop is a Cython-based replacement for asyncio’s event loop allowing 2–4 times faster than the default event loop.
Uvicorn can be installed using the following command line:

pip install uvicorn

To launch the API, type:

python fastapi_api.py

Where fastapi_api.py is the file hosting all the code developed above.

We get the following response:

>>> INFO:     Started server process [50003]
>>> INFO:     Waiting for application startup.
>>> INFO:     Application startup complete.
>>> INFO:     Uvicorn running on http://0.0.0.0:8080 (Press CTRL+C to quit)

• Request & Response

+ Postman
Given the HTTP request on Postman:

localhost:8080/predict_class_postman?sepLen=1,5&sepWid=2,6&petLen=3,7&petWid=4,8

The response is the following:

{  "y_pred": "1,2"}
Image by Author

+ CURL
We launch the following command-line using a curl to communicate with the API:

curl -F "input={\"sepLen\":\"1,5\",\"sepWid\":\"2,6\",\"petLen\":\"3,7\",\"petWid\":\"4,8\"}" -X POST "http://0.0.0.0:8080/predict_class_curl"

As expected, we get the same results with a 200 HTTP code::

{  
"y_pred": "1,2"
}

You can find the code of the FastAPI API in my GitHub repository.

Conclusion

APIs are very powerful tools that allow you to expose your work to services and facilitate communication with it. When working in a team of developers, mastering these technologies becomes crucial for the progress of the project.