New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

laconia-core

Package Overview
Dependencies
Maintainers
1
Versions
5
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

laconia-core - npm Package Compare versions

Comparing version 0.1.0 to 0.2.0

src/CoreLaconiaContext.js

19

package.json
{
"name": "laconia-core",
"version": "0.1.0",
"version": "0.2.0",
"description": "Micro AWS Lambda framework",

@@ -18,5 +18,5 @@ "keywords": [

"files": [
"lib"
"src"
],
"main": "lib/index.js",
"main": "src/index.js",
"repository": {

@@ -26,17 +26,14 @@ "type": "git",

},
"scripts": {
"compile": "babel src -d lib",
"prepublish": "npm run compile",
"compile:watch": "npm run compile -- --watch"
},
"dependencies": {
"lodash.isfunction": "^3.0.9",
"lodash.isplainobject": "^4.0.6"
},
"devDependencies": {
"laconia-test-helper": "^0.1.0"
"laconia-test-helper": "^0.2.0"
},
"peerDependencies": {
"aws-sdk": "^2.0.1"
},
"engines": {
"node": ">=6.10"
"node": ">=8.10"
}
}

@@ -9,2 +9,17 @@ # laconia-core

An AWS Lambda handler function is a single entry point for both injecting dependencies
and function execution. In non-serverless development, you can and will normally
only focus on the latter. This brings a unique challenge to AWS Lambda development
as it is very difficult to test a handler function when it is responsible for doing
both the object creations and the application run. laconia-core is a simple dependency
injection framework for your Lambda code, hence solving this problem for you.
Laconia explicitly splits the responsibility of the object creations and Lambda function execution.
Laconia also provides a simple way for you to execute your Lambda function
so that your unit tests will not execute the code that instantiates your Lambda dependencies.
## FAQ
Check out [FAQ](https://github.com/ceilfors/laconia#faq)
## Usage

@@ -24,28 +39,107 @@

Create a new js file and the following capabilities will be made
available for you:
To fully understand how Laconia's Dependency Injection works, let's have a look into an
example below. _This is not a running code as there are a lot of code that have been trimmed down,
full example can be found in the acceptance test: [src](packages/laconia-acceptance-test/src/place-order.js)
and [unit test](packages/laconia-acceptance-test/test/place-order.spec.js)_.
Lambda handler code:
```js
const { laconia, recurse invoke } = require('laconia-core')
// Objects creation, a function that returns an object
const instances = ({ env }) => ({
orderRepository: new DynamoDbOrderRepository(env.ORDER_TABLE_NAME),
idGenerator: new UuidIdGenerator()
});
// Handler function, which do not have any object instantiations
module.exports.handler = laconia(
// Instances made available via destructuring
async ({ event, orderRepository, idGenerator }) => {
await orderRepository.save(order);
}
).register(instances);
```
The `laconia` function will be the main entry of your Lambda execution. It wraps the
original Lambda signature so that you won't forget to call AWS
Lambda's `callback` anymore.
Unit test code:
To respond to your Lambda caller, you can do the following:
```js
const handler = require("../src/place-order").handler;
* return object: This will used for calling Lambda `callback`
* return Promise: The promise will be resolved/rejected, and `callback` will called appropriately
* throw error: The error object will be used for calling Lambda `callback`
* return `recurse(payload)` function: Recurse the currently running Lambda
* -_in progress_- return `send(statusCode, data)` function: Return an API Gateway Lambda Proxy Integration response
* -_in progress_- return `sendError(statusCode, error)` function: Return an API Gateway Lambda Proxy Integration response
// Creates a mock Laconia context
beforeEach(() => {
lc = {
orderRepository: {
save: jest.fn().mockReturnValue(Promise.resolve())
}
};
});
// Runs handler function without worrying about the objects creation
it("should store order to order table", async () => {
await handler.run(lc);
expect(lc.orderRepository.save).toBeCalledWith(
expect.objectContaining(order)
);
});
```
Note that as you have seen so far, Laconia is not aiming to become a comprehensive
DI framework hence the need of you handle the instantiation of all of the objects by yourself.
It should theoretically be possible to integrate Laconia to other more comprehensive
NodeJS DI framework but it has not been tested.
### LaconiaContext
Laconia provides a one stop location to get all of the information you need for your Lambda
function execution via `LaconiaContext`. In a nutshell, LaconiaContext is just an object that
contains all of those information by using object property keys, hence you can destructure it
to get just the information you need.
#### AWS Event and Context
When Laconia is adopted, the handler function signature will change. Without Laconia,
your handler signature would be `event, context, callback`. With Laconia, your handler
signature would be `laconiaContext`. The `event` and `context` are always available in LaconiaContext.
`callback` is not made available as this should not be necessary anymore when you are
using Node 8, just `return` the value that you want to return to the caller inside the handler function.
Example:
```js
const { laconia } = require('laconia-core')
laconia(({ event, context }) => true);
```
module.exports.handler = laconia(() => 'hello')
#### Laconia helpers
LaconiaContext contains some helpers that you can use by default. They are accessible
via the following keys:
* `invoke`
* `recurse`
The details of these helpers are covered in the different section of this documentation.
Example:
```js
laconia(({ invoke, recurse }) => true);
```
#### Environment Variables
It is very common to set environment variables for your Lambda functions.
This is normally accessed via `process.env`. Unit testing a Lambda function that
uses `process.env` is awkward, as you have to modify the `process` global variable and remember
to remove your change so that it doesn't affect other test.
For better unit testability, LaconiaContext contains the environment variables
with key `env`.
Example:
```js
laconia(({ env }) => true);
```
### API

@@ -63,8 +157,47 @@

// Simple return value
laconia(() => 'value')
laconia(() => "value");
// Return a promise and 'value' will be returned to the Lambda caller
laconia(() => Promise.resolve('value'))
laconia(() => Promise.resolve("value"));
```
#### `register(instanceFn)`
Registers objects into LaconiaContext. Objects registered here will be made
available in the Lambda function execution.
* `instanceFn(laconiaContext)`
* This `Function` is called when your Lambda is invoked
* An object which contains the instances to be registered must be returned
Example:
```js
// Register an object with key 'service'
laconia(({ service }) => service.call()).register(() => ({
service: new SomeService()
}));
```
#### `run(laconiaContext)`
Runs Lambda handler function with the specified `laconiaContext` and bypasses
the LaconiaContext registration step. This function should only be used in a
unit test.
* `laconiaContext`
* A plain object that should represent the LaconiaContext to be used in the function execution
```js
// Runs a handler function with a LaconiaContext that contains a mock service object.
// `SomeService` will not be instantiated
laconia(({ service }) => service.call())
.register(() => ({
service: new SomeService()
}))
.run({
service: jest.mock()
});
```
## Lambda Invocation

@@ -78,9 +211,14 @@

An `invoke` function is injected to LaconiaContext by default, or you can
import it manually.
```js
const { invoke } = require('laconia-core')
const { laconia } = require("laconia-core");
// Waits for Lambda response before continuing
await invoke('function-name').requestResponse({ foo: 'bar' })
// Invokes a Lambda and not wait for it to return
await invoke('function-name').fireAndForget({ foo: 'bar' })
module.exports.handler = laconia(async ({ invoke }) => {
// Waits for Lambda response before continuing
await invoke("function-name").requestResponse({ foo: "bar" });
// Invokes a Lambda and not wait for it to return
await invoke("function-name").fireAndForget({ foo: "bar" });
});
```

@@ -103,5 +241,5 @@

// Customise AWS.Lambda instantiation
invoke('name', {
lambda: new AWS.Lambda({ apiVersion: '2015-03-31' })
})
invoke("name", {
lambda: new AWS.Lambda({ apiVersion: "2015-03-31" })
});
```

@@ -119,3 +257,3 @@

```js
invoke('fn').requestResponse({ foo: 'bar' })
invoke("fn").requestResponse({ foo: "bar" });
```

@@ -133,3 +271,3 @@

```js
invoke('fn').fireAndForget({ foo: 'bar' })
invoke("fn").fireAndForget({ foo: "bar" });
```

@@ -139,12 +277,13 @@

To be used together with `laconia` function to recurse the currently running Lambda.
An instantiated `recurse` function is injected to LaconiaContext by default, or
you can import it manually from laconia-core.
```js
const { laconia, recurse } = require('laconia-core')
const { laconia } = require("laconia-core");
module.exports.handler = laconia(({ event }) => {
module.exports.handler = laconia(({ event, recurse }) => {
if (event.input !== 3) {
return recurse({ input: event.input + 1 })
return recurse({ input: event.input + 1 });
}
})
});
```

@@ -163,7 +302,7 @@

```js
laconia(({ event }, { recurse }) => {
laconia(({ event, recurse }) => {
if (event.input !== 3) {
return recurse({ input: event.input + 1 })
return recurse({ input: event.input + 1 });
}
})
});
```
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc