Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(jmespath): add JMESPath utility #2135

Closed
wants to merge 104 commits into from
Closed

feat(jmespath): add JMESPath utility #2135

wants to merge 104 commits into from

Conversation

dreamorosi
Copy link
Contributor

@dreamorosi dreamorosi commented Feb 24, 2024

Description of your changes

This PR introduces a new Powertools utility for JMESPath which will be published under @aws-lambda-powertools/jmespath.

The utility is primarily aimed at being a dependency of the Idempotency utility but can be used as standalone as well as in future utilities that revolve around JSON like the Validation utility (#508).

As discussed in one of the linked issues (#1645) the official JMESPath module does not support custom functions (example in Powertools Python) and all other existing versions and forks are largely unmaintained or owned by individuals.

To tackle the concerns and limitations above, as well as providing a modern implementations fully written in TypeScript we decided to implement our own version based of the Python jmespath module which is MIT licensed.

The JMESPath specification offers a compliance test suite that is used by all libraries who want to offer spec-compliance, the utility we are introducing in this PR adopts that same suite and thus can be considered fully spec compliant.

In addition to the utility and corresponding documentation, this PR also introduces a new helper function that allows to extract data from envelopes when using JSON. Together with this, it introduces also a series of envelopes from common data sources similar to what found in Powertools Python.

import {
  extractDataFromEnvelope,
  SQS,
} from '@aws-lambda-powertools/jmespath/envelopes';
import { Logger } from '@aws-lambda-powertools/logger';
import type { SQSEvent } from 'aws-lambda';

const logger = new Logger();

type MessageBody = {
  customerId: string;
};

export const handler = async (event: SQSEvent): Promise<void> => {
  const records = extractDataFromEnvelope<Array<MessageBody>>(event, SQS);
  for (const record of records) {
    // records is now a list containing the deserialized body of each message
    const { customerId } = record;
    logger.appendKeys({ customerId });
  }
};

Note that while there are similarities with the Parser utility being implemented in parallel with this utility, the main difference is the way the problem is approached. While the Parser utility uses Zod to validate and parse a payload using Zod schemas, the extractDataFromEnvelope() function and its envelopes is instead used to simply extract a subset of data from a JSON payload while also not applying any kind of validation.

Together with these utilities we also provide some custom JMESPath functions that complement the existing JMESPath built-in functions. Using these functions customers can reach into encoded data structures within their JSON payload.

For example, when dealing with an event coming to API Gateway or SQS, the body of the message is a stringified version of a JSON. To access it customers have to apply their own parsing, but with these custom functions they do so within the same JMESPath expression, and potentially even extract data from within the parsed object.

import type { APIGatewayEvent } from 'aws-lambda';
import { randomUUID } from 'node:crypto';
import {
  makeIdempotent,
  IdempotencyConfig,
} from '@aws-lambda-powertools/idempotency';
import { DynamoDBPersistenceLayer } from '@aws-lambda-powertools/idempotency/dynamodb';

const persistenceStore = new DynamoDBPersistenceLayer({
  tableName: 'IdempotencyTable',
});

export const handler = makeIdempotent(
  async (event: APIGatewayEvent) => {
    const body = JSON.parse(event.body || '{}');
    const { user, productId } = body;

    const result = await createSubscriptionPayment(user, productId);

    return {
      statusCode: 200,
      body: JSON.stringify({
        paymentId: result.id,
        message: 'success',
      }),
    };
  },
  {
    persistenceStore,
    config: new IdempotencyConfig({
      eventKeyJmesPath: 'powertools_json(body)',
    }),
  }
);

declare function createSubscriptionPayment(
  user: string,
  productId: string
): Promise<{ id: string; message: string }>;

Finally, to support this utility I have made some small addition to the commons utility. Some of these, like the utilities to parse to and from base64 encoding can and will be adopted by the Parameters utility as well, allowing us to drop a dependency on a deprecated AWS SDK package.

This utility will be adopted by the Idempotency utility in a future PR. Some of the features mentioned above will allow customers to select parts of payloads to be used for idempotency that were not accessible before, like the SQS example mentioned above.

Related issues, RFCs

Issue number: #1645

Checklist

  • My changes meet the tenets criteria
  • I have performed a self-review of my own code
  • I have commented my code where necessary, particularly in areas that should be flagged with a TODO, or hard-to-understand areas
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings
  • I have added tests that prove my change is effective and works
  • The PR title follows the conventional commit semantics

Breaking change checklist

Is it a breaking change?: NO

  • I have documented the migration process
  • I have added, implemented necessary warnings (if it can live side by side)

By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.

Disclaimer: We value your time and bandwidth. As such, any pull requests created on non-triaged issues might not be successful.

@dreamorosi dreamorosi self-assigned this Feb 24, 2024
@dreamorosi dreamorosi linked an issue Feb 24, 2024 that may be closed by this pull request
2 tasks
@boring-cyborg boring-cyborg bot added automation This item relates to automation documentation Improvements or additions to documentation internal PRs that introduce changes in governance, tech debt and chores (linting setup, baseline, etc.) labels Feb 24, 2024
@github-actions github-actions bot added the feature PRs that introduce new features or minor changes label Feb 24, 2024
@dreamorosi dreamorosi added the on-hold This item is on-hold and will be revisited in the future label Mar 6, 2024
@boring-cyborg boring-cyborg bot added commons This item relates to the Commons Utility dependencies Changes that touch dependencies, e.g. Dependabot, etc. labels Mar 6, 2024
@pull-request-size pull-request-size bot added the size/XXL PRs with 1K+ LOC, largely documentation related label Mar 6, 2024
erikayao93 and others added 19 commits March 6, 2024 16:15
* Updated formatAttributes for additional parameters and LogItem return type

* Updated the unit tests to pass with new formatter

* Updated Powertool named objects to Powertools

* Updated tests to match new naming consistency

* Updated for tests for new naming consistency

* Updated formatter for new design decisions

* Update Logger for ephemeral attributes

* Update bringYourOwnFormatter documentation to match new formatter

---------

Co-authored-by: erikayao93 <[email protected]>
* Updated formatAttributes for additional parameters and LogItem return type

* Updated the unit tests to pass with new formatter

* Updated Powertool named objects to Powertools

* Updated tests to match new naming consistency

* Updated for tests for new naming consistency

* Updated formatter for new design decisions

* Update Logger for ephemeral attributes

* Update bringYourOwnFormatter documentation to match new formatter

---------

Co-authored-by: erikayao93 <[email protected]>
…pdate (#1585)

* Updated formatAttributes for additional parameters and LogItem return type

* Updated the unit tests to pass with new formatter

* Updated Powertool named objects to Powertools

* Updated tests to match new naming consistency

* Updated for tests for new naming consistency

* Updated formatter for new design decisions

* Update Logger for ephemeral attributes

* Update bringYourOwnFormatter documentation to match new formatter

* Fixed incorrect return type, renamed variable for consistency
…1722)

* chore(maintenance): bump dependencies & drop nodejs14x (#1687)

* chore: add pre-release script

* chore: restore deps

* chore: added v2 shim

* chore(maintenance): remove logger and tracer helper function

* chore: remove imports

* chore: fix deps & versions

* tests: moved unit tests

* tests: move logger tests

* chore: added v2 shim

* chore: added v2 shim
* feat(logger): add esm build output

* fix(Logger): Remove barrel files update references

* test(Logger): update jest/ts-jest to use ESM

* chore(Logger): remove unused lodash.merge

* fix(logger): reinstate lodash.merge

* chore(logger): revert TS assertion

* chore(logger): revert format changes

* chore(logger): update postbuild to remove incremental tsbuildinfo files

* fix(logger): correct reference to types output

* feat(logging): add middleware export

* chore(logger): replace postbuild script with echo statement

* feat(logger): add typesVersions property and barrel files to /types

* chore(logger): file not used, can be added back if needed

* chore(logger): add space back to README

* chore(logger): revert space in README
* chore(logger): adapt logger to commons exports

* feat(commons): add esmodule support

* chore: address sonar findings

* chore(commons): exported version

* chore: fixed imports in examples

* chore(parameters): fixed imports

* chore(metrics): fixed imports

* chore(tracer): fixed imports

* chore(idempotency): fixed imports

* chore(commons): test coverage

* chore(batch): fix imports
* feat(testing): add esmodule support

* chore(all): update imports
* docs(maintenance): update mkdocs to support tabs

* chore(ci): add parallel test npm script

* chore(ci): add jest command

* docs(maintenance): add testing page to navbar

* docs(maintenance): add contributing info

* chore: update roadmap

* chore: update release drafter workflow to allow for manual trigger

* fix formatting

* docs: maintainers handbook

* chore: link to new location

* fix links

* Update docs/maintainers.md

Co-authored-by: Alexander Schueren <[email protected]>

---------

Co-authored-by: Alexander Schueren <[email protected]>
* chore(logger): refactor types and interfaces

* chore: grouped type files

* chore: fix code smell

* chore: fix ci

* chore: fix ci
* chore(layers) widen version check in e2e

* chore(maintenance): enable isolatedModules

* chore: remove redundant comments from tsconfig

* chore: changed path of tsbuild cache
@boring-cyborg boring-cyborg bot added the tests PRs that add or change tests label Mar 6, 2024
Copy link

sonarqubecloud bot commented Mar 12, 2024

Quality Gate Passed Quality Gate passed

Issues
0 New issues
0 Accepted issues

Measures
0 Security Hotspots
No data about Coverage
27.9% Duplication on New Code

See analysis details on SonarCloud

@dreamorosi dreamorosi closed this Mar 25, 2024
@dreamorosi
Copy link
Contributor Author

I closed this PR in favor of: #2187, #2189, #2192, #2212, #2213, #2214, #2259, #2264, #2266, #2265, #2271

@dreamorosi dreamorosi removed a link to an issue Mar 27, 2024
2 tasks
@dreamorosi dreamorosi deleted the feat/jmespath branch April 17, 2024 06:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
automation This item relates to automation commons This item relates to the Commons Utility dependencies Changes that touch dependencies, e.g. Dependabot, etc. documentation Improvements or additions to documentation feature PRs that introduce new features or minor changes internal PRs that introduce changes in governance, tech debt and chores (linting setup, baseline, etc.) on-hold This item is on-hold and will be revisited in the future size/XXL PRs with 1K+ LOC, largely documentation related tests PRs that add or change tests
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Feature request: provide custom functions for JMESPath expressions
4 participants