Object Paths
An ObjectPath names one field of the object Aethrix builds for a service operation. It is the address you enter when a step has to read or write a specific field rather than the whole message: a mapping rule, a data transfer, an assertion, or a condition in a simulated service.
Where paths are used
| Window | Field or command |
|---|---|
| Send Request step, mapping rules | Mapping Rules → Add Mapping Rule, or right-click a field in the object tree → Add mapping rule here |
| Data Transfer step | Add/Edit Data Transfer Rule, with Path Type set to PropertyValue and the path in Path |
| Assertions on a response | Add Object Path Assertion |
| Simulated service rules | Conditions → Edit Condition... |
| API Playground checks | the Assertions tab, the object-path kind |
The same syntax applies in all of them and on every protocol: REST, SOAP, GraphQL, gRPC, Kafka and OData. Some windows label it PropertyValue rather than Object Path; both names refer to this addressing.
The root of a path
A path is written against the operation's request object, or its response object. That object holds the parts of the message, and the body is one of them. The object tree shows the same structure:
POST_Create_a_booking_The_ba…
└─ Body
└─ flight
├─ carrier HB
└─ number 118
The carrier of that flight is Body.flight.carrier. Body is a node in the path, not a prefix the syntax requires.
The remaining parts of the message are siblings of Body and are addressed directly, by the name the message uses:
| Part of the message | Path | Taken from |
|---|---|---|
| Body of a request or response | Body.flight.carrier | the message content |
| Path parameter | reference | POST /api/v1/bookings/{reference}/baggage |
| Query field | date | GET /api/v1/flights?from=...&to=...&date=... |
| Header | X-Correlation-Id | the header name, with its capitals and dashes |
An operation that returns a list as its body is read from the response object in the same way: Body[0].number.
Copying a path
Right-click a field in the object tree and choose Copy Object Path. This is the reliable way to obtain a path for a field whose name is long, mixed-case, or spelled in a form you would not type by hand. The tree is the body editor in the Playground and on a Send Request step, the response editor, the simulation response editor, and the Kafka message payload editor.
Syntax
Segments are separated by dots, and each segment names one field. A segment that names a collection may carry a selector in square brackets. There are no wildcards, filters or functions, and matching is case-sensitive: Body.photos[1].Name is not Body.photos[1].name.
Body.passengers[1].bags[type:checked].weightKg
Read left to right: the body of the request, its second passenger, that passenger's checked bag, and the weight of that bag.
Selecting an element of a collection
| Path | Meaning |
|---|---|
Body.photos[0] | the first photo. Positions start at 0 |
Body.photos | the whole collection. A path that ends at a collection selects it, which is how an assertion or a data transfer takes a list as one value |
Body.photos.name | an error. A path that continues past a collection has to name the element it means |
Two further rules:
- Writing through an index past the end grows the collection.
Body.passengers[4].name = "Jo"on a booking with two passengers creates the elements up to position 4. - A selector on a field that holds no elements is refused, rather than applied to the field as a whole.
Selecting an element of a polymorphic collection
Some collections hold items of different kinds, where each item declares which kind it is. In JSON the item carries a field for this, commonly type:
"bags": [
{ "type": "checked", "weightKg": 23 },
{ "type": "carryOn", "weightKg": 7 }
]
Address those items by the value they carry:
Body.bags[type:checked].weightKg
Body.bags[type:carryOn].hasLaptop
checked and carryOn are the values from the message. On an XML or SOAP service the equivalent is the element name the schema gives each kind, which is also the name the object tree shows, so the path you copied is the path that works: Body.bags[type:hold].
Prefer this to a position where the kind matters. A position records the order one payload happens to be in; if the service returns the carry-on first, or a bag is added at the front, bags[0] addresses a different item, while bags[type:checked] still addresses the checked bag.
| Situation | Behaviour |
|---|---|
| Several items carry the same tag | the path addresses the first of them. Use a position for a specific one: Body.bags[1] |
| No item carries the tag, and the service declares it | reading returns nothing; writing creates that item, so an optional part of a payload can be filled without restating the whole message |
| The tag is not one the service declares | the path is refused, and the error lists the tags that are declared |
| Two declared kinds share one tag name | the path is refused and names both kinds. Address the item by position; the definition needs a proper tag mapping |
To create such an item in the editor, select the entry in the object tree, choose Initialize as …, then pick the kind. Append Item adds another entry.
Example
Baggage registration for one booking. The object tree shows the path parameter and the body as siblings:
POST_Register_ONE_piece_of_ba…
├─ reference GZT001
└─ Body
└─ bags
├─ type checked weightKg 23 lengthCm 75
└─ type carryOn weightKg 7 hasLaptop true
| Target | Path |
|---|---|
| The booking reference in the URL | reference |
| The weight of the first bag | Body.bags[0].weightKg |
| The weight of the checked bag | Body.bags[type:checked].weightKg |
| Whether a laptop is in the cabin bag | Body.bags[type:carryOn].hasLaptop |
| The whole list of bags, as one value | Body.bags |
| A checked bag on a booking that has none | Body.bags[type:checked].weightKg = 20, which creates the item |
On the response side, an assertion of the object-path kind reads Body.bags[type:checked].weightKg from the compiled response and compares it with the expected value. A Data Transfer step with Path Type PropertyValue and Path Body.bags[type:carryOn].tagId stores that tag in a variable, which a later step's mapping rule can write to Body.bags[type:checked].matchesTag.
Error messages
| The message says | Cause | Remedy |
|---|---|---|
... is not found on ..., followed by a list of names | a segment names no field at that position | copy the path from the tree; check capitalisation, and check that the path came from the step that runs the rule |
... walks through '<field>', a collection ... without saying which element | the path continues past a collection with no selector | add [0] or [type:…], or end the path at the collection to take it whole |
[type:'<tag>'] names no variant of '<field>'. The values it does declare: … | the tag belongs to no kind this collection can hold | use one of the listed tags |
[type:'<tag>'] is ambiguous | two declared kinds share the tag | address the item by position |
... carries an index, but '<field>' is a … which holds no elements | a selector was applied to a single field | remove the selector |
Scope
A path is read against the object of one step, and the same field can sit at a different depth elsewhere. A test step's request is wrapped in an envelope, so its fields sit below a step-specific prefix, while the Playground and a saved request expose the parts of the message directly. A path that works in one of those may need a prefix, or lose one, in the other. Take the path for a mapping rule from the step that will run the rule.
Not supported
- Keyed maps. A field defined as "any key with a value" cannot be addressed key by key:
Body.extras.someKeyfails. Edit that region as text, or declare the keys in the definition. - Arrays of arrays.
Body.matrix[0][1]does not select the second item of the first inner list; the second bracket is not applied. Use a script step for this shape. - Regions kept as text. Where a definition is too open for Aethrix to build a field tree, that part of the message is shown and edited as text, and has no paths.
- Fields outside the definition. A path cannot name a field the service description does not declare, even if a live payload contains it.
- Operations with no response model. An object-path assertion on such an operation reports that there is no model to read, because the transport returns the raw message rather than an object.