Skip to content

API layer for Applications, Comments and Reasons for Decisions

License

Notifications You must be signed in to change notification settings

jeznorth/nrts-prc-api

 
 

Repository files navigation

ACRFD API (master)

Minimal API for the ACRFD Public and Admin apps

How to run this

Start the server by running npm start

Check the swagger-ui on http://localhost:3000/api/docs/

  1. POST http://localhost:3000/api/login/token with the following body { "username": #{username}, "password": #{password} }

and take the token that you get in the response

  1. GET http://localhost:3000/api/application again with the following header Authorization: Bearer _TOKEN_, replacing _TOKEN_ with the value you got from that request

Initial Setup

  1. Start server and create database by running npm start in root

  2. Add Admin user to users collection

    db.users.insert({ "username": #{username}, "password": #{password}, roles: [['sysadmin'],['public']] })

  3. Seed local database as described in seed README

Testing

This project is using jest as a testing framework. You can run tests with yarn test or jest. Running either command with the --watch flag will re-run the tests every time a file is changed.

To run the tests in one file, simply pass the path of the file name e.g. jest api/test/search.test.js --watch. To run only one test in that file, chain the .only command e.g. test.only("Search returns results", () => {}).

The MOST IMPORTANT thing to know about this project's test environment is the router setup. At the time of writing this, it wasn't possible to get swagger-tools router working in the test environment. As a result, all tests COMPLETELY bypass the real life swagger-tools router. Instead, a middleware router called supertest is used to map routes to controller actions. In each controller test, you will need to add code like the following:

const test_helper = require('./test_helper');
const app = test_helper.app;
const featureController = require('../controllers/feature.js');
const fieldNames = ['tags', 'properties', 'applicationID'];

app.get('/api/feature/:id', function(req, res) {
  let params = test_helper.buildParams({'featureId': req.params.id});
  let paramsWithFeatureId = test_helper.createPublicSwaggerParams(fieldNames, params);
  return featureController.protectedGet(paramsWithFeatureId, res);
});

test("GET /api/feature/:id  returns 200", done => {
  request(app)
    .get('/api/feature/AAABBB')
    .expect(200)
    .then(done)
});

This code will stand in for the swagger-tools router, and help build the objects that swagger-tools magically generates when HTTP calls go through it's router. The above code will send an object like below to the api/controllers/feature.js controller protectedGet function as the first parameter (typically called args).

{
  swagger: {
    params: {
      auth_payload: {
        scopes: ['sysadmin', 'public'],
        userID: null
      }, 
      fields: {
        value: ['tags', 'properties', 'applicationID']
      }, 
      featureId: {
        value: 'AAABBB'
      }
    }
  }
}

Unfortunately, this results in a lot of boilerplate code in each of the controller tests. There are some helpers to reduce the amount you need to write, but you will still need to check the parameter field names sent by your middleware router match what the controller(and swagger router) expect. However, this method results in pretty effective integration tests as they exercise the controller code and save objects in the database.

Test Database

The tests run on an in-memory MongoDB server, using the mongodb-memory-server package. The setup can be viewed at test_helper.js, and additional config in [config/mongoose_options.js]. It is currently configured to wipe out the database after each test run to prevent database pollution.

Factory-Girl is used to easily create models(persisted to db) for testing purposes.

Mocking http requests

External http calls (such as GETs to BCGW) are mocked with a tool called nock. Currently sample JSON responses are stored in the test/fixtures directory. This allows you to intercept a call to an external service such as bcgw, and respond with your own sample data.

  const bcgwDomain = 'https://openmaps.gov.bc.ca';
  const searchPath = '/geo/pub/FOOO';
  const crownlandsResponse = require('./fixtures/crownlands_response.json');
  var bcgw = nock(bcgwDomain);
  let dispositionId = 666666;

  beforeEach(() => {
    bcgw.get(searchPath + urlEncodedDispositionId)
      .reply(200, crownlandsResponse);
  });

  test('returns the features data from bcgw', done => {
    request(app).get('/api/public/search/bcgw/dispositionTransactionId/' + dispositionId)
      .expect(200)
      .then(response => {
        let firstFeature = response.body.features[0];
        expect(firstFeature).toHaveProperty('properties');
        expect(firstFeature.properties).toHaveProperty('DISPOSITION_TRANSACTION_SID');
        done();
      });
  });

About

API layer for Applications, Comments and Reasons for Decisions

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages

  • JavaScript 100.0%