Loopback-next: Serverless support

Created on 3 May 2017  路  14Comments  路  Source: strongloop/loopback-next

I should be able to run my loopback.next apps in the following contexts:

  1. Inside an action within a serverless architecture (eg. whisk, lambda)
  2. As a gateway to a serverless backend
  3. An event provider
epic help wanted

Most helpful comment

@8secz-johndpope thanks for sharing your direction around swift. I just published an update to serverless-loopback including a loopback 4 example (using express).

@achrinza seems like the direction you all are taking is tackling this from a webpack perspective only.

Based on what I learned during my brief exploration of options, I think it would be really powerful to have loopback4 be an easy way for serverless to deploy different granularity of functions (I am not sure if this is already possible with the current loopback 4 capabilities).

Here is an example showing what I mean by "different granularity of functions":

functions:
  defaultController: # check [1] for a working example
    handler: dist/lambda-wrapper.handler
    events:
      - http: ANY /
      - http: 'ANY {proxy+}'
  controllerAbc: # mocked, still needs wrapper to work in serverless (e.g. AWS Lambda)
    handler: dist/controllers/abc.controller
    events:
      - http:
          path: /abc
          method: ANY
  ping: # mocked, still needs wrapper to work in serverless (e.g. AWS Lambda)
    handler: dist/controllers/ping.controller.PingController.ping
    events:
      - http:
          path: /ping
          method: get

[1] 'botbits/serverless-loopback#15'

Would love to hear any thoughts around feasibility of the above with current capabilities.

All 14 comments

There is a distinct lack of a good framework around "Serverless" options. Obviously, there is a desire to keep serverless functions lean in an attempt to speed up cold-start times.

It would be VERY interesting to utilize something like Webpack to create build folders to match your serverless architecture (lambda, whisk, google functions, etc...). Similar to what Google has been working on with the PRPL pattern for front-end architecture:
https://developers.google.com/web/fundamentals/performance/prpl-pattern/

@ritch can you please provide a good example where one would want to run a loopback.next app in a handler or action within a serverless arch? I'm trying to understand in order to come up with good examples.

@onel0p3z here is a good documentation that deeply explains the serverless architecture with good examples

https://martinfowler.com/articles/serverless.html#ACoupleOfExamples

@jonathan-casarrubias thanks for your response and the resource! Maybe I can rephrase the question to make it more clear. I am familiar with the serverless arch and have used diff providers. My question was targeted more to understand where can loopback.next play a role in the handler of a lambda function for instance. as a router for other actions? CQRS? Hope i explained myself better 馃憤

@onel0p3z thanks for clarifying now it is more clear, though I guess we will need to wait for the official answer for that question since I'm unaware of the plans for this implementation.

I apologize for the confusion.

Cheers
Jon

@jonathan-casarrubias thanks and no need to apologize 馃憤 馃槃 ideally, with a clear use case, I'd like to come up with examples of it for different providers (aws, azure, gcloud, etc.)

@onel0p3z I see a use of leveraging loopback in a light form for serverless functions. Obviously a function is typically tied to one event.

Even within a Lambda, Google Function, etc... there are common needs. Authentication, Access Management, Data connections, external API calls, common middleware, etc... A lot of stuff that frameworks like Loopback provide currently.

But, yeah, ideally in these new functional services you want to keep your code light for cold-starts. Still, I find that my package.json list grows and I'm slowly building up blueprints for my functions that are looking more and more like "loopback light" (sort of).

Use case:
Single codebase for multiple functional deployments providing unified model references, unified data connectors, unified settings, etc... So if I have a lambda listening to an event and I update a database and fire off an API call, I'm using the same shared codebase that another lambda using to handle database updates (which, in this case is triggered by the first lambda). We both have a common mapping of that database's structure due to the common loopback models.

I am closing this issue because we are not going to have time to work on this in the next 6-9 months. However, we are happy to accept a pull request contributing this feature.

It's been over 2 years since this discussion stopped and there appear to be no answer from IBM Strongloop about this yet. Serverless is today way more popular than it was in 2017 and there's still no framework solution for it. I think Loopback has been the de-facto framework for NodeJS since its conception as it has virtually no competition, and would love to see some interest from their side on this topic.

Thanks @sebolio for bringing the issue to our attention.

it鈥檚 definitely been a while and I agree it鈥檚 good to revisit this.

I鈥檝e re-opened the issue so that we can continue discussion.

Unfortunately I鈥檓 not too sure how to go forward with serverless for LoopBack 4, and will need to read up more first.

In the mean time, the core maintainers may have some new ideas to chime in.

to accommodate millions of users on our system - we need to be able to scale up systems / api end point capacity. aws lambda / serverless can do this out of the box without much (any?) thought - and then you pay per cpu usage / no servers / no web farms / no load balancing pools / health checks / no pm2 / no process monitoring....

Loopback needs to strive to play nicelessly in this space -
just bootup quickly - accept the api request - process - and spit out result.
@botbits created this repo a long time back - I'm yet to test it out https://github.com/botbits/serverless-loopback

UPDATE
this article sums things up nicely
https://medium.com/smac-4u/serverless-loopback-9ff0d6fa539d

@marcelobern
Current thinking is to go aws lambda + swift
https://github.com/swift-aws
https://github.com/swift-sprinter/aws-serverless-swift-api-template/blob/master/Products/Sources/ProductService/ProductService.swift
Hoping it's not a complete re-write.

@8secz-johndpope now that lb4 seems to have caught up to the key lb3 feature set and with lb3 in Maintenance LTS I am gearing up to look into creating a lb4 serverless based on the work done for lb3-serverless.

As I am reading up on lb4 I am starting to put together a plan and would be happy to get input from the lb4 community and collaborate on the development either as a contribution to standard lb4 or an external extension.

The lb3-serverless work was primarily showcasing the power of pairing up lb3 and serverless framework, and as such focused mainly on tying up the Lambda handler into the lb3 express instance.

For a minimum (and useful) capability as it relates to lb4, I would offer that the following is a good starting point:

  • Lambda handler integrated into lb4 controllers. Based on what I read so far I am thinking a sequence action might be a good approach here.
  • Datastore config dynamically loaded from Secrets Manager/Parameter Store. The current approach in the lb3 example is statically defined, primarily because I was hving a hard time loading those values dynamically prior to the datastore connection being established by lb3. I suspect participating in the app start/stop might be a suitable approach for this bit on lb4.

Would love to hear any other needs the community came across and hear ideas on better approaches to tackle the capabilities listed above from folks more experienced that I am on lb4 ;-)

@8secz-johndpope thanks for sharing your direction around swift. I just published an update to serverless-loopback including a loopback 4 example (using express).

@achrinza seems like the direction you all are taking is tackling this from a webpack perspective only.

Based on what I learned during my brief exploration of options, I think it would be really powerful to have loopback4 be an easy way for serverless to deploy different granularity of functions (I am not sure if this is already possible with the current loopback 4 capabilities).

Here is an example showing what I mean by "different granularity of functions":

functions:
  defaultController: # check [1] for a working example
    handler: dist/lambda-wrapper.handler
    events:
      - http: ANY /
      - http: 'ANY {proxy+}'
  controllerAbc: # mocked, still needs wrapper to work in serverless (e.g. AWS Lambda)
    handler: dist/controllers/abc.controller
    events:
      - http:
          path: /abc
          method: ANY
  ping: # mocked, still needs wrapper to work in serverless (e.g. AWS Lambda)
    handler: dist/controllers/ping.controller.PingController.ping
    events:
      - http:
          path: /ping
          method: get

[1] 'botbits/serverless-loopback#15'

Would love to hear any thoughts around feasibility of the above with current capabilities.

I just wrote an article to use Loopback 4 in AWS Lambda without express composition with easy setup.
Link to article
and also there is an example repo for it. Link to Repo
Also, I have done AWS Secrets Manager implementation for the same to get config on runtime. For this, you can simply change this code in lambda.js.

const AWS = require('aws-sdk');

const application = require('./dist');
const awsServerlessExpress = require('aws-serverless-express');
let configs;
const app = new application.Lb4LambdaBoilerplateApplication({
  rest: {
    openApiSpec: {
      setServersFromRequest: true,
    },
  },
});
const server = awsServerlessExpress.createServer(app.restServer.requestHandler);

async function getConfig() {
  return new Promise((resolve, reject) => {
    const client = new AWS.SecretsManager({
      region: process.env.PINPOINT_REGION,
    });
    client.getSecretValue({SecretId: `${process.env.CONFIG_KEY}`}, function(err, data) {
      if (err) {
        reject(err);
      } else {
        resolve(data.SecretString);
      }
    });
  });
}

const setEnv = async () => {
  configs = JSON.parse(await getConfig());
  Object.keys(configs).forEach(key => {
    process.env[key] = configs[key];
  });
};

exports.handler = async (event, context) => {
  if (!configs) {
    await setEnv();
  }
  await app.boot();
  return awsServerlessExpress.proxy(server, event, context, 'PROMISE').promise;
};

In this implementation, I am passing configs through env during runtime you can use configs in any other way also.

Was this page helpful?
0 / 5 - 0 ratings