Custom Form Validation in React with Redux Middleware
Tags: react, redux, middleware, formvalidation
Published: 2018-03-21 15:53:54

---
title: Custom Form Validation in React with Redux Middleware
published: true
description: Redux provides a clean architecture for state management. So why do we continue to muddy our components with complex validation logic? Instead, let's leverage Redux, with the help of some custom middleware!
tags: React, Redux, Middleware, Form Validation
---
*This post was originally published on the [TuneCore Tech Blog](http://tech.tunecore.com/)*
Redux provides a clean architecture for state management. So why do we continue to muddy our components with complex validation logic? Instead, let's leverage Redux, with the help of some custom middleware!

## Redux and State Management

Redux provides a centralized state management system for our React apps. We subscribe our component tree to a central store and state changes are enacted via a data-down-actions-up pattern. Actions are dispatched to the store, the store uses a reducer to change state and broadcast the new state to our components, and the components then re-render.

Letting Redux manage our React application's state means taking (most) of that responsibility _away_ from individual components–– even our big meaty container components. We don't let our components establish complex internal state and we don't weigh these components down with complex logic to update such state. Instead, we use the Redux store to shape our application's state; action creator functions to communicate the need for state changes; reducers to make state changes. So why should we treat our form validation and error handling any differently?

Despite the adherence of so many React developers to the Redux architecture, it's still common to see complex form components that handle their own validations and errors. Let's allow Redux to do what it does best and manage such interactions for us!

## The App
_**Note**: You can check out the complete code for this project on GitHub [here](https://github.com/SophieDeBenedetto/spacex-apply), and you can play around with a live demo [here](https://spacex-apply.herokuapp.com/). Keep in mind that this is simple dummy app and as such does not have a persistence layer. Sorry, we're not really saving your form
responses :(_

[You may have heard that we can travel to space now](http://www.bbc.com/news/science-environment-42969020). Elon Musk is looking to staff a mission to Mars. All of the world's top astronauts and nerds are competing for a spot on the ship. In order to apply for a position, you have to fill out a pretty complicated, rigorous application form. As the developers behind this form, we need to implement a complex set of form validations.

Here's a look at the behavior we're going for:

{% youtube O9aBHizDpvo %}


Our form validations range from the standard:

* Without the required fields of name and email, the form cannot be submitted.
* Email must be a properly formatted email address.

To the more complicated:

* The email a user supplies _must_ be their official SpaceEx email address––`name@space.ex`––as only registered SpaceEx members can apply for this mission.
* If an applicant checks that they _do_ have experience terraforming other planets, they must fill out the "which planets have you terraformed?" text field.
* The "which planets have you terraformed?" text field _cannot_ contain "Mars"––this is a mission to Mars, we know you didn't terraform it already!

We can imagine that the list of complex form validations could go on and on. Trying to manage all of this in one component, let's say a `FormContainer` component, will get really messy, really fast. Instead, we'll offload the form validation and the population of error messages to Redux.

### Application State

Our app is pretty simple--it displays an astronaut application form and submits that form. Our initial state looks like this:

```javascript
// client/src/store/initialStates/astronaut.js

{
  astronaut: {
    id: null,
    name: "",
    email: "",
    terraform_experience: false,
    terraform_planets: ""
  }
}
```

### The Component Tree

Our component architecture is also simple. We have a top-level container component: `AstronautForm` that contains some child components, each of which represent a section of the form.

Here's a simplified look:

[`client/src/components/AstronautForm.js`:](https://github.com/SophieDeBenedetto/spacex-apply/blob/master/client/src/components/AstronautForm.js)
```jsx
import React                  from 'react';
import { Form, Button}        from 'react-bootstrap'
import { connect }            from 'react-redux';
import { bindActionCreators } from 'redux';
import * as astronautActions  from '../actions/astronautActions';
import AstronautName          from './form/AstronautName';
import AstronautEmail         from './form/AstronautEmail';
import TerraformExperience    from './form/TerraformExperience';
import TerraformPlanets       from './form/TerraformPlanets';

class AstronautForm extends React.Component {
  ...
  render() {
    const {
      id,
      name,
      email,
      terraform_planets,
      terraform_experience
    } = this.props.astronaut;

    return (
      <Form key="astronaut-form" onSubmit={this.submitForm}>
        <AstronautName
          name={name}
          onAttributeUpdate={this.updateAstronautAttributes}/>
        <AstronautEmail
          email={email}
          onAttributeUpdate={this.updateAstronautAttributes}/>
        <TerraformExperience
          terraformExperience={terraform_experience}
          onAttributeUpdate={this.updateAstronautAttributes}/>
        <TerraformPlanets
          terraformExperience={terraform_experience}
          terraformPlanets={terraform_planets}
          onAttributeUpdate={this.updateAstronautAttributes}/>
        <Button type="submit">
          Submit
        </Button>
        <Button onClick={this.clearForm}>
          Clear
        </Button
      </Form>
    )
  }
}

function mapStateToProps(storeState, componentProps) {
  const { astronaut } = storeState;
  return { astronaut };
}

function mapDispatchToProps(dispatch) {
  return { actions: bindActionCreators(astronautActions, dispatch) }
};

export default connect(mapStateToProps, mapDispatchToProps)(AstronautForm);
```

Our `AstronautForm` component is the container component. It is connected to Redux and aware of state changes. It uses `mapStateToProps` to pluck `astronaut` out of state and make it available as part of the component's `props`. It _contains_ (get it?) the child components that make up our form:

* `AstronautName`: the name field on our form
* `AstronautEmail`: the email field on our form
* `TerraformExperience`: the terraforming experience checkbox
* `TerraformPlanets`: the terraformed planets text field


### Managing State with Actions and Reducers

Our Redux architecture handles updates to the astronaut's attributes in state: name, email, terraform experience and terraform planets.

When a user is done filling out a particular form field, we use the `onBlur` event to dispatch an action that updates the corresponding attribute in state.

Let's take a look at the `AstronautName` component as an example:

[`client/src/components/form/AstronautName.js`:](https://github.com/SophieDeBenedetto/spacex-apply/blob/master/client/src/components/form/AstronautName.js)
```jsx
import React from 'react';

class AstronautName extends React.Component {
  state = {
    name: ""
  };

  componentWillReceiveProps(nextProps) {
    this.setState({name: nextProps.name});
  };

  onChange = (e) => {
    this.setState({name: e.target.value});
  };

  onBlur = (e) => {
    this.props.onAttributeUpdate(
      { name: this.state.name }
    )
  };

  render() {
    const { name } = this.state;
    return (
      <div>
        <label>Name</label>
        <input
          type="text"
          onBlur={this.onBlur}
          onChange={this.onChange}
          value={name}/>
      </div>
    )
  }
};

export default AstronautName;
```

We passed in `name` as a prop from the `AstronautForm` parent component. We use `componentWillReceiveProps` to put that in `AstronautName`'s internal state.

We use the `onChange` event to update `AstronautName`'s state with the updated name. We use the `onBlur` event to call the `onAttributeUpdate` function.

This function is passed in as part of `props` from `AstronautForm`. `AstronautForm` defines the function like this:

[`client/src/components/AstronautForm.js`:](https://github.com/SophieDeBenedetto/spacex-apply/blob/master/client/src/components/AstronautForm.js)
```javascript
...
updateAstronautAttributes = (newAttributes) => {
  this.props.actions.updateAstronautAttributes(newAttributes)
};
```

We dispatch an action creator function `updateAstronautAttributes`. Our action looks like this:

[`client/src/actions/astronautActions.js`:](https://github.com/SophieDeBenedetto/spacex-apply/blob/master/client/src/actions/astronautActions.js)
```javascript
export function updateAstronautAttributes(newAttributes) {
  return {
    type: "UPDATE_ASTRONAUT_ATTRIBUTES",
    newAttributes
  }
}
```

This action is handled by our `astronautReducer` like this:

[`client/src/reducers/astronautReducer.js`:](https://github.com/SophieDeBenedetto/spacex-apply/blob/master/client/src/reducers/astronautReducer.js)
```javascript
import defaultState from '../store/initialStates/astronaut.js'

export default function astronautReducer(state=defaultState, action) {
  switch(action.type) {
    case "UPDATE_ASTRONAUT_ATTRIBUTES":
      return {...state, ...action.newAttributes}
    ...
  }
}
```

This creates a new version of our application's central state, updating our components accordingly.

### Submitting the Form

When a user clicks the "submit" button on our form, we fire the `submitForm` function, defined in the `AstronautForm` container component:

[`client/src/components/AstronautForm.js`:](// src/components/AstronautForm.js)
```javascript
...
submitForm = (e) => {
  e.preventDefault();
  this.props.actions.saveAstronaut(this.props.astronaut);
};
```

As described in the previous section, every time a user triggers the `onBlur` event of a particular form field (name, email, terraforming experience, terraforming planets), we dispatch an action to update the corresponding attribute in the application's state. Since the `AstronautForm` component is connected to Redux via the `connect` function, every time such a state change occurs, the component will re-render, and call `mapStateToProps`. Thus ensuring that at any given point in time, when the user hits "submit" the astronaut in `this.props.astronaut` is up-to-date with the latest changes.

So, our `submitForm` function just needs to dispatch the `saveAstronaut` action creator function with an argument of `this.props.astronaut`.

Our `saveAstronaut` action needs to send a web request to our API to submit the form. We know that we can't just plop some async code into the middle of an action creator function without the help of middleware. So, we have some custom API middleware that will send the web request for us. If you're unfamiliar with custom async middleware, I strongly recommend checking out the [official Redux Middleware documentation](https://redux.js.org/docs/advanced/Middleware.html), along with [this excellent post](http://tech.tunecore.com/redux-API-middleware) written by my TuneCore teammate, Charlie Massry.

Our action looks like this:

[`client/src/actions/astronautActions.js`:](https://github.com/SophieDeBenedetto/spacex-apply/blob/master/client/src/actions/astronautActions.js)
```javascript
export function saveAstronaut(astronaut) {
  return {
    type: "API",
    astronaut
  };
}
```

And our middleware looks like this:

[`client/src/middleware/apiMiddleware.js`:](https://github.com/SophieDeBenedetto/spacex-apply/blob/master/client/src/middleware/apiMiddleware.js)


```javascript
import {
  saveAstronautSuccess,
  saveAstronautFailure
} from '../actions/astronautActions';

const apiMiddleware = ({ dispatch, getState}) => next => action => {
  if (action.type !== "API") {
    return next(action)
  }
  fetch('/api/astronauts', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      astronaut: action.astronaut
    })
  }).then((response) => {
    return response.json();
  }).catch((error) => {
    dispatch(saveAstronautFailure(error));
  }).then((data) => {
    dispatch(saveAstronautSuccess(data));
  });
};

export default apiMiddleware;
```

Our middleware gets called by the store _before_ sending an action creator function's return value along to the reducer. If the action has a type of `"API"`, we will use `fetch` to send our API request. Then, when the promise resolves, we will dispatch another action. For the purpose of this post, we won't worry about our success and failure functions. Suffice it to say that the `success` function updates state with the saved astronaut and the `failure` function updates state with some error message.

Now that we understand the overall structure of our React + Redux app, we're ready to tackle our form validations.

### Form Validation
There are three categories of form validations we have to deal with for our app to work as expected.

* Required fields (like name and email)
* Custom validations that need to run when the form is submitted
* Custom validations that need to run when an attribute is updated in state

Let's start with the low-hanging fruit: required fields.

### Required Fields: Easy HTML5 Validations
Making a field required, and therefore preventing the user from submitting the form without it, is super easy to do with just HTML. We simply add `required` to the input tag.

[`client/src/components/form/AstronautName.js`:](https://github.com/SophieDeBenedetto/spacex-apply/blob/master/client/src/form/AstronautName.js)
```jsx
...
render() {
  const { name } = this.state;
  return (
    <div>
      <label>Name</label>
      <input
        required
        type="text"
        onBlur={this.onBlur}
        onChange={this.onChange}
        value={name}/>
    </div>
  )
}
```

Now, when a user clicks "submit" without filling out this field, we'll see this behavior:

{% youtube hgBP8gEPess %}

Blammo.

We can do the same for our email field for the same effect.

### Validate on Submission

Let's move on to some more complex form validations. If a user clicks the checkbox indicating that they _do_ have experience terraforming other planets, we want to require them to fill out the "which planets have you terraformed?" text field.

We _can't_ validate for the presence of `terraformed_planets` on the blur of the `terraformed_experience` checkbox. That would cause the error to show up for the terraformed planets field _right after they click the checkbox, before the user has a chance to interact with the `terraform_planets` text field_.

We _can_ (and should) validate the `terraform_planets` text field on the blur of that text field. But what if the user never clicks into that field at all? What if they check the `terraform_experience` checkbox and then immediately click "submit". We _don't_ want to actually submit the form to the API under those circumstances. We want to perform this validation before we send the web request.

### Why We Shouldn't Validate In the Component

We could handle this directly in the component by adding code to our `submitForm` function in `AstronautForm`:

#### Bad Example, Don't Do This:

```javascript
submitForm = (e) => {
  e.preventDefault();
  if (this.props.astronaut.terraform_experience && !this.props.astronaut_planets {
    this.props.actions.saveAstronaut(this.props.astronaut);
  } else {
    this.setState({
      errors:
        ...this.state.errors,
        terraform_planets: true
      }
    }
  }
};
```

This approach has a few drawbacks.

* It requires us to store `errors` in the `AstronautForm` component's state. While there isn't anything inherently wrong with this, storing complex state within individual components is exactly what Redux allows us to avoid.
* We are starting to add complex logic to our component. Currently, we're only looking at just two attributes. But if we really want our component to handle this validation, this code will have to grow to validate _every_ astronaut attribute. Not only is that messy, but it forces the form component's submit function to explod its responsibilities. No longer can it simply submit a form, now it validates the astronaut object stored in props and _decides_ whether it should submit the form or update the component's internal state. Think of your form submission function like a younger sibling that you don't entirely trust to do anything right and wouldn't give a lot of responsibility to (no offense Zoe). Our form submission function should do exactly that––submit a form. It _shouldn't_ be responsible for validating the astronaut or updating state.

Let's let Redux handle both validating the astronaut _and_ tracking astronaut errors.

### Tracking Errors in Redux's State

When we first established our state, we established an object that looks like this:

[`client/src/store/initialStates/astronaut.js`:](https://github.com/SophieDeBenedetto/spacex-apply/blob/master/client/src/store/initialStates/astronaut.js)

```javascript
{
  astronaut: {
    id: null,
    name: "",
    email: "",
    terraform_experience: false,
    terraform_planets: ""
  }
}
```

Let's expand the `astronaut` key of state to include errors, tracking an error for each attribute that we want to validate:

```javascript
{
  astronaut: {
    id: null,
    name: "",
    email: "",
    terraform_experience: false,
    terraform_planets: "",
    errors: {
      name: null,
      email: null,
      terraform_planets: null
    }
  }
}
```
Now that the `astronaut` key in Redux's state contains its own errors, we can rely on our `astronautReducer` to update these errors appropriately. When will we tell our reducer to update the astronaut's errors? Let's return to our use-case: "validating on submit".

### Custom Validation Middleware

According to our earlier example, we know that we want to validate the presence of `terraform_planets` when a user submit the form, _if they have checked the `terraform_experience` box_.

We want to perform this validation _after_ the user hits submit, _not_ inside our component, and we want to do the validation _before_ the API request gets sent. If the astronaut is not valid, we _don't_ want to send the API request. Instead, we'll dispatch an action that will tell our reducer to update the appropriate error in state.

How on earth can we plug into the moment in time _after_ the form is submitted and the `saveAstronaut` action is dispatched, but _before_ the API request is sent? Custom middleware of course!

We'll define some custom validation middleware and we'll add it to our middleware stack _before_ the custom API middleware. That way it will get called before the API middleware gets called, i.e. before the API request is sent.

This diagram illustrates where in the Redux lifecycle our middleware fits in.

![custom middleware](http://www.thegreatcodeadventure.com/content/images/2018/02/custom-middleware--1-.svg)

#### Defining the Middleware
We'll define our form validation middleware:

[`client/src/middleware/formValidationMiddleware.js`:](https://github.com/SophieDeBenedetto/spacex-apply/blob/master/client/src/middleware/formValidationMiddleware.js)

```javascript
const formValidationMiddleware = ({ dispatch, getState}) => next => action => {
  // validations coming soon!
};

export default formValidationMiddleware;
```

#### Adding to the Middleware Stack

We'll add it to the stack _before_ our custom `apiMiddleware`.

[`client/src/store/configureStore.js`:](https://github.com/SophieDeBenedetto/spacex-apply/blob/master/client/src/store/configureStore.js)
```javascript
import {
  createStore,
  applyMiddleware } from 'redux'
import rootReducer  from '../reducers'
import initialState from './initialState';
import apiMiddleware from '../middleware/apiMiddleware';
import formValidationMiddleware from '../middleware/formValidationMiddleware';

export default function configureStore() {
  return createStore(
    rootReducer,
    initialState,
    applyMiddleware(
      formValidationMiddleware,
      apiMiddleware
    )
  )
}
```

Now we're ready to code our validation middleware!

#### Performing the Validations

First things first. We _only_ want to do this validation work if the action that was dispatched is the `saveAstronaut` action. This is the action that will send the web request, courtesy of our `apiMiddleware`. So, we'll add an `if` statement that checks for the `"API"` action type. If the action does _not_ have that type, we'll return `next(action)` so that the action will proceed to the reducer.

[`client/src/middleware/formValidationMiddleware.js`:](https://github.com/SophieDeBenedetto/spacex-apply/blob/master/client/src/middleware/formValidationMiddleware.js)

```javascript
const formValidationMiddleware = ({ dispatch, getState}) => next => action => {
  if (action.type !== "API") {
    return next(action)
  }
  // validations coming soon!
};

export default formValidationMiddleware;
```

Okay, on to our validations. We'll run the validations for _every astronaut attribute_ that requires validation. By taking the validation logic out of the component, we are taking the responsibility of deciding whether to not to send the form submission API request out of the component too. We are allowing the component to dispatch the `saveAstronaut` action, regardless of the presence of any errors. So, we _always_ want to validate _all_ attributes in this middleware.

[`client/src/middleware/formValidationMiddleware.js`:](https://github.com/SophieDeBenedetto/spacex-apply/blob/master/client/src/middleware/formValidationMiddleware.js)

```javascript
import { astronautValidationError } from '../actions/astronautActions';
import astronautValidationErrors    from '../utils/astronautValidationErrors';
import astronautIsValid             from '../utils/astronautIsValid';

const formValidationMiddleware = ({ dispatch, getState}) => next => action => {
  if (action.type != = "API") {
    return next(action)
  }
  const { astronaut } = action;
  let errors          = astronautValidationErrors(astronaut)
  if (!astronautIsValid(errors)) {
    dispatch(astronautValidationError(errors))
  } else {
    next(action)
  };
};

export default formValidationMiddleware;
```

Let's break this down and take a look at some of the helper functions being called here.

First, we grab the astronaut from the action:

```javascript
const { astronaut } = action;
```

Then, we build the errors object with the help of a function, `astronautValidationErrors`.

```javascript
let errors = astronautValidationErrors(astronaut)
```
Our goal is to generate an object that looks exactly like the `errors` sub-key of state's `astronaut` key, with the values properly reflecting the presence of an error. We want to generate such an object so that we can send it along to the reducer which will use it to update the astronaut's errors in the application's state.

For example, the following errors object would indicate that there is an error with the `name` attribute, but not the `email` or `terraform_planets` attributes.

```javascript
{
  name: true,
  email: false,
  terraform_planets: false
}
```

Let's take a look at the `astronautValidationErrors` function defined in [`client/src/utils/astronautValidationErrors.js`](https://github.com/SophieDeBenedetto/spacex-apply/blob/master/client/src/utils/astronautValidationErrors.js):

```javascript
import { attributeValidators } from './attributeValidators';

export default function astronautValidationErrors(astronaut) {
  Object.keys(attributeValidators).reduce((errors, validator) => {
    errors[validator] = !attributeValidators[validator](astronaut)
  }, {})
}
```

This function relies on an object we've imported from another `utils/` file, [`attributeValidators`](https://github.com/SophieDeBenedetto/spacex-apply/blob/master/client/src/utils/attributeValidators.js):

```javascript
export const attributeValidators = {
  name: nameValid,
  email: emailValid,
  terraform_planets: terraformPlanetValid
}

function nameValid(astronaut){
  return astronaut.name && astronaut.name.length > 0;
}

function emailValid(astronaut) {
  return astronaut.email && astronaut.email.split("@")[1] === "space.ex"
}

function terraformPlanetValid(astronaut) {
  const { terraform_experience, terraform_planets } = astronaut;
  if (terraform_experience) {
    return terraform_planets &&
      terraform_planets.length > 0 &&
      !terraform_planets.toLocaleLowerCase().includes("mars");
  } else {
    return true
  }
}
```

Here we have an object `attributeValidators`, with keys corresponding to each of the astronaut attribute names and values pointing to our custom validation helper functions.

We use this object in our `astronautValidationErrors` function to:

* Look up the validation function by the name of the attribute, call that function,
* Set that same key in the `errors` object we are building to `false` if the validator returns true (indicating that there isn't an error for this attribute) or `true` if the validator returned false (indicating that there is an error for this attribute).

```javascript
errors[validator] = !attributeValidators[validator](astronaut)
```

Super clean and dynamic.

Returning to our middleware, we've produced an object, `errors`, that contains the keys of the attribute names and the values of `true` to indicate an invalid attribute or `false` to indicate no such error.

Now we need to implement some logic. If the `errors` object contains _any_ true values (i.e. if any of the attributes are invalid), we _should not_ allow our action to proceed to the next middleware––the API middleware. We should instead dispatch a new action that will tell the reducer to update the astronaut's errors in state.

```javascript
// client/src/middleware/formValidationMiddleware.js
...
if (!astronautIsValid(errors)) {
  dispatch(astronautValidationError(errors))
} else {
  next(action)
}
```

Here we use another helper function, `astronautIsValid`. If the astronaut is not valid, we will dispatch the `astronautValidtionError` action. Otherwise, we will call `next(action)` and let Redux proceed to pass our action to the API middleware.

Let's take a look at our helper function, `astronautIsValid`:

```javascript
// client/src/utils/astronautIsValid.js

export default function astronautIsValid(errors) {
  return !Object.values(errors).some(err => err)
}
```
It simply returns true if the `errors` object has no keys with a value of `true` (which indicates an invalid attribute) and `false` if the `errors` object contains any `true` values.

Back in our middleware, if the `errors` object does in fact contain `true` values, we dispatch the `astronautValidtionError` action with a payload of the `errors` object we built.

#### Updating State

The `astronautValidtionError` action looks like this:

```javascript
// client/src/actions/astronautActions.js
...
export function astronautValidationError(errors) {
  return {
    type: "ASTRONAUT_VALIDATION_ERROR",
    errors
  }
}
```

And is handled by the `astronautReducer` which uses the object contained in `action.errors` to update the astronaut in state with the appropriate errors:

```javascript
// client/client/src/reducers/astronautReducer.js
...
case "ASTRONAUT_VALIDATION_ERROR":
  return {
    ...state,
    errors: {
    ...state.errors,
    ...action.errors
  }
}
```

Lastly, we'll update each component to display an error message if the given attribute has an error.

Let's look at the `AstronautEmail` component as an example.

Notice that the container component, `AstronautForm` now passes in the `this.props.astronaut.errors.email` as a prop.

```jsx
// client/client/client/src/components/AstronautForm.js
...
render() {
  const { email, errors } = this.props.astronaut;
  ...
  <AstronautEmail
    email={email}
    emailError={errors.email}
    onAttributeUpdate={this.updateAstronautAttributes} />
  ...
}
```

And our `AstronautEmail` component implements some display logic based on the presence of `emailError` in props:

```jsx
// client/client/src/components/form/AstronautEmail.js
...
render() {
  ...
  {emailError &&
    <div>please provide a valid SpaceEx email.</div>
  }
}
```

We've successfully validated our form after the user clicked submit, taught Redux to manage errors in application state, _prevented_ the web request from being sent to the API when the astronaut is not valid, and displayed errors in our components––all without adding complicated view logic or state management to our components! Good job us.

#### Validate on State Change

Now that we've looked at the scenario in which we want to preform validations when we submit the form, let's discuss our last validation use-case. Some validations should occur as the user edits the form––updating the component to display certain errors as soon as the user finishes editing a particular form field.

Our email and "which planets have you terraformed?" fields are good examples of this desired behavior. As soon as a user focuses off of one of these form fields, we should display or remove the appropriate errors. In the case of email, we should show them an error message if they provided a non "@space.ex" email. In the case of terraformed planets, we should show them an error if (1) they clicked "terraforming experience" but left this field blank, or (2) they included "Mars" in their list of planets.

We can see this behavior below:

<iframe width="640" height="360" client/src="https://www.youtube.com/embed/DrXLJI30IPo?rel=0&amp;showinfo=0" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen></iframe>

So, how do we hook into the point in time when we're blurring away from a form field and updating the astronaut's attributes in Redux's state? We already have an action that gets dispatched `onBlur` of each form field: `updateAstronautAttributes`. This action sends the new attributes to the reducer where the astronaut is updated in state.

Let's write custom middleware to intercept this action, validate the astronaut against its new attributes, and add errors to the action for the reducer to include in any state changes.

We'll define our middleware and add it to the middleware stack:

[`client/src/middleware/validateAttributeUpdateMiddleware.js`:](https://github.com/SophieDeBenedetto/spacex-apply/blob/master/client/src/middleware/validateAttributeUpdateMiddleware.js)
```javascript
const validateAttributeUpdateMiddleware = ({ dispatch, getState}) => next => action => {
  // validations coming soon!
};

export default validateAttributeUpdateMiddleware;
```

```javascript
// client/src/store/configureStore.js

import {
  createStore,
  applyMiddleware } from 'redux'
import rootReducer  from '../reducers'
import initialState from './initialState';
import apiMiddleware from '../middleware/apiMiddleware';
import formValidationMiddleware from '../middleware/formValidationMiddleware';
import validateAttributeUpdateMiddleware from '../middleware/ValidateAttributeUpdateMiddleware';

export default function configureStore() {
  return createStore(
    rootReducer,
    initialState,
    applyMiddleware(
      formValidationMiddleware,
      validateAttributeUpdateMiddleware,
      apiMiddleware
    )
  )
}
```

Now we're ready to code our validations!

[`client/src/middleware/validateAttributeUpdateMiddleware.js`:](https://github.com/SophieDeBenedetto/spacex-apply/blob/master/client/src/middleware/validateAttributeUpdateMiddleware.js)
```javascript
import astronautAttribueIsValid from '../utils/astronautAttributeIsValid'

const ValidateAttributeUpdateMiddleware = ({ dispatch, getState}) => next => action => {
  if (action.type !== "UPDATE_ASTRONAUT_ATTRIBUTES") {
    return next(action)
  }
  const { newAttributes } = action;
  const { astronaut }     = getState();
  let updatedAstronaut    = {...astronaut, ...newAttributes}
  const attrName          = Object.keys(newAttributes)[0]
  action.errors = {
    [attrName]: !astronautAttribueIsValid(updatedAstronaut, attrName)
  }
  next(action)
};

export default ValidateAttributeUpdateMiddleware;
```

Let's break this down:

First, we grab our hash of new attributes from the action:

```javascript
const { newAttributes } = action;
```

Then, we build a copy of the astronaut object that is currently in state, with the new attributes:

```javascript
const { astronaut }     = getState();
let updatedAstronaut    = {...astronaut, ...newAttributes}
```

Next up, we need to grab the name of the attribute we are currently updating, so that we know which validation helper function to call:

```javascript
const attrName = Object.keys(newAttributes)[0]
```

Lastly, we dynamically populate `action.errors` with a key of the name of the attribute we are updating/validating and a `true/false` value. We populate this value with the help of another helper function, `astronautAttribueIsValid`. Let's take a look at that function now:

[`client/src/utils/astronautAttribueIsValid.js`:](https://github.com/SophieDeBenedetto/spacex-apply/blob/master/client/src/utils/astronautAttribueIsValid.js)
```javascript
import { attributeValidators } from './attributeValidators';

export default function astronautAttributeIsValid(astronaut, attribute) {
  if (attributeValidators[attribute]) {
    return attributeValidators[attribute](astronaut);
  } else {
    return true;
  }
}
```

This function takes in arguments of the astronaut object we are validating and the name of the attribute to validate.

Once again we utilize our `attributeValidators` object and the helper functions it stores. We look up the validation function by its attribute name, if it exists, we call the function with an argument of our astronaut. This will return `true` for a valid attribute and `false` for an invalid one.

If our attempts to lookup a validation function in the `attributeValidators` object returns `undefined`, then this is an attribute that we _don't_ have a validator for. It doesn't need to be validated and we should just return `true` to indicate that the attribute is valid (by virtue of not requiring validation, it _can't_ be invalid).

So, in the case in which the astronaut's `newAttributes` look like this:

```javascript
{email: "sophie@gmail.com"}
```
We set `action.errors` to:

```javascript
{
  email: true
}
```
Thereby indicating that the `email` attribute is invalid.

#### Updating State

Once we've built our errors object and attached it to `action`, we return `next(action)`. This will send our action to the reducer in the following state:

```javascript
{
  type: "UPDATE_ASTRONAUT_ATTRIBUTES",
  newAttributes: {email: "sophie@email.com"},
  errors: {email: true}
}
```

Lastly, we'll teach our `astronautReducer` to handle this action correctly by updating not just the astronaut's top-level attributes, but also by updating the astronaut's errors.

```javascript
// client/src/reducers/astronautReducer.js

...
case "UPDATE_ASTRONAUT_ATTRIBUTES":
  return {
    ...state,
    ...action.newAttributes,
    errors: {
      ...state.errors,
      ...action.errors
    }
  }
...
```
This will cause the components to re-render with the appropriately updated `astronaut` mapped into `props` from state. Our components already contain logic to display any errors found in `astronaut.errors` so our app should just work!

### Conclusion

The code shared here represents just a handful of (contrived and simplified) example use-cases for custom validation middleware. The main take away here is _not_ the particular validation functions for our fictitious astronaut form, but rather the manner in which we leveraged Redux to handle these validations. We avoided creating a bloated container component that was responsible for validations and making decisions about which actions to dispatch under which circumstances. Instead, we let Redux's centralized state management system maintain error states and hooked into the dispatch of different actions to perform custom and complex validations. We kept our components clean, and we let Redux do what it does best.