Scroll down to the script below, click on any sentence (including terminal blocks!) to jump to that spot in the video!Cool, got it! Show me the script!
This Chapter isn't quite ready yet
Rest assured, the gnomes are hard at work on completing this video
Earlier, we talked about the three types of validation. First, HTML5 validation
with things like the
required attribute. It's dead-simple to setup, but limited.
Second, custom client-side validation, which we added because we wanted to make sure
the users enter a positive quantity. And third, of course, the one type of
validation you must have: server-side validation.
Look at the
RepLog entity. We already have a few important validation constraints:
reps cannot be blank and needs to be a positive number, and the
cannot be blank.
Thanks to HTML5 validation & client-side validation, we are already preventing these bad values from even being submitted to the server. And, of course, if some annoying hacker wants to send bad values to the API, sure, they totally could. But then our server-side validation would be there to tell them to bugger off.
However, a lot of time, I either skip client-side validation entirely, or just add it for a few things, but not everything. And, in that case, if an API request fails because of failed server-side validation, our React app needs to read those errors from the server and tell the user.
RepLogController. We're using the form system, but that's not important.
Nope, the really important thing is that we, somehow, get a
RepLog object that's
populated with data, and run it through the validation system. The form does this
for us. But if you were manually setting up the object or using the serializer to
deserialize, you could pass the object directly to the validation system to get
back a collection of errors.
In this application, I added a shortcut method called
BaseController. This recursively loops over my errors to create a big
array of errors, where the key is the name of the field. This is what's returned
from our API.
When you use the form system, there is one other way to add validation, which
is often forgotten: on the form itself:
ChoiceType is normally
used to render a
select element where
choices is where you define the valid
options. When used in an API, if we submit a value that is not in choices, the
form will fail validation.
For testing purposes, let's purposely make this easy to do. In
itemOptions array: these items match what's configured inside the form.
Add a fake one:
invalid_item with text
The server will not like this value. Let's try it anyways! Move over, select "Dark Matter", 10 and... ah! Run! Woh!
Ok, two things. First, you can see the request failed: 400 bad request. Great!
Our server-side validation is working and you can see the message in the response.
But, second, React exploded in a crazy way! Something about how each child in an
array should have a unique "key" prop, from
We know that error... but why is it suddenly happening?
There's one simple explanation and it's hiding in
rep_log_api.js. If you used
jQuery's AJAX function, you might remember that if the server returns an error
status code, a failure callback is executed instead of your
callback. That makes sense: the request failed!
fetch() does not do this. Even if the server sends back a 400 or 500
error... fetch thinks:
We did it! We made a request! Yaaay! Let's execute the
Thanks to that, our app parsed the JSON, thought it contained a rep log, tried to add it to state, and things went bananas.
This behavior... isn't great. So, I like to fix it: I'll paste in a new function called
checkStatus(). If we call this function and the status code is not 200 or 300,
it creates an
Error object, puts the response onto it, and throws it. By the way,
you could change this logic to also throw an error for 300-level status codes,
that's actually how jQuery works.
To use this, back up in
fetchJson(), add this handler:
Let's try it! Refresh, select our bad item, a number and... yes! This is a much more obvious message:
Uncaught (in promise) Error: Bad Request at
fetch is behaving better, let's use this error response to add a
message for the user.