Documentation, Uncategorized

Multiple Environments with Loopback 4

When configuring multiple environments for a Loopback 4 Application, it can appear less straight forward than with Loopback 3, so here is a quick fix for how to get over this obstacle as elegantly as possible in 5 minutes.

  1. Import dotenv and create a .env file in the root of the app.
  2. Put your database configuration in this file.
  3. Empty the existing datasource file so it contains an empty JSON (file is required by compiler and the bootstrapping).
  4. Add the code below to the application.ts file in the src directory.
  5. Don’t forget to require the dotenv from the run command.
this.bind('datasources.default').to(new DefaultDataSource());
this.dataSource(new DefaultDataSource());
this.bind('datasources.config.default').to({
  name: 'default',
  connector: 'mongodb',
  hostname: process.env.DB_DEFAULT_HOSTNAME,
  port: process.env.DB_DEFAULT_PORT,
  user: process.env.DB_DEFAULT_USER,
  password: process.env.DB_DEFAULT_PASSWORD,
  database: process.env.DB_DEFAULT_DATABASE,
  useNewUrlParser: process.env.DB_DEFAULT_USENEWURLPARSER,
  authSource: process.env.DB_DEFAULT_AUTHSOURCE
});
this.bind('datasources.default').toClass(DefaultDataSource);

This is a quick fix intended to help move on if in a pickle, I will refine this further so the application will check the process.env.NODE_ENV variable instead and load the corresponding file.

For the original inspiration to this post, head over here: https://medium.com/p/8f085399268/responses/show

 

Documentation

QuickFix how to deploy a Loopback 4 Application to Heroku

When you are prototyping, sometimes you just need something to work, this was my case with a new experiment I’m working using Loopback 4 which I wanted to deploy for to Heroku for some rapid testing.

Generally CLI generated App’s doesn’t like environments like Heroku too much and since I later will deploy to DigitalOcean through some Docker containers, I just needed a QuickFix.

Anyways, let’s get to the point… this is a very opiniated post which takes for granted you are using the exact same development workflow that I have, if not, post a comment and I will do my best to help you out.

  1. Remove the /dist entry from .gitignore so it will be committed to Git, and subsequently caught by the CD routine running on Heroku through the GitHub Webhook.
  2. Remove the prestart script entry from package.json.
  3. Remove the “-r source-map-support/register” from the start script entry in package.json.

Now you are good to deploy it to Heroku via GitHub, however don’t forget to build before you commit.

 

Documentation

CORS with Loopback & Angular Apps

To get the two running nicely together in respect to CORS, don’t forget to disable the origin only default policy of Loopback by setting the origin in the CORS configuration to “*” in the middleware.json file.

{
  ...
  "initial": {
    "compression": {},
    "cors": {
      "params": {
        "origin": "*",
        "credentials": true,
        "maxAge": 86400
      }
    }
    ...
  }
}

 

undocumentation

Hacks to get Loopback App’s running on Heroku

To get Loopback App’s running on Heroku, a couple of hacks are required due to the way Loopback manages it’s configurations.

The first issue to solve is to get Loopback to take the port number from the environment since Heroku uses arbitrary port numbers to target different applications.

There is probably a more elegant way, however I first wanted to stay out of node_modules files, so I opted to just focus on modifying server.js.

It’s actually very easy, since loopback internally supports passing arguments to the listen function all the way out from the server.js file.
It does this by switching between automatic configuration and explicit configuration from the arguments passed to the listen function.

So, basically it’s just amending the “start” function to fetch the port number from the environment and pass it as argument to the listen function.

I have done it this way…

app.start = function () {
   // start the web server
   var port = process.env.PORT || 8000;
   return app.listen(port, function () {
      app.emit('started');
      console.log('Web server listening at: %s', app.get('url'));
  });
};
Uncategorized

Simple WhoAmI for Loopback

Retrieving the currently authenticated user in a Loopback Application can be done in many ways, and one of them is the one I want to share in this post.

I wanted to be able to utilise the Angular SDK as well as the Explorer, so adding a routing manually in a boot script was not really an option, however simple that might be, so I decided to opt for implementing it as a custom Model.

The first thing to do is to create a whoami.json and whoami.js file in the commons directory.

whoami.json

{
  "name": "WhoAmI",
  "base": "Model",
  "plural": "whoami",
  "acls": [
    {
      "accessType": "*",
      "principalType": "ROLE",
      "principalId": "$everyone",
      "permission": "DENY"
    },
    {
      "accessType": "*",
      "principalType": "ROLE",
      "principalId": "$authenticated",
      "permission": "ALLOW"
    }
  ]
}

whoami.js

module.exports = function (WhoAmI) {

    WhoAmI.whoAmI = function (req, next) {
        var AccessToken = WhoAmI.app.models.AccessToken;
        AccessToken.findForRequest(req, {}, function (aux, accesstoken) {
            var UserModel = WhoAmI.app.models.User;
            UserModel.findById(accesstoken.userId, function (error, user) {
                next(error, user);
            });
        });
    }

    WhoAmI.remoteMethod(
        'whoAmI',
        {
            accepts: {arg: 'req', type: 'object', http: {source: 'req'}},
            returns: {arg: 'user', type: 'object'},
            http: {path: '/', verb: 'get'}
        }
    );
};

Secondly, I make sure to add the model to the model-config.json

...
"WhoAmI": {
  "dataSource": null,
  "public": true
}
...

Now, when you restart the server, you will see the following endpoint having been added to your API

2015-03-01_23-05-18

And because of the ACL’s we set in the model, all requests without an access-token are handled by the security of Loopback… so there you go, a nice and easy WhoAmI !

Alternatively… a bootscript

If you for some reason should be inclined to prefer putting it in a boot script, all you have to do is to create a file in the boot directory of the server with the following content

module.exports = function (server) {

    var router = server.loopback.Router();

    router.get('/whoami', function (req, res) {

        var AccessToken = server.models.AccessToken;
        AccessToken.findForRequest(req, {}, function (aux, accesstoken) {
            if (accesstoken == undefined) {
                res.status(401);
                res.send({
                    'Error': 'Unauthorized',
                    'Message': 'You need to be authenticated to access this endpoint'
                });
            }
            else {
                var UserModel = server.models.User;
                UserModel.findById(accesstoken.userId, function (err, user) {
                    res.status(200);
                    res.send(user);
                });
            }
        });
    });

    server.use(router);
}

Gist: https://gist.github.com/pmoelgaard/af6aa61146766f0e8551