Welcome back! In the previous lesson, we explored defining schemas and serializing data with Marshmallow. Now, we will take it a step further by handling incoming data from a request and automatically validating it using Marshmallow
. This is crucial for ensuring that the data your application receives adheres to expected formats and standards.
By the end of this lesson, you will be able to create a Flask endpoint that handles incoming user data, validates it using Marshmallow
schemas, and adds it to a mock database.
Here’s a reminder of the initial setup, including the Flask app instance and our mock database:
Python1from flask import Flask 2 3# Initialize a Flask app instance 4app = Flask(__name__) 5 6# Mock database as a list of dictionaries 7database = [ 8 {"id": 1, "username": "cosmo", "email": "cosmo@example.com"}, 9 {"id": 2, "username": "jake", "email": "jake@example.com"}, 10 {"id": 3, "username": "emma", "email": "emma@example.com"} 11]
To handle incoming data properly, we need to specify what valid data looks like using a Marshmallow schema. Let's focus on making certain fields mandatory, like username
and email
.
Here's an updated version of our schema that enforces these requirements:
Python1from marshmallow import Schema, fields 2 3# Define a Marshmallow schema for user data 4class UserSchema(Schema): 5 id = fields.Int() 6 username = fields.Str(required=True) 7 email = fields.Email(required=True) 8 9# Create an instance of the User schema 10user_schema = UserSchema()
In this schema, setting required=True
for the username
and email
fields ensures that both fields must be provided and follow their respective data types (string and email format).
On the other hand, the id
field is not marked as required because it will be generated automatically when a new user is added. This setup helps keep our user data accurate and complete.
Now that we've defined our schema, we need to validate incoming data against this schema!
We'll use Marshmallow
's load
method to load and validate incoming JSON data. If the data is invalid, Marshmallow
will raise a ValidationError
. Let's see how this works in the context of a Flask route:
Python1from flask import request, jsonify 2from marshmallow import ValidationError 3 4# Define a route to handle user creation 5@app.route('/users', methods=['POST']) 6def create_user(): 7 try: 8 # Validate the incoming JSON data using the User schema 9 user_data = user_schema.load(request.get_json()) 10 except ValidationError as err: 11 # Return validation errors as a JSON response 12 return jsonify(error = err.messages), 400
request.get_json()
retrieves the incoming JSON data from the request body.user_schema.load(request.get_json())
attempts to load and validate this data against the UserSchema
.ValidationError
is raised, and we catch it in the except
block, returning the error messages as a JSON response with a 400 status code.Once the data is validated, we can proceed to add it to our mock database. Here is the complete code snippet:
Python1from flask import request, jsonify 2from marshmallow import ValidationError 3 4# Define a route to handle user creation 5@app.route('/users', methods=['POST']) 6def create_user(): 7 try: 8 # Validate the incoming JSON data using the User schema 9 user_data = user_schema.load(request.get_json()) 10 except ValidationError as err: 11 # Return validation errors as a JSON response 12 return jsonify(error = err.messages), 400 13 14 # Generate a new ID by finding the maximum existing ID and adding 1 15 new_id = max(user['id'] for user in database) + 1 16 user_data["id"] = new_id 17 18 # Add the new user to the mock database 19 database.append(user_data) 20 21 # If validation is successful, return a positive status and the created user 22 return jsonify(new_user), 201
id
is generated and assigned to the new user.database
list.If the incoming request does not meet the validation criteria defined in the UserSchema
, the ValidationError
exception will be raised and the response will detail the specific validation errors.
For example, if both username
and email
are missing, the response will look like this:
JSON1{ 2 "error": { 3 "email": [ 4 "Missing data for required field." 5 ], 6 "username": [ 7 "Missing data for required field." 8 ] 9 } 10}
This response is returned with a 400 status code, indicating invalid data provided by the client.
Additionally, if the email
field contains an invalid email address, the response will look like this:
JSON1{ 2 "error": { 3 "email": [ 4 "Not a valid email address." 5 ] 6 } 7}
This response is also returned with a 400 status code, indicating invalid data provided by the client.
In this lesson, we extended our Marshmallow
skills by focusing on handling incoming data and its validation. Specifically, we:
UserSchema
with required fields using Marshmallow
.With these concepts in mind, you're now ready to tackle the practice exercises ahead. These exercises will provide hands-on experience and help solidify your understanding.
Keep practicing, and happy coding!