christiangeorgelucas/jmespath-tools
v0.1.0PythonThe 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
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)
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}")
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}")
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}")
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}")
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 .protoThe JMESPath expression to be parsed into an abstract syntax tree.
Indicates whether the parsing was successful.
The JSON-encoded abstract syntax tree representing the parsed expression.
Contains an error message if the parsing fails.
The JSON document against which the JMESPath expressions will be evaluated.
A list of field definitions, each containing a unique name and a corresponding JMESPath expression to evaluate.
A boolean indicating whether to format the output JSON in a human-readable way.
An integer specifying the number of spaces to use for indentation in the pretty-printed JSON output.
No fields
An array of JSON documents to which the JMESPath expression will be applied.
The JMESPath expression to be evaluated against each JSON document.
A boolean indicating whether the output JSON should be formatted in a human-readable way.
The number of spaces to use for indentation in the pretty-printed output.
The JSON document to be evaluated against the JMESPath expression.
The JSON document to be evaluated against the JMESPath expression.
The JMESPath expression that needs to be validated for syntax correctness.
A boolean indicating whether the expression is syntactically valid.
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