Public beta — not for production use. Data may be wiped at any time. Questions? Contact us.
A
Axiom
/Marketplace/christiangeorgelucas/jmespath-tools
Sign in

christiangeorgelucas/jmespath-tools

v0.1.0Python

The jmespath-tools package provides composable Axiom nodes for JMESPath, a declarative JSON query language. It allows users to evaluate JMESPath expressions against JSON documents, validate expressions, and introspect them without execution, making it ideal for building robust JSON querying tools and applications.

Published by Christian George Lucas· MIT

json-queryjmespathdata-validationexpression-evaluationjson-toolserror-handling

Use cases

  • Evaluate complex JSON queries in AWS CLI
  • Validate JMESPath expressions before execution
  • Introspect and analyze JMESPath expressions for tooling
  • Batch process multiple JSON documents with error isolation
  • Project multiple JMESPath expressions into a single JSON object

Nodes (5)

Parseunary
ParseRequest·ParseResult

The Parse node takes a JMESPath expression and converts it into its abstract syntax tree (AST) representation without executing it, enabling tools to analyze or construct expressions programmatically.

View source
import json

import jmespath
from jmespath import exceptions as jmespath_exceptions

from gen.messages_pb2 import ParseRequest, ParseResult
from gen.axiom_context import AxiomContext


def parse(ax: AxiomContext, input: ParseRequest) -> ParseResult:
    """Parses a JMESPath expression into its abstract syntax tree, without
    evaluating it against any data -- useful for tooling that introspects,
    analyzes, or programmatically builds expressions (e.g. a visual query
    builder, or checking which fields/functions an expression touches). The
    AST is jmespath.py's own parsed tree: a nested structure of node "type"
    (field, subexpression, index, slice, projection, filter_projection,
    function_expression, comparator, pipe, or_expression, and_expression,
    not_expression, literal, multi_select_list, multi_select_hash, expref,
    current, ...), "children", and, for identifier/literal/function nodes, a
    "value".
    """
    try:
        try:
            compiled = jmespath.compile(input.expression)
        except jmespath_exceptions.JMESPathError as e:
            return ParseResult(valid=False, error=str(e))

        ast_json = json.dumps(compiled.parsed, sort_keys=True)
        return ParseResult(valid=True, ast=ast_json)
    except Exception as e:  # never leak a raw traceback for any input
        return ParseResult(valid=False, error=f"unexpected error: {e}")
ProjectPathsunary
ProjectPathsRequest·ProjectPathsResult

The ProjectPaths node evaluates multiple JMESPath expressions against a single JSON document and compiles the results into a flat JSON object, where each result is keyed by a unique name. This process simplifies the creation of complex JMESPath queries by eliminating the need for manual syntax construction.

View source
import jmespath
from jmespath import exceptions as jmespath_exceptions

from gen.messages_pb2 import ProjectPathsRequest, ProjectPathsResult
from gen.axiom_context import AxiomContext
from nodes._common import parse_json_document, dump_json_value


def project_paths(ax: AxiomContext, input: ProjectPathsRequest) -> ProjectPathsResult:
    """Evaluates several independent JMESPath expressions against the same
    document and assembles the results into one flat JSON object keyed by
    name -- the structured equivalent of JMESPath's multiselect-hash syntax
    ("{a: expr_a, b: expr_b}"), without requiring the caller to hand-author
    that syntax (whose colons and nested quoting are awkward to embed
    correctly inside a JSON string value). All field names must be unique
    and every field's expression must parse and evaluate cleanly, or the
    whole request fails with a structured error naming the offending field.
    """
    try:
        try:
            document = parse_json_document(input.json)
        except ValueError as e:
            return ProjectPathsResult(error=str(e))

        seen_names = set()
        assembled = {}
        for field in input.fields:
            if field.name in seen_names:
                return ProjectPathsResult(
                    error=f"duplicate field name: {field.name!r}"
                )
            seen_names.add(field.name)

            try:
                compiled = jmespath.compile(field.expression)
                value = compiled.search(document)
            except jmespath_exceptions.JMESPathError as e:
                return ProjectPathsResult(
                    error=f"field {field.name!r}: {e}"
                )
            assembled[field.name] = value

        return ProjectPathsResult(
            json=dump_json_value(assembled, input.pretty, input.indent)
        )
    except Exception as e:  # never leak a raw traceback for any input
        return ProjectPathsResult(error=f"unexpected error: {e}")
Searchunary
SearchRequest·SearchResult

The Search node evaluates a JMESPath expression against a provided JSON document and returns the resulting value. It handles errors gracefully, returning structured error messages for malformed documents or invalid expressions instead of crashing.

View source
import jmespath
from jmespath import exceptions as jmespath_exceptions

from gen.messages_pb2 import SearchRequest, SearchResult
from gen.axiom_context import AxiomContext
from nodes._common import parse_json_document, dump_json_value


def search(ax: AxiomContext, input: SearchRequest) -> SearchResult:
    """Evaluates a JMESPath expression (https://jmespath.org) against a JSON
    document and returns the single result value the expression produces,
    using jmespath.py -- the reference implementation AWS CLI's --query and
    Ansible's json_query filter are built on. JMESPath makes no distinction
    between "the path is absent" and "the value is JSON null" -- both
    evaluate to null, per the language spec.
    """
    try:
        try:
            document = parse_json_document(input.json)
        except ValueError as e:
            return SearchResult(error=str(e))

        try:
            compiled = jmespath.compile(input.expression)
        except jmespath_exceptions.JMESPathError as e:
            return SearchResult(error=f"invalid JMESPath expression: {e}")

        try:
            result = compiled.search(document)
        except jmespath_exceptions.JMESPathError as e:
            return SearchResult(error=f"expression evaluation failed: {e}")

        return SearchResult(json=dump_json_value(result, input.pretty, input.indent))
    except Exception as e:  # never leak a raw traceback for any input
        return SearchResult(error=f"unexpected error: {e}")
SearchBatchunary
SearchBatchRequest·SearchBatchResult

The SearchBatch node evaluates a single JMESPath expression against multiple independent JSON documents, ensuring that errors are isolated to individual documents. This allows for each document to succeed or fail independently, with results reported at their original indices.

View source
import jmespath
from jmespath import exceptions as jmespath_exceptions

from gen.messages_pb2 import SearchBatchRequest, SearchBatchResult, BatchItem
from gen.axiom_context import AxiomContext
from nodes._common import parse_json_document, dump_json_value


def search_batch(ax: AxiomContext, input: SearchBatchRequest) -> SearchBatchResult:
    """Evaluates one JMESPath expression against each of several independent
    JSON documents, with per-document error isolation -- distinct from
    running one Search against a single document that happens to contain an
    array (there, one malformed element fails the whole request; here, each
    document succeeds or fails on its own and every outcome is reported).
    The expression is compiled exactly once and reused across all documents.
    """
    try:
        try:
            compiled = jmespath.compile(input.expression)
        except jmespath_exceptions.JMESPathError as e:
            return SearchBatchResult(error=f"invalid JMESPath expression: {e}")

        items = []
        for index, doc_json in enumerate(input.json_documents):
            try:
                document = parse_json_document(doc_json)
            except ValueError as e:
                items.append(BatchItem(index=index, error=str(e)))
                continue

            try:
                result = compiled.search(document)
            except jmespath_exceptions.JMESPathError as e:
                items.append(
                    BatchItem(index=index, error=f"expression evaluation failed: {e}")
                )
                continue

            items.append(
                BatchItem(
                    index=index,
                    json=dump_json_value(result, input.pretty, input.indent),
                )
            )

        return SearchBatchResult(items=items)
    except Exception as e:  # never leak a raw traceback for any input
        return SearchBatchResult(error=f"unexpected error: {e}")
Validateunary
ValidateRequest·ValidateResult

The Validate node checks the syntactical validity of a JMESPath expression and compiles it without executing against any data, allowing users to verify expressions before evaluation. If the expression is invalid, it returns detailed error messages indicating the nature of the syntax error.

View source
import jmespath
from jmespath import exceptions as jmespath_exceptions

from gen.messages_pb2 import ValidateRequest, ValidateResult
from gen.axiom_context import AxiomContext


def validate(ax: AxiomContext, input: ValidateRequest) -> ValidateResult:
    """Checks whether a JMESPath expression is syntactically valid and
    compiles successfully, without running it against any data -- useful
    for checking an expression before spending an invocation evaluating it
    against real data.
    """
    try:
        jmespath.compile(input.expression)
        return ValidateResult(valid=True)
    except jmespath_exceptions.JMESPathError as e:
        return ValidateResult(valid=False, error=str(e))
    except Exception as e:  # never leak a raw traceback for any input
        return ValidateResult(valid=False, error=f"unexpected error: {e}")

Messages (12)

Download .proto
BatchItem
index:int32
json:string
error:string
NamedExpression
name:string
expression:string
ParseRequest
expression:string

The JMESPath expression to be parsed into an abstract syntax tree.

ParseResult
valid:bool

Indicates whether the parsing was successful.

ast:string

The JSON-encoded abstract syntax tree representing the parsed expression.

error:string

Contains an error message if the parsing fails.

ProjectPathsRequest
json:string

The JSON document against which the JMESPath expressions will be evaluated.

fields:[]NamedExpression

A list of field definitions, each containing a unique name and a corresponding JMESPath expression to evaluate.

pretty:bool

A boolean indicating whether to format the output JSON in a human-readable way.

indent:int32

An integer specifying the number of spaces to use for indentation in the pretty-printed JSON output.

ProjectPathsResult

No fields

SearchBatchRequest
json_documents:[]string

An array of JSON documents to which the JMESPath expression will be applied.

expression:string

The JMESPath expression to be evaluated against each JSON document.

pretty:bool

A boolean indicating whether the output JSON should be formatted in a human-readable way.

indent:int32

The number of spaces to use for indentation in the pretty-printed output.

SearchBatchResult
items:[]BatchItem
error:string
SearchRequest
json:string

The JSON document to be evaluated against the JMESPath expression.

SearchResult
json:string

The JSON document to be evaluated against the JMESPath expression.

error:string
ValidateRequest
expression:string

The JMESPath expression that needs to be validated for syntax correctness.

ValidateResult
valid:bool

A boolean indicating whether the expression is syntactically valid.

error:string

An error message detailing the syntax error if the expression is invalid.

Use as a tool in any AI agent

christiangeorgelucas/jmespath-tools is callable as a tool from any MCP client (Claude, Cursor, or your own agent) via Axiom's hosted MCP server — no install, no download. Add the server, then your agent can search and invoke it, or pin it as a typed tool.

claude mcp add --transport http axiom https://api.axiomide.com/mcp --header "Authorization: Bearer YOUR_AXIOM_API_KEY"

Replace YOUR_AXIOM_API_KEY with a key you create in Console → API Keys.

MCP server setup & other clients →

Use this package

Sign in to import christiangeorgelucas/jmespath-tools into the graph editor — drop it into a flow and hit run. Or call it directly via the API Reference with your API key.

Sign in to useOpen editor

Stats

Error rate (1h)0.0%
Back to marketplace