Quickstart

A quick dive into getting started with Lore

Step 3: Parse the Model

In this step we’ll continue restoring the functionality to the application.

You can view the finished code for this step by checking out the server.3 branch of the completed project.

Why is the application still broken?

The error we're seeing now looks like this:

Invalid call to `getState('user.byId')`. Missing required attribute 'id'.

This error stems from another parsing problem. In our original mock API, the response for a single tweet looked like this:

{
  id: 1,
  userId: 1,
  text: "Ayla fight while alive! Win and live. Lose and die.",
  createdAt: "2018-04-24T04:03:25.546Z"
}

But in our current API, the response looks like this:

{
  id: 1,
  user: 1,
  text: "Ayla fight while alive! Win and live. Lose and die.",
  createdAt: "2018-04-24T04:03:25.546Z"
}

The difference is that our userId property has been renamed to user, and this is generating an error in the connect call of our Tweet component, show below:

// src/components/Tweet.js
connect(function(getState, props) {
  const { tweet } = props;

  return {
    user: getState('user.byId', {
      id: tweet.data.userId
    })
  };
})

Since userId doesn't exist in the new API response, this code is passing undefined as the value of the id.

Parse the Model Response

To fix this, we could simply replace userId with user in the code above, and that would certainly be the better long-term solution. But since this Quickstart is intended to showcase key features in Lore, we're going to use an alternative approach, and instead add the missing userId field to all tweets.

Models and Collections in Lore both have a parse() method. The parse() method on Models is responsible for parsing a single resource and producing the final set of attributes that will be used by the components in your application. We're going to use this method to add the missing field.

Open src/models/tweet.js and look for the commented out parse() method that looks like this:

// src/models/tweet.js
export default {
  ...
  properties: {
    // parse: function(response, options) {
    //  return response;
    // }
  }
  ...
}

Modify that method to look like this:

// src/models/tweet.js
export default {
  ...
  properties: {
    parse: function(response, options) {
      response.userId = response.user;
      return response;
    }
  }
  ...
}

Now whenever a tweet resource comes back from the server, this method will copy the user attribute to userId, making both available.

While config/connections.js does contain a parse method for models, that method will affect all models in the application, which isn't what we want, since this issue only affects the tweet models.

It's also worth mentioning that this approach of overriding parse() to resolve breaking API changes is only suitable for consuming data, since you're effectively transforming the server response.

If you edit that data, and want to save your changes, then you'll need to transform it back to the format the server expects before sending it. In that case, you should use the sync() method, which you can learn more about here.

If you refresh the browser, you'll notice the Feed displays correctly again, but our profile picture isn't being displayed. This is because the application doesn't actually know who the user is. If you open the network tab in the browser developer tools, you'll see that the call to /user returns a 401 Unauthorized.

We'll fix that issue in the next step.

Visual Check-in

If everything went well, your application should look like this.

Code Changes

Below is a list of files modified during this step.

src/models/tweet.js

export default {

  properties: {

    parse: function(response, options) {
      response.userId = response.user;
      return response;
    }

  }

};
export default {

  properties: {

    parse: function(response, options) {
      response.userId = response.user;
      return response;
    }

  }

}
export default {

  properties: {

    parse: function(response, options) {
      response.userId = response.user;
      return response;
    }

  }

}

Next Steps

Next we're going to add an experience to show when the user is unauthorized.