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:
- API & RESTful API
- HTTP protocol & CURL & Postman
- Data Science model
- Flask
- 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.

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 efficientXML
orJSON
exchanges with the server.

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.

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.

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:

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
andport
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"
}

+ 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:

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.

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 usingrequest.query_params
- Form parameters in
curls
are obtained usingeval(input)
whereinput: 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"}

+ 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.