npm package: @noths/cloud-utils
Description: Functional cloud utilities for NOTHS Serverless Cloud Applications
Author: Notonthehighstreet Enterprises Ltd
Latest version: 0.2.0

# Cloud Utilities
A collection of helpful Node.JS utility functions which are used across Lambda (and other) serverless functions.

### Secrets
Wraps function execution with encrypted secrets from [AWS SSM Parameter Store](https://docs.aws.amazon.com/systems-manager/latest/userguide/systems-manager-paramstore.html) using a specific key, provided that the executing IAM Role has sufficient privileges to do so.

```js
import { withParameters } from '@noths/cloud-utils';

const SECRET_KEY = '/path/to/ssm/encrypted/secret';

const ALIAS = 'SUPER_SECRET_KEY';

const myFn = async ({ [ALIAS]: key }, a, b) => {
  return thirdPartyApi(key).someOperation(a, b);
};

export default withParameters({ [ALIAS]: SECRET_KEY })(myFn);
```

Elsewhere in the application, this function can be consumed as:

```js
import myFn from './some-file';

const handler = async (a, b, ...other) => {
  const { result } = await myFn(a, b);
  return result;
};
```

---

### Tracing
Wraps modules & functions, providing [AWS XRay]() tracing for trace execution. You may also provide a recognizable name for the module to be traced, in addition to custom metadata, annotations and captured functions as subsegments.

Note, functions wrapped with `captureFunc` or `captureFuncSync` should have a `withTracing` higher in their call stack; otherwise XRay will throw an error, as no namespace, segment or context has been configured.

##### Async module tracing with
```js
import { captureFunc } from '@aerofer/utils/tools/tracing';
import someRemoteOperation from 'some-other-module';

const OPERATION = 'Some Remote Operation';

const metadata = {
  version: '0.0.1',
};

// capture arguments and add as annotations
const capture = (a, b) => ({ a, b });

const handler = async (a, b) => {
  const { body } = await someRemoteOperation(a, b);
  return body;
}

export default captureFunc(OPERATION, { metadata, capture })(handler);
```

##### Runtime sync tracing with annotations
```js
import { captureFuncSync } from '@aerofer/utils/tools/tracing';
import captureSync from 'some-other-module';

const CAPTURE = 'Capture';

const handler = (customerId, amount) => {
  const annotations = { customerId };
  const capture = captureFuncSync(CAPTURE, { annotations })(captureSync);
  return capture(customerId, amount);
};

export default handler;
```
---

### Errors
Provides a helpful utility for optionally wrapping low-level, native error objects from libraries with application errors which can be:

* Serialized and surfaced to consumer applications.
* Filtered inside logs using JSONPath to provide custom application error metrics.

```js
import { withProperties } from '@noths/cloud-utils/tools/errors';

export const FOOBAR_ERROR = 'FoobarError';

const errors = {
  ...(withProperties(FOOBAR_ERROR, { statusCode: 400, message: 'A foobar error occurred' })),
};

export default errors;
```

When you need to throw an error of this type inside your application, you can instantiate it like so:

```js
import Errors, { FOOBAR_ERROR } from './errors';

const { [FOOBAR_ERROR]: LogicalError } = Errors;

const fn = (cb) => {
  someOperation((err, data) => {
    if (err) {
      throw new LogicalError('overrides default message', err);
    } else {
      cb(data);
    }
  })
};
```

---

### Logger
Simple logger for serializing objects and application errors into JSON lines for inspection and JSONPath filtering.

```js
import Logger from '@noths/cloud-utils/tools/logger';

const TIME_TAKEN = 'ExecutionTimeTaken';

const reporter = (time) => ({ time, type: TIME_TAKEN });

const handler = async () => {
  const start = +new Date();
  const data = await processor();
  const end = +new Date();
  Logger.info(reporter(end - start));
  return data;
};
```

There are two environment variables you can set, in-order to control the logger:

* `LOG_LEVEL` - The level of logging to produce output for.

---

### Responders
HTTP Responders wrap response objects from Lambda Proxy functions (or any other mechanism), enabling the easy serialization of Javascript objects whether it is a success or failure.

```js
import { success, failure } from '@noths/cloud-utils/tools/responders';

// Object containing security HTTP headers & CORS
import headers from './headers';

export const handler = async (event, context, cb) => {
  try {
    const result = await processor(event);
    const response = success({ code: 201, headers, body: result });
    cb(null, response);
  } catch (err) {
    if (err.statusCode) {
      // application error
      cb(null, failure(event, err));
    } else {
      // native error
      cb(err);
    }
  }
};
```