Issuing Requests

A dataModel is a representation of your model from the server. Footwork dataModels have features and capabilities aimed at the management of a record of your data on some sort of remote resource.

Request Types

Example DataModel Configured For Requests:

function Person (personData) {
  var self = fw.dataModel.boot(this, {
    url: '/person',
    idAttribute: 'id'
  });

  // note the self.id observable is mapped to the idAttribute
  self.id = fw.observable(personData.id).map('id', self);
  self.name = fw.observable(personData.name).map('name', self);
}

Requests return promises

The following sections outline how to use the API to issue requests related to the dataModel you are working with. Footwork utilizes ES6's fetch for AJAX internally. If you need to make a generic AJAX request you will want to use fetch, for more info on using fetch see ES6 Fetch.

It is also important to note that all of the methods used below return an ES6 Promise and so you can hook into them using standard methods such as .then(). For more information see: ES6 Promise.

Create A New Record

To create a record using a dataModel:

  • It must have a falsey value resolved for its mapped idAttribute (the falsey value tells Footwork the dataModel needs to be created, not updated).
  • It must have a valid url configured to create the record on (see: url configuration).
  • The data you want saved needs to be mapped (see mapping request data).

Using the example dataModel we instantiate a new instance and provide it a value for the id, which if you remember is mapped to the idAttribute. This value will be used to construct the url when we update the record on the server. We also provide a value for the name which is what we want saved:

var person = new Person({
  id: 1,
  name: 'Bruce Wayne'
});

Since the id observable is mapped to the idAttribute of our dataModel it will be used when we issue the request. Footwork follows a typical REST endpoint schema by appending the id of a model to the URL when update a record. So in this case the final request will be to POST /person/1.

To create the dataModel on the endpoint we call save on the instance:

var promise = person.save();

When save is called:

  1. The url is resolved
  2. The mapped idAttribute is resolved (and since it is falsey, a create request is generated)
  3. All of the mapped observable data is resolved and collected together in the structure the mappings define.
  4. A POST request is issued in the form of url/idAttribute and passed the data (this can be customized with an explicit url object configuration).

Request Options

  • If you need to pass options to the underlying ES6 fetch call you can do so by passing them into the dataModel.save call:

    person.save({ method: 'POST' });
    
  • By default when the request is returned its data is applied to your dataModel, you can disable this by passing writeResponse: false as an option:

    person.save({ writeResponse: false });
    

Read A Record

To read (or fetch) a record using a dataModel:

  • It must have a non-falsey value resolved for its mapped idAttribute (the non-falsey value tells Footwork where the record is located at and is used in url generation).
  • It must have a valid url configured to read the record from (see: url configuration).
  • The data you want fetched needs to be mapped (so Footwork knows where to write it after retrieving the request data, see mapping request data).

Using the example dataModel we instantiate a new instance and provide it a value for the id, which if you remember is mapped to the idAttribute. This value will be used to construct the url when we fetch the data from the server:

var person = new Person({ id: 1 });

Since the id observable is mapped to the idAttribute of our dataModel and we have a simple string configured for the url, it will be used when we dispatch the fetch request (see url configuration). Footwork follows a typical REST endpoint schema by appending the id of a model to the URL when fetching its data. So in this case the final request will be to GET /person/1.

To issue the request we call fetch on the dataModel instance:

var promise = person.fetch();

When fetch is called:

  1. The url is resolved
  2. The idAttribute is resolved
  3. A GET request is issued in the form of url/idAttribute (this can be customized with an explicit url object configuration).

In the above example this would generate a request to GET /person/1.

At this point Footwork waits for the request to finish. Your endpoint should return an object literal representing the data you want to be written to your dataModel. For example, given our person instance and the GET /person/1 request, our endpoint should return something like:

{
  id: 1,
  name: 'Bruce Wayne'
}

Once the request returns a response, Footwork then takes the mappings defined and uses that to translate and write the response object back to the person instance.

// ...after the request finishes:
person.name() === 'Bruce Wayne'

Now that the request has finished and the data has been written back to the mapped observables:

Request Options

If you need to pass options to the underlying fetch call you can do so by passing them into the dataModel.fetch call:

person.fetch({ method: 'POST' });

Update A Record

To update a record using a dataModel:

  • It must have a non-falsey value resolved for its mapped idAttribute (the non-falsey value tells Footwork the dataModel needs to be updated, not created).
  • It must have a valid url configured to update the record on (see: url configuration).
  • The data you want saved needs to be mapped (see mapping request data).

Using the example dataModel we instantiate a new instance and provide it a value for the id, which if you remember is mapped to the idAttribute. This value will be used to construct the url when we update the record on the server. We also provide a value for the name which is what we want saved:

var person = new Person({
  id: 1,
  name: 'Bruce Wayne'
});

Since the id observable is mapped to the idAttribute of our dataModel it will be used when we issue the request. Footwork follows a typical REST endpoint schema by appending the id of a model to the URL when update a record. So in this case the final request will be to PUT /person/1.

To update the dataModel on the endpoint we call save on the instance:

var promise = person.save();

When save is called:

  1. The url is resolved
  2. The mapped idAttribute is resolved (and since it is non-falsey, an update request is generated)
  3. All of the mapped observable data is resolved and collected together in the structure the mappings define.
  4. A PUT request is issued in the form of url/idAttribute and passed the data (this can be customized with an explicit url object configuration).

Request Options

  • If you need to pass options to the underlying fetch call you can do so by passing them into the dataModel.save call:

    person.save({ method: 'POST' });
    
  • By default when the request is returned its data is applied to your dataModel, you can disable this by passing writeResponse: false as an option:

    person.save({ writeResponse: false });
    

Delete A Record

To delete (or destroy) a record using a dataModel:

  • It must have a non-falsey value resolved for its mapped idAttribute (the non-falsey value tells Footwork where the record is located at and is used in url generation).
  • It must have a valid url configured to delete the record at (see: url configuration).

Using the example dataModel we instantiate a new instance and provide it a value for the id, which if you remember is mapped to the idAttribute. This value will be used to construct the url when we delete the record on the server:

var person = new Person({
  id: 1
});

Since the id observable is mapped to the idAttribute of our dataModel it will be used when we issue the request. Footwork follows a typical REST endpoint schema by appending the id of a model to the URL when update a record. So in this case the final request will be to DELETE /person/1.

To delete the dataModel on the endpoint we call destroy on the instance:

var promise = person.destroy();

When destroy is called:

  1. The url is resolved
  2. The mapped idAttribute is resolved (and since it is non-falsey, an update request is generated)
  3. A DELETE request is issued in the form of url/idAttribute (this can be customized with an explicit url object configuration).

Request Options

If you need to pass options to the underlying fetch call you can do so by passing them into the dataModel.destroy call:

person.destroy({ method: 'POST' });

Handling Errors

For all requests made, the ES6 Promise created will be passed back to the caller. You can use that to handle any errors that might occur:

var promise = myDataModel.fetch(); // example request
promise.then(function (response) {
  if (!response.ok) {
    console.log('Something went wrong with the request:', response.statusText);
  }
}).catch(function (error) {
  console.log('Something else went wrong:', error);
});

Overriding Request Options

A dataModel has 3 ways in which you can alter the options passed into the underlying fetch call when a request is made:

  • Individually with each request as shown in the above CRUD sections

  • As a configuration option

  • On a global fw.options.fetchOptions configuration

    You can supply the same fetch options object configuration or callback on fw.options.fetchOptions just as you would on a configuration option:

    fw.options.fetchOptions = fetchOptions: {
      credentials: 'same-origin'
    };
    

    By supplying your options here they will be used on all requests issued.

Override Priority

You can supply fetch options in 3 different ways, they are applied to your requests by mixing them together when the request is generated. This is done by extending one onto the other such that the options you supply are used in the following priority (higher ones override lower ones):

Altering the Storage Method

By default the storage engine utilizes a RESTful endpoint. All requests are dispatched through fw.dataModel.sync which is then proxied through fw.sync. You can override the default behavior by providing your own method at either of these two locations.

  • action

    The request action (create/read/update/delete).

  • dataModel

    Your dataModel instance

  • options

    Any passed in options