11

I would like to know if there is a way to returns a specific HTTP status code from within a remote method.

I can see that there is a callback function which we can pass an error object, but how do we define the HTTP status code?

JBCP
  • 13,109
  • 9
  • 73
  • 111
ppoliani
  • 4,792
  • 3
  • 34
  • 62

7 Answers7

25

If you wish to use an HTTP status code to notify of an error, you can pass an error in the remote methods callback method:

var error = new Error("New password and confirmation do not match");
error.status = 400;
return cb(error);

You can find more information about the error object here: Error object

If you wish to just alter the HTTP response status without using an error, you can use one of the two methods defined by either #danielrvt or #superkhau. To obtain the reference to the request object mentioned by #superkhau, in your method registration you can define an additional argument that will be passed to your remote method. See HTTP mapping of input arguments

Juan Acosta
  • 303
  • 4
  • 7
  • 2
    Doesn't this return an entire stack trace though? If you wanted to return `{ status: 404, message: 'Not found'}` is there a better approach? – user3162553 Oct 12 '16 at 22:44
4

Lets assume that you have a CoffeShop Model and you want to send status 404 if the item is not in your db.

CoffeeShop.getName = function(req, res, cb) {
    var shopId = req.query.id;
    CoffeeShop.findById(shopId, function(err, instance) {
      if (instance && instance.name){
        var response = instance.name;
        cb(null, response);
      }
      else {
        res.status(404);
        cb(null);
      }
    });
  }

CoffeeShop.remoteMethod(
    'getName',
    {
      http: { path: '/getname', verb: 'get' },
      accepts: [{arg: 'req', type: 'object', http: { source: 'req' }},
                { arg: 'res', type: 'object', http: { source: 'res' }}],
      returns: { arg: 'name', type: 'string' }
    }
  );
Henok Tesfaye
  • 8,287
  • 13
  • 47
  • 84
4

When using an async remote method function, you need to let the async function throw any encountered errors, rather than trying to catch them and call return. By calling return you're telling LoopBack that it should respond as if it were successful.

Here's an example working structure.

AdminDashboard.login = async(body) => {
  let username = body.username
  let password = body.password
  await isDomainAdmin(username, password)
}
AdminDashboard.remoteMethod(
  'login',
  {
    http: {path: '/login', verb: 'put'},
    consumes: ['application/json'],
    produces: ['application/json'],
    accepts: [
      {arg: 'body', type: 'Credentials', http: {source: 'body'}}
    ]
  }
)

Just make sure that any internal functions you call like isDomainAdmin are also either throwing their errors directly, or that you catch them and convert them to an error object like this:

{
  statusCode: 401,
  message: 'Unauthorized'
}

Where err.statusCode is the HTTP status code you want LoopBack to return.

ivandov
  • 619
  • 8
  • 14
3

You can return any status code just like you would in ExpressJS.

...
res.status(400).send('Bad Request');
...

See http://expressjs.com/api.html

superkhau
  • 2,781
  • 18
  • 9
  • 2
    I understand that; but how do you get an instance of express response? – ppoliani Dec 22 '14 at 20:49
  • Depends what part of the lifecycle you're in. In some places, you have access to ctx, in which case you can do `ctx.req`. There are also major discussions around getCurrentContext: https://github.com/strongloop/loopback/issues/1676. – superkhau Sep 26 '16 at 02:07
  • 3
    Why is it downvoted? It works and it's not deprecated api, http://expressjs.com/en/api.html#res.status – Pratik Jul 11 '17 at 06:23
  • 1
    How to get a reference of res ? – Henok Tesfaye Sep 27 '18 at 15:02
2

In your remote method registration:

YourModel.remoteMethod('yourMethod', {
    accepts: [
      {arg: 'res', type: 'object', http:{source: 'res'}}
    ],
    ...
    returns: {root: true, type: 'string'},
    http: {path: '/:id/data', verb: 'get'}
  });
danielrvt
  • 10,177
  • 20
  • 80
  • 121
1

If you just need to modify response status, just do:

ctx.res.status(400);
return cb(null);
soyacz
  • 437
  • 2
  • 11
0

In Loopback 4 there is an HttpErrors class for this. Here are just a few:

// Throw a 400 error
throw new HttpErrors.BadRequest("Invalid request");

// Throw a 403 error
throw new HttpErrors.Forbidden("You don't have permission to do this");

// Throw a 404 error
throw new HttpErrors.NotFound("The data was not found")

You can also inject the Response object in the controller's constructor and explicitly call it:

// As a constructor argument
@inject(RestBindings.Http.RESPONSE) private res: Response

// In your method
this.res.status(400).send("Invalid request");
Dan Sterrett
  • 1,160
  • 11
  • 12