Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do you substitute HttpClient in Aurelia?

I'm brand new to Aurelia.

How would you change the following code to provide a dummy HttpClient, e.g. a json reader instead that would provide just a static set of json data, negating the need for a server in development.

import {inject} from 'aurelia-framework';
import {HttpClient} from 'aurelia-fetch-client';

@inject(HttpClient)
export class Users {
  heading = 'Github Users';
  users = [];

  constructor(http) {
    http.configure(config => {
      config
        .useStandardConfiguration()
        .withBaseUrl('https://api.github.com/');
    });

    this.http = http;
  }

  activate() {
    return this.http.fetch('users')
      .then(response => response.json())
      .then(users => this.users = users);
  }
}
like image 858
JMac Avatar asked Feb 01 '16 21:02

JMac


2 Answers

There's a couple steps required to get the demo code in your original post to a state where we can substitute HttpClient implementations.

Step 1

Remove the configuration code in the class's constructor...

These lines:

users.js

...
http.configure(config => {
  config
    .useStandardConfiguration()
    .withBaseUrl('https://api.github.com/');
});
...

Should move to the main.js file:

main.js

export function configure(aurelia) {
  aurelia.use
    .standardConfiguration()
    .developmentLogging();

  configureContainer(aurelia.container);  // <--------

  aurelia.start().then(a => a.setRoot());
}

function configureContainer(container) {
  let http = new HttpClient();
  http.configure(config => {
    config
      .useStandardConfiguration()
      .withBaseUrl('https://api.github.com/');
  });
  container.registerInstance(HttpClient, http); // <---- this line ensures everyone that `@inject`s a `HttpClient` instance will get the instance we configured above.
}

Now our users.js file should look like this:

users.js

import {inject} from 'aurelia-framework';
import {HttpClient} from 'aurelia-fetch-client';

@inject(HttpClient)
export class Users {
  heading = 'Github Users';
  users = [];

  constructor(http) {
    this.http = http;
  }

  activate() {
    return this.http.fetch('users')
      .then(response => response.json())
      .then(users => this.users = users);
  }
}

Step 2:

Mock the HttpClient.

The user.js module only uses the fetch method which returns a Response object that has a json method. Here's a simple mock:

let mockUsers = [...todo: create mock user data...];

let httpMock = {
  fetch: url => Promise.resolve({
    json: () => mockUsers
  })
};

Step 3:

Reconfigure the container to use the http mock:

In step 1 we added a configureContainer function to the main.js module that registered a configured HttpClient instance in the container. If we wanted to use our mock version the configureContainer function would change to this:

main.js

...

let mockUsers = [...todo: create mock user data...];

let httpMock = {
  fetch: url => Promise.resolve({
    json: () => mockUsers
  })
};

function configureContainer(container) {      
  container.registerInstance(HttpClient, httpMock);
}

More info on configuring the container here: https://github.com/aurelia/dependency-injection/issues/73

like image 51
Jeremy Danyow Avatar answered Nov 10 '22 09:11

Jeremy Danyow


There is another possibility to provide static data for the application during development. Navigation Skeleton already comes with Gulp and BrowserSync, so we used those to fake API calls.

Let's say you load JSON data from /api virtual directory, so e.g.

GET /api/products

In this case your just need two things to fake it.

Put your mock data into files

Go to the root folder of your Aurelia app and create an /api folder.

Create a /api/products subfolder and put a new file called GET.json. This file should contain the JSON, e.g.

GET.json

[ { "id": 1, "name": "Keyboard", "price": "60$" },
  { "id": 2, "name": "Mouse", "price": "20$" },
  { "id": 3, "name": "Headphones", "price": "80$" }
]

Configure BrowserSync to mock your API calls

Navigate to /build/tasks folder and edit the serve.js file. Change the definition of serve task to the following code:

gulp.task('serve', ['build'], function(done) {
  browserSync({
    online: false,
    open: false,
    port: 9000,
    server: {
      baseDir: ['.'],
      middleware: function(req, res, next) {
        res.setHeader('Access-Control-Allow-Origin', '*');

        // Mock API calls
        if (req.url.indexOf('/api/') > -1) {
          console.log('[serve] responding ' + req.method + ' ' + req.originalUrl);

          var jsonResponseUri = req._parsedUrl.pathname + '/' + req.method + '.json';

          // Require file for logging purpose, if not found require will 
          // throw an exception and middleware will cancel the retrieve action
          var jsonResponse = require('../..' + jsonResponseUri);

          // Replace the original call with retrieving json file as reply
          req.url = jsonResponseUri;
          req.method = 'GET';
        }

        next();
      }
    }
  }, done);
});

Now, when your run gulp serve, BrowserSync will be handling your API calls and serving them from the static files on disk.

You can see an example in my github repo and more description in my Mocking API calls in Aurelia.

like image 30
Mikhail Shilkov Avatar answered Nov 10 '22 07:11

Mikhail Shilkov