Skip to content

Commit

Permalink
feat: add envelopes & entrypoint
Browse files Browse the repository at this point in the history
  • Loading branch information
dreamorosi committed Mar 25, 2024
1 parent 7c6eba6 commit c72a4f7
Show file tree
Hide file tree
Showing 3 changed files with 165 additions and 1 deletion.
103 changes: 103 additions & 0 deletions packages/jmespath/src/envelopes.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
import { search } from './search.js';
import { PowertoolsFunctions } from './PowertoolsFunctions.js';
import type { ParsingOptions, JSONObject } from './types.js';

/**
* Searches and extracts data using JMESPath
*
* Envelope being the JMESPath expression to extract the data you're after
*
* Built-in JMESPath functions include: `powertools_json`, `powertools_base64`, `powertools_base64_gzip`
*
* @example
* ```typescript
* import { extractDataFromEnvelope } from '@aws-lambda-powertools/jmespath/envelopes';
*
* type CustomEvent = {
* body: string; // "{\"customerId\":\"dd4649e6-2484-4993-acb8-0f9123103394\"}"
* };
*
* type EventBody = {
* customerId: string;
* };
*
* export const handler = async (event: CustomEvent): Promise<unknown> => {
* const payload = extractDataFromEnvelope<EventBody>(event, "powertools_json(body)");
* const { customerId } = payload; // now deserialized
* // ...
* };
* ```
*
* We provide built-in envelopes for popular AWS Lambda event sources to easily decode and/or deserialize JSON objects.
*
* @example
* ```typescript
* import {
* extractDataFromEnvelope,
* SQS,
* } from '@aws-lambda-powertools/jmespath/envelopes';
* import type { SQSEvent } from 'aws-lambda';
*
* type MessageBody = {
* customerId: string;
* };
*
* export const handler = async (event: SQSEvent): Promise<unknown> => {
* const records = extractDataFromEnvelope<Array<MessageBody>>(event, SQS);
* for (const record in records) { // records is now a list containing the deserialized body of each message
* const { customerId } = record;
* }
* };
* ```
*
* @param data The JSON object to search
* @param envelope The JMESPath expression to use
* @param options The parsing options to use
*/
const extractDataFromEnvelope = <T>(
data: JSONObject,
envelope: string,
options?: ParsingOptions
): T => {
if (!options) {
options = { customFunctions: new PowertoolsFunctions() };
}

return search(envelope, data, options) as T;
};

const API_GATEWAY_REST = 'powertools_json(body)';
const API_GATEWAY_HTTP = 'powertools_json(body)';
const SQS = 'Records[*].powertools_json(body)';
const SNS = 'Records[0].Sns.Message | powertools_json(@)';
const EVENTBRIDGE = 'detail';
const CLOUDWATCH_EVENTS_SCHEDULED = 'detail';
const KINESIS_DATA_STREAM =
'Records[*].kinesis.powertools_json(powertools_base64(data))';
const CLOUDWATCH_LOGS =
'awslogs.powertools_base64_gzip(data) | powertools_json(@).logEvents[*]';
const S3_SNS_SQS =
'Records[*].powertools_json(body).powertools_json(Message).Records[0]';
const S3_SQS = 'Records[*].powertools_json(body).Records[0]';
const S3_SNS_KINESIS_FIREHOSE =
'records[*].powertools_json(powertools_base64(data)).powertools_json(Message).Records[0]';
const S3_KINESIS_FIREHOSE =
'records[*].powertools_json(powertools_base64(data)).Records[0]';
const S3_EVENTBRIDGE_SQS = 'Records[*].powertools_json(body).detail';

export {
extractDataFromEnvelope,
API_GATEWAY_REST,
API_GATEWAY_HTTP,
SQS,
SNS,
EVENTBRIDGE,
CLOUDWATCH_EVENTS_SCHEDULED,
KINESIS_DATA_STREAM,
CLOUDWATCH_LOGS,
S3_SNS_SQS,
S3_SQS,
S3_SNS_KINESIS_FIREHOSE,
S3_KINESIS_FIREHOSE,
S3_EVENTBRIDGE_SQS,
};
60 changes: 60 additions & 0 deletions packages/jmespath/src/search.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { Parser } from './Parser.js';
import type { ParsingOptions, JSONObject } from './types.js';

const parser = new Parser();

/**
* Search for data in a JSON object using a JMESPath expression.
*
* @example
* ```typescript
* import { search } from '@aws-lambda-powertools/jmespath';
*
* const data = {
* foo: {
* bar: {
* baz: 1
* }
* }
* };
*
* const result = search('foo.bar.baz', data);
* console.log(result); // 1
* ```
*
* By default the search function will use all the built-in functions
* present in the [JMESPath specification](https://jmespath.org/specification.html).
*
* Powertools for AWS Lambda provides some additional functions that can be used
* by passing them in the `customFunctions` option.
*
* @example
* ```typescript
* import { search } from '@aws-lambda-powertools/jmespath';
* import { PowertoolsFunctions } from '@aws-lambda-powertools/jmespath/functions';
*
* const data = {
* body: "{\"foo\": \"bar\"}"
* };
*
* const result = search(
* 'powertools_json(body)',
* data,
* { customFunctions: new PowertoolsFunctions() }
* );
* console.log(result); // { foo: 'bar' }
* ```
*
* @param expression The JMESPath expression to use
* @param data The JSON object to search
* @param options The parsing options to use
*/
const search = (
expression: string,
data: JSONObject,
options?: ParsingOptions
): unknown => {
return parser.parse(expression).search(data, options);
};

export { search };
3 changes: 2 additions & 1 deletion packages/jmespath/typedoc.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
"../../typedoc.base.json"
],
"entryPoints": [
"./src/index.ts",
"./src/search.ts",
"./src/errors.ts",
"./src/types.ts",
"./src/envelopes.ts",
"./src/Functions.ts",
Expand Down

0 comments on commit c72a4f7

Please sign in to comment.