A RESTCONF dashboard pulls 40 MB of interface data to show one counter per interface; what do depth and fields each cut?
answer
- one prunes by level, one by name
- the target itself is level 1
- semicolons and parentheses select nodes
- paths below a list need every key
- both advertised as capability URIs
basics
~20 sRESTCONF's depth prunes by level: counting the target as level 1, nodes deeper than level N are dropped, whatever their names. fields prunes by name: fields=interface(name;statistics/in-octets) returns just those nodes for every entry. Both are optional, advertised capabilities.
solid answer
~40 s`depth` and `fields` prune a GET along different axes. `depth` counts levels from the target, which is level 1, and drops anything deeper; it cannot tell one leaf from another, so a `depth` large enough to reach `in-octets` also returns every other leaf at or above that level for every interface. `fields` prunes by name: on `ietf-interfaces:interfaces`, `fields=interface(name;statistics/in-octets)` returns only each entry's key and one counter — `;` separates selections, parentheses hold sub-selectors and `/` steps to a child. For one interface, a URI that addresses the leaf is simpler, but a RESTCONF path below a list must name every key, so only `fields` can take one leaf from every entry. Both are optional: look for `urn:ietf:params:restconf:capability:fields:1.0` and `depth:1.0` in the server's capability list, because an unexpected parameter draws `400 Bad Request`.
code
http · 8 linesGET /restconf/data/ietf-interfaces:interfaces?depth=1 HTTP/1.1
Host: core1.example.net
Accept: application/yang-data+json
HTTP/1.1 200 OK
Content-Type: application/yang-data+json
{"ietf-interfaces:interfaces": {}}go deeper
Recall that RESTCONF can trim a GET, that depth limits how many levels come back, and that fields picks named nodes.
Explain level counting from the target, the fields grammar with semicolons, parentheses and slashes, and why a path cannot take one leaf from every list entry.
Size the cost of an untrimmed poll, pick fields over depth for per-entry counters, and build capability discovery with a fallback into the client.
Treat retrieval shape as part of the telemetry design: decide when polling with fields is enough and when the device's management plane should not be polled at all.
## The failure being fixed A dashboard tile shows the inbound byte counter of every interface on a core router. It polls `GET /restconf/data/ietf-interfaces:interfaces` with no query parameters, and on a router with hundreds of interfaces and many augmenting modules the reply runs to tens of megabytes. Polled every 10 seconds, a 40 MB reply is 4 MB/s — 32 Mbit/s of management traffic — plus the device CPU spent serialising it, for a tile that needs one number per row. RFC 8040 gives a client two retrieval parameters to prevent exactly this, and they cut in different dimensions. ## depth — prune by level The **`depth`** parameter (RFC 8040 §4.8.2) limits how far below the target the reply descends: - the **target resource is level 1**; each child is one level deeper than its parent; - nodes with a level greater than `depth` are left out of the reply; - the value is an integer from 1 to 65535 or the string `unbounded`, which is the default; - it is allowed on `GET` for the API, datastore and data resources, and draws `400 Bad Request` anywhere else. For `ietf-interfaces:interfaces` the levels are: `interfaces` (1), each `interface` entry (2), the entry's own leaves and the `statistics` container (3), the counters inside `statistics` (4). `depth=3` returns every interface's name, description, enabled flag, status and speed with `statistics` present but empty; `depth=4` finally reaches `in-octets` — together with every other counter and every other level-3 node. Depth **cannot select by name**. Its real uses are different: `depth=1` answers "does this resource exist?" (the RFC's own example), and a small depth shows the shape of an unfamiliar tree without its bulk. ## fields — prune by name The **`fields`** parameter (§4.8.3) names the descendants to keep, and the server returns the target resource with everything else pruned — one message body, not a set of separate resources. Its grammar is short: | Syntax | Meaning | Example on `interfaces` | |---|---|---| | `a;b` | select several nodes | `fields=interface(name;enabled)` | | `a(b;c)` | sub-selectors under `a`, no `/` before `(` | `fields=interface(name;statistics/in-octets)` | | `a/b` | a child of a node | `fields=interface/statistics` | Identifiers follow the same `[module-name ":"] identifier` form as path segments, so a node from an augmenting module carries its module name. Nodes selected by `fields` — and their ancestors — count as level 1 for `depth`, so a small `depth` does not hide what `fields` asked for. ```http GET /restconf/data/ietf-interfaces:interfaces?fields=interface(name;statistics/in-octets) HTTP/1.1 Host: core1.example.net Accept: application/yang-data+json HTTP/1.1 200 OK Content-Type: application/yang-data+json {"ietf-interfaces:interfaces": {"interface": [ {"name": "eth0", "statistics": {"in-octets": "918273645512"}}, {"name": "eth1", "statistics": {"in-octets": "40211877"}} ]}} ``` Selecting `name` explicitly keeps every counter attached to its interface. ## Why not just address the leaf? For a single interface, a URI that names the leaf — `.../interface=eth0/statistics/in-octets` — is the simplest request of all. But a RESTCONF path that descends below a list entry must encode **all** of that entry's keys; partial instance identifiers are not supported (§3.5.3). There is no wildcard key, so "`in-octets` of every interface" cannot be written as one path. That is precisely the case `fields` exists for. ## Optional, so discover first RFC 8040 makes most query parameters optional. `depth` and `fields` each have a capability URI — `urn:ietf:params:restconf:capability:depth:1.0` and `urn:ietf:params:restconf:capability:fields:1.0` — that a supporting server MUST list in the `capability` leaf-list under `ietf-restconf-monitoring:restconf-state/capabilities`. A server MUST answer an unexpected query parameter with `400 Bad Request` and error-tag `invalid-value` (§4.8). So a robust client: 1. reads the capability list once per device; 2. uses `fields` when it is listed; 3. otherwise falls back to direct per-interface leaf URIs, or to `depth` plus `content=nonconfig` to shed configuration. ## Mistakes that survive code review - **Counting depth from the root.** Levels count from the target in the URI, so the same `depth` value means different things on `/data` and on one interface entry. - **Forgetting the key in `fields`.** Selecting only `statistics/in-octets` returns counters; selecting `name` as well is what lets the client say which interface each one belongs to. - **Dropping module prefixes.** A node that another module adds by augmentation carries that module's name in `fields`, just as it does in a path segment. - **Assuming silent tolerance.** An unsupported parameter is an error, not a no-op, so a client built against one server can fail outright on another. - **Mixing names into `depth`.** `depth` takes an integer or `unbounded`; it never takes a node name. ## Putting it together - `depth` = how far down; blind to names. - `fields` = which named nodes; the right tool for one leaf across many entries. - `content` = which half (configuration or state); coarse but mandatory to implement. For the dashboard, `fields=interface(name;statistics/in-octets)` turns a 40 MB poll into a reply of a few tens of kilobytes, and the tile shows the same numbers.
- If a RESTCONF client sends depth=1 together with fields=interface(name), does the depth hide the names?No. RFC 8040 §4.8.2 gives nodes selected by `fields`, and their ancestors, a depth of 1, so they are included even though their real level is deeper. Children of the selected nodes still count normally from there, so `depth` keeps trimming anything beneath the selections.
- How does a RESTCONF client learn whether fields is safe to send to a given device?It reads `ietf-restconf-monitoring:restconf-state/capabilities` and looks for `urn:ietf:params:restconf:capability:fields:1.0`; a supporting server MUST list it. If the URI is absent, sending `fields` risks `400 Bad Request` with `invalid-value`, since an unexpected parameter is an error, not something silently ignored.
- Why does depth=3 on the interfaces container show statistics as an empty object?Levels count from the target: `interfaces` is 1, each `interface` entry 2, the entry's leaves and the `statistics` container 3. The counters inside `statistics` are level 4, deeper than the limit, so the container appears without its children — the same pattern as the empty containers in RFC 8040's own depth example.
depth is like printing a manual's table of contents to three heading levels: you get every heading down to that level, wanted or not. fields is like the index: you name the entries and get exactly those pages from every chapter.
saying these in an interview costs you the question
- depth=2 returns the target and one named leaf beneath it.
- depth counts from the datastore root, not from the target resource.
- fields returns each selected node as a separate resource.
- A list key can be wildcarded in the path to read every entry.
- Every server must support depth and fields, so no discovery is needed.
- A server silently ignores a query parameter it does not support.