What are Ember Data Snapshots?

Last reviewed on February 27, 2016

If you've had to work with Ember Data and non-standard APIs, you may have dug into the adapters and serializers a bit and seen snapshot as a parameter to a few of the methods. If you dug a little deeper, you may have learned that a snapshot is an instance of DS.Snapshot, a private class in Ember Data. If you visit the API docs for this class, it doesn't really tell you what it is. It just tells you what methods and properties are available on snapshots. So what is a snapshot and why do you care?

In a great video on Ember Data by Ember Data Core Team member @ChristofferP, Christoffer defines a snapshot as something that:

"Represents a record that you can inspect without causing side-effects."

He goes on to explain that snapshots were introduced to the library because there were issues when trying to inspect asynchronous model relationships during serialization that might trigger fetches which required dealing with promises making things complicated. Check out the video at 37:42 as he does a great job at explaining it.

So anyways, why might you need to use a snapshot? You probably won't have to instantiate a snapshot yourself as it is a private class, but you may run into situations where you'll need to know how to use it if you're dealing with a custom API. The API of a snapshot is the following:

// Get the ID of the record
snapshot.id;

// Get an attribute of the record
snapshot.attr('name');

// Get a hasMany relationship for the record
// Returns another snapshot
snapshot.hasMany('toys');

// Get a belongsTo relationship for the record
// Returns another snapshot
snapshot.belongsTo('user');

// Get the original record
snapshot.record;

With snapshot.belongsTo() and snapshot.hasMany(), you can access relationships synchronously regardless if those relationships were declared on your model as asynchronous or synchronous. That data will be returned in another snapshot if it has been loaded into the store. null will be returned if the relationship is known but data for that relationship wasn't loaded into the store. And lastly, undefined will be returned if the relationship is unknown.

Let's look at a practical example.

Handling Nested Resource Paths

One situation you might need to use a snapshot is in the adapter when determining a URL before a request is made. For example, what if you want to create a pet record, and the endpoint for creation has a nested resource path like /api/users/:id/pets instead of the default api/pets? In the adapter, we can use the snapshot to compute this URL in urlForCreateRecord().

app/adapters/pet.js
export default ApplicationAdapter.extend({
  urlForCreateRecord(modelName, snapshot) {
    let userID = snapshot.belongsTo('user').id;
    return `/${this.namespace}/users/${userID}/pets`;
  },
});

Here we are grabbing the belongsTo user relationship which gives us another snapshot for the user, and accessing the ID. This same technique can be used for computing the URL for other operations like deleting and updating records.

If you need to access a model's computed property in the adapter, you can use:

snapshot.record.get('someComputedProperty');

If you'd like to work with nested resources for data retrieval, read more about it in my other blog post Handling Nested Resources in Ember Data.

Serializing Data Sent to the Persistence Layer

Another reason you might have to use a snapshot is when serializing data sent to your API when saving it, if your API doesn't follow the conventions expected by the serializer you are using. The serialize() method can be overridden to control the outgoing data format and its argument is a snapshot.

app/serializers/pet.js
export default DS.JSONSerializer.extend({
  serialize(snapshot) {
    // send the new pet data as an array instead of an object
    // with the first item containing the new pet data
    return [
      {
        name: snapshot.attr('name'),
        age: snapshot.attr('age'),
        user_id: snapshot.belongsTo('user').id,
      },
    ];
  },
});

In this example, maybe the backend requires that the payload is an array where the first object contains the newly created data. This format isn't really common in APIs, but it is a situation I have run into. You can customize the format to whatever you need in this method.

Conclusion

Snapshots represent records that you can inspect without causing side effects. This means you can access attributes and relationships off of a record in a synchronous manner without having to deal with promises or causing side effects like triggering Ember Data to request that related data.


Pro Ember Data cover
Pro Ember Data available now!

Are you struggling with Ember Data?

In my new book Pro Ember Data, you will learn how to work with Ember Data efficiently, from APIs, adapters, and serializers to polymorphic relationships, using your existing JavaScript and Ember knowledge. This book will teach you how to adapt Ember Data to fit your custom API.

What You'll Learn

  • Review the differences between normalization and serialization
  • Understand how the built-in adapters and serializers in Ember Data
  • Understand how the built-in adapters and serializers in Ember Data work
  • Customize adapters and serializers to consume any API and write them from scratch
  • Handle API errors in Ember Data
  • Work with the Reddit API using Ember Data
  • Learn how to use polymorphic relationships
Check out Pro Ember Data on Amazon using my affiliate link
You can also find Pro Ember Data on Apress.

I've been enjoying @iamdtang's Pro Ember Data book. It's to the point and has lots of great examples. My favorite part was about error handling. This book is perfect after you've exhausted the official guides.

Ilya Radchenko

Product Developer at Applied Geographics

Ilya Radchenko

Pro Ember Data is such an approachable book @iamdtang! Good job. Loving the book so far! Thank you!

Lenora Porter

Software Engineer at Heroku

Lenora Porter

Great to see all those topics in which I struggled when I started working on Ember. Nice job, will check it out :)

AbulAsar S

Fullstack Developer

AbulAsar S

I haven't read David's new book, but his previous Ember Data book helped me a lot when I was starting out with Ember, so I am sure this book is a must if you're working with Ember Data!

Kenneth Larsen

Ember Learning Core Team member

Kenneth Larsen

I bought Ember Data in the Wild back in 2016 and found it really helpful. Looking forward to reading this.

@EmberLinks

Ember related news by Chris Masters

@EmberLinks