Lesson 5
Building Your Own Custom Validator
Building Your Own Custom Validator

Welcome back! In this lesson, we will focus on building custom validators to handle specific data validation needs that built-in validators in Marshmallow may not cover. By creating custom validators, you can enforce business rules and data integrity specific to your application.

Let's get started!

Basic Setup

Before we dive into custom validators, let's briefly recap our basic Flask setup using a mock database:

Python
1from flask import Flask, request, jsonify 2from marshmallow import Schema, fields, ValidationError 3 4# Initialize a Flask app instance 5app = Flask(__name__) 6 7# Mock database as a list of dictionaries 8database = [ 9 {"id": 1, "username": "cosmo", "email": "cosmo@example.com"}, 10 {"id": 2, "username": "jake", "email": "jake@example.com"}, 11 {"id": 3, "username": "emma", "email": "emma@example.com"} 12] 13 14# Define a User schema 15class UserSchema(Schema): 16 id = fields.Int() 17 username = fields.Str(required=True) 18 email = fields.Email(required=True)

Now, we are ready to define and use custom validators.

Custom Validators with Marshmallow

Marshmallow allows us to create custom validators using the @validates decorator. This decorator is applied to a function within your schema that will validate a specific field. If the value doesn’t meet the criteria, the function raises a ValidationError.

Here is a generic example:

Python
1from marshmallow import Schema, fields, validates, ValidationError 2 3class ExampleSchema(Schema): 4 example_field = fields.Str() 5 6 @validates('example_field') 7 def validate_example_field(self, value): 8 if value != 'expected_value': # Example condition 9 raise ValidationError('Value must be ...')

In this example:

  • example_field is a simple string field.
  • We use the @validates decorator on the validate_example_field function to indicate that it validates the example_field.
  • The function checks a condition and raises a ValidationError if the condition is not met.

Let’s now create custom validators for our specific use case.

Creating a Custom Validator for the Username Field

Let's start by building a custom validator for the username field. This validator will ensure that the username is at least three characters long and contains only alphanumeric characters (letters and numbers).

Python
1from marshmallow import validates 2 3class UserSchema(Schema): 4 id = fields.Int() 5 username = fields.Str(required=True) 6 email = fields.Email(required=True) 7 8 # Custom validator for the username field 9 @validates('username') 10 def validate_username(self, value): 11 if len(value) < 3: 12 raise ValidationError('Username must be at least 3 characters.') 13 if not value.isalnum(): 14 raise ValidationError('Username must contain only letters and numbers.')
  • In the code above we define a custom validator for the username field using the @validates decorator.
  • The validate_username method performs multiple checks by chaining if statements. It first checks if the username is at least three characters long, and then checks if it contains only alphanumeric characters.
  • If the username fails any of these checks, a ValidationError is raised with an appropriate error message.
Creating a Custom Validator for the Email Field

Next, let's create a custom validator for the email field. This validator will ensure that email addresses belong to a specific domain, @example.com.

Python
1class UserSchema(Schema): 2 id = fields.Int() 3 username = fields.Str(required=True) 4 email = fields.Email(required=True) 5 6 # Custom validator for the username field 7 @validates('username') 8 def validate_username(self, value): 9 if len(value) < 3: 10 raise ValidationError('Username must be at least 3 characters.') 11 if not value.isalnum(): 12 raise ValidationError('Username must contain only letters and numbers.') 13 14 # Custom validator for the email field 15 @validates('email') 16 def validate_email(self, value): 17 if not value.endswith('@example.com'): 18 raise ValidationError('Email must be a valid @example.com address.')
  • Here we define a custom validator for the email field using the @validates decorator.
  • The validate_email method checks if the email value ends with the domain @example.com.
  • If the email does not meet this condition, a ValidationError is raised with an error message specifying the requirement.
Response from Custom Validation

When a validation error occurs, the response will indicate the specific reasons for the failure. For example:

JSON
1{ 2 "error": { 3 "username": ["Username must be at least 3 characters."], 4 "email": ["Email must be a valid @example.com address."] 5 } 6}
Summary and Practice Section

In this lesson, we learned how to build custom validators using Marshmallow in a Flask application. We started with a basic setup, then created a custom validator for the username field to ensure it is at least three characters long and alphanumeric. We also developed a custom validator for the email field to ensure the email addresses belong to the specific domain @example.com. By integrating these custom validators into our schema, we can enforce specific business rules and data integrity.

Now, it's your turn to practice creating and validating custom fields in the upcoming exercises. Keep experimenting and happy coding!

Enjoy this lesson? Now it's time to practice with Cosmo!
Practice is how you turn knowledge into actual skills.