5 Reasons to Adopt FastAPI to build REST Web Services
Tags: python, machinelearning
Published: 2020-12-30 10:43:53

<!-- wp:paragraph -->
<p>A common way of deploying our machine learning models is exposing them through a REST Web Service API. And because our focus is not creating web tools, we prefer to adopt a well-tested, ready-to-use framework to shorten our time to market.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>When choosing a framework, we want to get the right balance between performance and productivity. Usually, as a tool is more specific and closer to the bare metal, it will perform better. However, low-level libraries leave most of the work to us. On the other hand, if a framework provides too much abstraction, it could degrade performance.&nbsp;</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>This article briefly discusses five reasons to adopt FastAPI as the framework for our REST API and why it offers an outstanding balance between performance and productivity.&nbsp;</p>
<!-- /wp:paragraph -->

<!-- wp:more -->
<!--more-->
<!-- /wp:more -->

<!-- wp:heading -->
<h2>1. High Performance</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>FastAPI is one of the fastest Python frameworks available, and its performance is comparable to NodeJS and Go frameworks, according to the TechEmpower benchmark.</p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2>2. Declarative Routing</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Creating routes and endpoints using FastAPI is very simple. We include a decorator around a method, and it will serve on the path specified in the decorator argument:&nbsp;</p>
<!-- /wp:paragraph -->

<!-- wp:syntaxhighlighter/code {"language":"python"} -->
<pre class="wp-block-syntaxhighlighter-code">@app.post("/diabetes:predict")
def predict(p):
    return __predict_batch([p])[0]</pre>
<!-- /wp:syntaxhighlighter/code -->

<!-- wp:paragraph -->
<p>To receive a path parameter, we need to declare the name of the path parameter in the path template and then declare a method parameter using the same name:&nbsp;</p>
<!-- /wp:paragraph -->

<!-- wp:syntaxhighlighter/code {"language":"python"} -->
<pre class="wp-block-syntaxhighlighter-code">@app.get("/patients/{patient_id}")
def get_patient(patient_id):
    pass</pre>
<!-- /wp:syntaxhighlighter/code -->

<!-- wp:paragraph -->
<p>Any other parameter declared in the method signature is handled as a query parameter. If the method has typed parameters, FastAPI automatically converts the query string parameters to the right type. In the example below, the endpoint supports the parameters "size" and "page" so that the framework will automatically convert the query parameters to their right type:</p>
<!-- /wp:paragraph -->

<!-- wp:syntaxhighlighter/code {"language":"python"} -->
<pre class="wp-block-syntaxhighlighter-code">@app.get("/patients")
def get_patient(page: int, size: int):
    pass</pre>
<!-- /wp:syntaxhighlighter/code -->

<!-- wp:paragraph -->
<p>With FastAPI, we declare routes and their parameters close to the method that servers the endpoint. We also receive the route parameters directly in method parameters, so we don't need to inspect generic data structures to find and validate parameters, representing a gain in our productivity.</p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2>3. Automatic Serialization and Deserialization</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>FastAPI automatically deserializes the bodies of requests into method parameters. To receive the request body as an object in our method, we need to create a Pydantic model class and declare this model as the type of our parameter. For example:</p>
<!-- /wp:paragraph -->

<!-- wp:group -->
<div class="wp-block-group"><div class="wp-block-group__inner-container"><!-- wp:syntaxhighlighter/code {"language":"python"} -->
<pre class="wp-block-syntaxhighlighter-code">from pydantic import BaseModel

class Patient(BaseModel):
    name: str
    address: str

@app.post("/patients")
def save_patient(patient: Patient):
    pass</pre>
<!-- /wp:syntaxhighlighter/code --></div></div>
<!-- /wp:group -->

<!-- wp:paragraph -->
<p>On the other hand, it is possible to automatically serialize a model to JSON format by just returning the object. For example:</p>
<!-- /wp:paragraph -->

<!-- wp:syntaxhighlighter/code {"language":"python"} -->
<pre class="wp-block-syntaxhighlighter-code">@app.get("/patient/{patient_id}")
def save_patient(patient_id):
    return Patient('John Smith', '99 Nowhere Street')</pre>
<!-- /wp:syntaxhighlighter/code -->

<!-- wp:paragraph -->
<p>Thus, we FastAPI we don't need to worry about handling serialization and deserialization in our business code.&nbsp;</p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2>4. Declarative validation</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>As we have declarative routing, we validate our parameters by declaring their accepted values instead of writing logic to test them. The first alternative in which we obtain automatic validation is by declaring the parameters' types in the method signature. In the following example, trying to pass an argument that is not an integer to the parameters page and size will result in a client error:</p>
<!-- /wp:paragraph -->

<!-- wp:syntaxhighlighter/code {"language":"python"} -->
<pre class="wp-block-syntaxhighlighter-code">@app.get("/patients")
def get_patient(page: int, size: int):
    pass</pre>
<!-- /wp:syntaxhighlighter/code -->

<!-- wp:paragraph -->
<p>However, only validating the parameters' types is not enough. We also need to validate the accepted range for them. In the previous, it does not make sense to have negative values or zero for page and size. So we can modify our method to accept only positive numbers:</p>
<!-- /wp:paragraph -->

<!-- wp:syntaxhighlighter/code {"language":"python"} -->
<pre class="wp-block-syntaxhighlighter-code">@app.get("/patients")
def get_patient(\
        page: int = Query(..., gt=0),\
        size: int = Query(..., gt=0)):
    pass</pre>
<!-- /wp:syntaxhighlighter/code -->

<!-- wp:paragraph -->
<p>We can also set validators for our models. For example, we can validate that the field name of a Patient model will only accept letters and have a maximum length of 50 characters:</p>
<!-- /wp:paragraph -->

<!-- wp:syntaxhighlighter/code {"language":"python"} -->
<pre class="wp-block-syntaxhighlighter-code">class Patient(BaseModel):
    name: str = Field(regex='[a-zA-Z\s]*', max_length=50)
    address: str</pre>
<!-- /wp:syntaxhighlighter/code -->

<!-- wp:paragraph -->
<p>Using declarative validation, we drastically reduce the amount of code in our application, as we do not need to write logic to test our parameters. And because we can write validation more easily and rapidly, we significantly increase our API's quality and security.</p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2>5. Automatic Documentation Generation</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Good documentation is an essential part of a great API. However, for most developers is a tedious task, and in many cases, they don't write any documentation at all. Even for those who enjoy writing documentation, writing a documentation page is time-consuming, which could be a problem in a short deadline project.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>With FastAPI, we have excellent documentation for our API with no significant additional efforts. That's because FastAPI automatically generates an OpenAPI (Swagger) documentation page for our API and makes it available under our application's/doc path. The documentation generated by FastAPI includes:</p>
<!-- /wp:paragraph -->

<!-- wp:list -->
<ul><li>The endpoints of our API</li><li>The request parameters and responses</li><li>The returned codes</li><li>The schemas of entities used in requests and responses</li><li>An interface to test our API</li></ul>
<!-- /wp:list -->

<!-- wp:paragraph -->
<p>All the information used to build the documentation page comes from our code. There's no need to write additional files nor executing extra commands to generate the docs. You start serving the application, and the documentation is there.</p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2>Conclusion</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>FastAPI is a great framework that offers an outstanding balance between performance and productivity. The declarative nature of routes and validation, combined with automatic features like serialization and documentation, allows us to write high-quality APIs with much less code so that we can focus on our models and business goals.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>To learn more about FastAPI, visit the site:</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p><a href="https://fastapi.tiangolo.com/" target="_blank" rel="noreferrer noopener">https://fastapi.tiangolo.com/</a></p>
<!-- /wp:paragraph -->