Thanks to Precision Nutrition for sponsoring some of Mirage’s recent work!

In the last few weeks there’s been two important releases of Ember CLI Mirage. Version 0.3.2 bought along auto-discovery of Ember Data models, and version 0.3.3 (which I released over the weekend) added support for Polymorphic associations.

Taken together, these two features greatly improve the ergonomics of the library.

Auto-discovery of Ember Data models

In 0.3.2, Offir Golan shipped the auto-discovery feature.

Models in Mirage are used by the ORM to set up collections and define relationships (associations). With this new feature, if you happen to be using Ember Data, Mirage will now auto-discover your Ember Data models (and their associations), and use those for its own schema.

This is quite a convenient step, because if you’re using Ember Data your Mirage models should match your Ember Data models anyway. Local files in mirage/models will “win” against auto-generated definitions, but once you delete your local files Mirage will fall back to Ember Data’s schema.

So, if you’re using Ember Data, upgrade to the latest version of Mirage, nuke your mirage/models folder, and you never have to worry about running ember g mirage-model again!

Polymorphic associations

Polymorphic associations were the last big missing piece of Mirage’s ORM. Now, Mirage can represent any schema that Ember Data can.

Reaching parity with Ember Data’s flexible data-modeling story makes the auto-discovery feature that much more valuable. Now, no matter how you’re using Ember Data, you should be able to rely on the autogenerated model classes.

If you aren’t using Ember Data, you can define has-many or belongs-to polymorphic associations on your own Mirage models:

// mirage/models/user.js
export default Model.extend({
  collectibles: hasMany({ polymorphic: true })
});

// mirage/models/car.js
export default Model.extend({
  user: belongsTo()
});

// mirage/models/watch.js
export default Model.extend({
  user: belongsTo()
});

schema.users.create({
  collectibles: [
    schema.cars.create({ make: "Infiniti", model: "J30t" }),
    schema.watches.create({ make: "Citizen", model: "Men's Chronograph" }),
  ]
});

Just like all other associations in Mirage’s ORM, they can be one-way (null inverse), one-to-one, one-to-many or many-to-many. Check out the docs on polymorphic associations for more details.

Upgrading

These past few releases are all backwards-compatible with the 0.3.x series. If you’re still on 0.2.x, be sure to check out the upgrade guide so you can get on the 0.3 series.

Roadmap

Now that the majority of the work on the ORM is complete, there’s a few things I’ll be focusing on:

  • Real network requests. There’s a PR that needs a bit of attention, but soon Mirage will have an option to boot in Ember CLI’s Express server and send real HTTP responses back to your Ember app. This will enable several things:

    1. You’ll be able to use the network inspector to view your responses
    2. Mirage’s database state will persist across page refreshes of your application, and
    3. You’ll be able to test out features that depend on a real server, like verifying polling updates across two browser tabs

    Mirage will always be a tool focused on improving the development experience. Even though it will be able to run as a true node server, it will never make compromises to the developer experience in order to accommodate the needs of an actual production server.

  • Landing a version 1.0. I’m happy with Mirage’s API and I’d like to land a version 1.0 soon. The only possible breaking change I’m considering at the moment has to do with the database API.

    Before the ORM you would interact with Mirage’s db directly, doing things like db.users to fetch users and db.users.insert to insert new records.

    When designing this API I wanted db.users to return a JavaScript array but I also wanted insert, update and destroy to live off of this collection, e.g. db.users.insert(), db.users.update() and db.users.destroy().

    Having db.users return the underlying database records made it way too easy to inadvertently mutate the database, so I made an early decision to have db.users return a copy of the records using JSON.stringify. This is quite costly in terms of performance and some users have hit limits when trying to seed their dummy data.

    Now that the primary interface to the database is schema (Mirage’s ORM), the database’s API isn’t as important, and we could change db.users to db.users.all(). That way the other db methods (db.insert, db.update and db.delete) wouldn’t incur the expensive cost of copying the database each time they ran.

    Other than that, I think we can lock down the API, ship 1.0 and move forward with prioritizing other features that are on the horizon.

How you can help

Test your apps on 0.3.3 and report any issues that you run into, especially if your app has complex Ember Data schemas.

And as always, if you’d like to contribute code or documentation to Mirage, jump on the #ec-mirage Slack channel and reach out. There’s always more work to be done! :)