How FastAPI compares against Django and more reasons to switch to it | by Akshar Raaj | Jul, 2024 | Level Up Coding

Source: How FastAPI compares against Django and more reasons to switch to it | by Akshar Raaj | Jul, 2024 | Level Up Coding

Published in

Level Up Coding

4 min read

Jul 19, 2024

2

Makes developer’s productivity lightning fast!

Lately I have been using FastAPI for all my API development. I am a huge proponent of Django, however find myself coming back to FastAPI often.

This is an attempt to compile my reasons for preferring FastAPI over Django for API development.

Input Validation

FastAPI provides several kind of validations out of the box.

Consider an API endpoint to fetch a user’s profile. It expects the user_id as a query parameter. user_id is a required field.

It’s straight forward to achieve with FastAPI.

@app.get("/profile") 
def profile(user_id: int):
    ...
    ...
    return {"first_name": first_name, "last_name": last_name}

An API request to /profile without query parameter user_id would lead to response status code 422. API would enforce that the client sends a user_id .

With Django, explicit validation would have to be added in the view.

def profile(request):
  if 'user_id' not in request.GET:
    content = {'message': 'user_id is required'}
    return HttpResponse(json.dumps(content), status=422, headers={'Content-Type': 'application/json'})
  ...
  ...

Thus, simple validations like enforcing a required field can be handled seamlessly by FastAPI.
It doesn’t require any explicit application code.
However, Django needs explicit application code in such scenarios.

With only one query parameter, it is still manageable with Django. It rapidly becomes unwieldy when dealing with multiple parameters.

Consider an API which returns a list of items. It deals with 3 query parameters:

  • category: required
  • page: optional
  • num_items: optional

With Django the view would appear like:

def list_items(request):
  if 'category' not in request.GET:
    message = 'category required'
    return HttpResponse(message, status=422)
  page = int(request.GET.get('page', 1))
  num_items = int(request.GET.get('num_items', 20))
  ...
  ...

FastAPI path operation function would appear like:

def list_items(category: str, page: int = 1, num_items: int: 20):
  ...
  ...

No explicit input validation needed. FastAPI would enforce that category is required. It will also ensure that page and num_items are optional.

Things become more interesting in POST requests, when application has to deal with request body.

Consider an API which allows creating an item. Assume item has attributes namedescription and pricename and price are required while description is optional.

With Django, you would have to deserialise the request body, perform the validation in the view and then perform subsequent steps.
Otherwise, you would have to use an API framework, like DRF. If using DRF, the serialiser would still need to be used in the view to perform validation.

With FastAPI, the function wouldn’t require any validation code. A Pydantic model with type annotations can take care of the validation.

class Item(BaseModel):
  name: str
  description: str | None = None
  price: int

@app.post("/items/")
def create_item(item: Item):
  ...
  ...
  return {"name": item.name, "description": item.description, "price": item.price}

No validation code is needed in create_item.

Request Parsing

With type annotation, FastAPI performs type conversion. Application code doesn’t need to perform any kind of type conversion.

Notice our last example around pagination. Django view code expects page and num_items to be integer. As query parameters are string, hence the Django view had to perform explicit type conversion.

page = int(request.GET.get('page', 1))
num_items = int(request.GET.get('num_items', 20))

With FastAPI, there was no need to use int().

We added type annotation for the function arguments page and num_items.
And FastAPI automatically took care of converting the string query parameter to an integer.

Things become more interesting while dealing with POST request body. Considering our previous example around create_item.

Let’s assume the request body is:

{
  "name": "iPhone",
  "description": "The prime focus is your privacy",
  "price": 2000
}

FastAPI will automatically parse this request body and pass an Item instance as argument to create_item. No parsing code would have to be written.

With Django, we would have to add an additional library like DRF to perform this parsing. And the DRF serialiser invocation would need to be added to the Django view.

Response serialization

With Django, you must explicitly perform the serialisation and return a HttpResponse or it’s subclass.

Assume we want to return JSON {"message": "Hello World"}. We need to explicitly perform the serialisation and wrap it in a HttpResponse.

def root(request):
  response = {"message": "Hello World"}
  content = json.dumps(response)
  return HttpResponse(content, headers={'Content-Type': 'application/json'})

You can return any serialisable type from a FastAPI path function. FastAPI would perform the appropriate serialisation.

def root():
  return {"message": "Hello World"}

FastAPI is smart enough to also deal with some non serialisable types like datetime, Pydantic models and SQLAlchemy ORM models.

In our previous example of create_item, we only need to say return item and FastAPI would wisely return a JSON representation containing all attributes of Item.

@app.post("/items/")
def create_item(item: Item):
  ...
  ...
  return item

The response would have the following structure.

{
  "name": "iPhone",
  "description": "The prime focus is your privacy",
  "price": 2000
}

Automatic API schema

FastAPI creates the data JSON schema based on the Pydantic models and type annotations. It also generates an API schema compliant with OpenAPI.

With Django, we will have to plug in external dependencies to achieve the same and would require significant pipelining stuff.

Django Good Parts

We mostly discussed areas where FastAPI shines over Django.

There are areas where Django is almost unbeatable! Some of these include:
– Django Admin
– ORM
– Template engine

Thus the choice of the framework should solely depend on the target use case.
When building APIs, probably opt for FastAPI over Django. However if the application requires an admin user interface or say rendering the HTML pages on the server, then Django might be more suited.

Leave a Reply

The maximum upload file size: 500 MB. You can upload: image, audio, video, document, spreadsheet, interactive, other. Links to YouTube, Facebook, Twitter and other services inserted in the comment text will be automatically embedded. Drop file here