Ember Server Side Form validation with Mirage

In this Ember.js example, I’ll show how to get ember-cli-mirage to return correct JSON-API response, so that Ember Data correctly processes Error message and makes it accessible inside the template.

This code was tested on Ember 2.6.0.

We have the following registration model:

import Model from 'ember-data/model';
import attr from 'ember-data/attr';

export default Model.extend({
  firstname: attr('string'),
  lastname: attr('string'),
});

There are three main elements that make this work: Controller that saves the data, Template that renders form and errors, and Mirage that mocks the response.

Controller’s save action is very basic, it calls save on the model and catches any errors:

import Ember from 'ember';

export default Ember.Controller.extend({
  actions: {
    save() {
      this.get('model').save().then((registration) => {
        // it's a mock, we don't do anything
      }).catch((adapterError) => {
        // we just need to catch error
      });
    }
  }
});

Template displays form and any connected errors:

<form>
  <p>
    <label>First name: {{input value=model.firstname}}</label>
    {{#each model.errors.firstname as |error|}}
      <span class="errors">{{error.message}}</span>
    {{/each}}
  </p>
  <p>
    <label>Last name:
      {{input value=model.lastname}}
    </label>
    {{#each model.errors.lastname as |error|}}
      <span class="errors">{{error.message}}</span>
    {{/each}}
  </p>
  <button {{action 'save'}}>Save</button>
</form>

Now we only need to setup Ember Mirage. We emulate two different states. If firstname is ‘John’, we let request come through, and in all other cases we display error.

import Response from 'ember-cli-mirage/response';

export default function() {

  this.namespace = '/api';

  this.post('registrations', function(schema, request) {
   let attrs = JSON.parse(request.requestBody).data.attributes;

   if ( attrs.firstname === 'John') {
     return {
       'id': 1,
       'firstname': 'John',
       'lastname': attrs.lastname
     }
   } else {
     return new Response(422, {}, {
        "errors": [
          {
            "source": { "pointer": "/data/attributes/firstname"},
            "detail": "Please enter John as name"
          }
        ]}
     );
   }
  });
}

In the above example, it’s important that we return error code 422 (Unprocessable Entity), otherwise it will not be processed by JSONAPIAdapter as error.

Example repository

To make easier to see a complete and working example, I’ve also published a repository with complete code:
https://github.com/ember-examples/server-side-validation-mirage