Protect your API via Input Validation in Python 3 Data Class

Protect your API via Input Validation in Python 3 Data Class

Deserialise json input to a Python 3 data class and validate the input values to protect your API

Photo by Masaaki Komori on Unsplash


When building a web API, it is inevitable that we need to protect it or else it might be exploited by malicious users. One way is to do input validation of the request body the API receives. If it is a bad input, for example, our API expects an email address but is given an address, then, our API would (or should) reject the data and return a status code of 400 — BAD REQUEST .

Input validation on the server side must be done on top of the one on client side. The reason is that the data coming from the client side can not be trusted because anything can happen to the data before it reaches the server, for example, Man in the Middle (MITM) attack. Also, remember that the request can come from anywhere, for example, Postman or curl, and not just from your web and/or mobile app.

What You’ll Learn

You will learn how to model your API request body using Python 3’s dataclass and do input validation on it using marshmallow-dataclass package.

The use case we will go through in this tutorial is an API that accepts an email address as its input and creates a new user account based on the email address if it does not yet exist in the user database.

The system details for this tutorial:


Install the Dependencies

There are two dependency packages that need to be installed:


Let’s go ahead and install them on your Python project’s virtual environment.

Install marshmallow-dataclass using pip

Write the Request Body Model

As mentioned earlier, we are going to use Python 3’s dataclass to model our API request body. The input is an email address. Go ahead and create the basic dataclass without any input validation to start with.

Initial dataclass without input validation

Next, we will also add @dataclass_json decorator to be able to deserialise a json request body to the CreateUser data class.

CreateUser decorated with dataclass_json

Now, if we try to pass any kind of input to CreateUser , it will just accept it.

Examples showing CreateUser accepts any type of input

This isn’t good, is it? :cold_sweat:

Let’s see how we can improve it in the next section.

Add Input Field Validation

We are going to add a validator to our emailAddress field of CreateUser data class.

CreateUser with email address validation

Now, go ahead and try to create objects of CreateUser by passing different input values.

CreateUser objects still accept any type of input

Unfortunately, our CreateUser data class still accepts any types of input. :frowning:

Use Schema to Deserialise and Validate

The way the input validation is meant to work is via a schema that represents the dataclass we are interested in. In the previous section, we had not created the schema yet, that is why the validation did not work.

To create the schema for CreateUser , we need to use marshmallow_dataclass .

Add CreateUserSchema

Also, the way we initialise a CreateUser object needs to be adjusted to make use of the CreateUserSchema schema we just generated.

Examples with schema to create CreateUser objects

Our input validation works with CreateUserSchema . This way, our API will be protected from junk input that is not a valid email address.

Simpler Way to Use Schema for Input Validation

Lastly, I want to show you how we can automate the creation of the schema from the dataclass .

To do this, we need to use the @dataclass decorator that is provided by marshmallow_dataclass package, which behaves just like the @dataclass decorator in the Python 3.x’s standard dataclasses library.

Let’s modify our CreateUser data class and remove the CreateUserSchema as its creation will be automated.

Use marshmallow_dataclass to automate schema creation

Let’s see how to create a CreateUser object using our modified CreateUser data class.

Examples with automated schema to create CreateUser objects

Our code is much simpler now and the input validation works as expected. We did it, guys! :muscle:

Photo by Japheth Mast on Unsplash