Skip to content

docs: make the docs.rs reference usable - #149

Merged
olavgg merged 8 commits into
chore/remove-dead-codefrom
docs/usable-api-reference
Sep 30, 2026
Merged

olavgg merged 8 commits into
chore/remove-dead-codefrom
docs/usable-api-reference

Conversation

@JosteinGj

@JosteinGj JosteinGj commented Sep 23, 2026 •

Copy link
Copy Markdown
Contributor

The rendered API reference opened with about forty lines of raw pub use and no prose at all — nothing saying what the crate is or how to make one call. 19 of 23 modules rendered as a bare name with no description. 34 public types had none either, including DataWrapper, ResponseError, Event, TimeSeries and every service struct.

Judge this by building it rather than by the diff:

cargo doc --no-deps --all-features --open

What changed

A landing page. What the crate is, a runnable create_api_service() example, a table mapping each ApiService field to its module, then the four things a caller hits immediately: the DataWrapper envelope, id-or-externalId, ResponseError and its problem document, and the list/filter/search split.

blocking was absent from docs.rs entirely. With no [package.metadata.docs.rs], docs.rs builds default-features-only — so the README pointed callers at a client the reference never showed. Now all-features = true, and the blocking module doc states up front that it needs the feature, with the Cargo.toml line. (A doc_cfg badge would do the same but needs nightly, so it was left out.)

Every module and every public type described. Service structs get a one-liner pointing at their module doc; entity types carry the fact that is not guessable from the field list — an Event is keyed by UUID and its externalId is deliberately not unique, a TimeSeries value_type is fixed at creation, FileUpload::new panics on an unreadable path.

Plumbing hidden, as one group so no survivor is left referencing a hidden name: ApiServiceProvider, DataWrapperDeserialization, process_response, serde_helper. doc(hidden) rather than pub(crate) — the id-as-string serde adapters are legitimately reusable by a downstream type's own #[serde(with = …)], and hiding does not restrict. GraphNode and Identifiable stay visible on purpose: both appear as bounds in public signatures, where hiding renders them as unclickable bare names.

The 28 remaining service methods documented — datasets.create, events.filter, files.upload_file, timeseries.retrieve_datapoints, the whole units service. Builder setters and field getters are deliberately left alone: a line on set_name saying it sets the name is noise, and there are several hundred.

Four doc comments were contradicting the api

Found while drafting, each checked against the backend source:

  • labels::get said a miss returns empty items. It is a 404.
  • EdgeProxy claimed it is returned from GET /functions, which answers RelatedNode and never populates it.
  • TimeSeries::value_type said graph reads do not carry it. They do now.
  • the subscriptions module is not "CRUD" — there is no update and no get.

labels::delete's documented 400 was checked and left alone: it really is a 400 with fields, not the 409 would-strand that resources and edges answer with. Generalising there would have introduced an error.

CI now runs the doctests

cargo test --no-run does not build doctests at all, so the landing-page example was never compile-checked.

The existing crate job now also runs cargo test --doc, and only that — every other test in this crate needs a live backend, which CI cannot reach. The doctests are the documentation's own examples and are pure construction; confirmed passing with BASE_URL pointed at a dead address and no credentials in the environment.

Numbers

Rustdoc coverage 33.8% → 41.8% (+87 items), zero rustdoc warnings, 248 tests and 7 doctests green.

The 644 still-undocumented items are overwhelmingly builder setters and struct fields. A coverage ratchet was considered and deliberately left out.


Stack, 5 of 5 — based on #148.

Two things this does not do, both deliberate:

  • The three glob re-exports (pub use resources::*, events::*, timeseries::*) stay. They do duplicate items between the crate root and their modules, but removing them breaks use intellistream_datahub_sdk::TimeSeries for every existing caller — that belongs in a release, not a docs pass.
  • Nothing here reaches docs.rs until a tag is pushed. v0.2.0 is still the only one, so the published reference predates the filter refactor, the assets service and the Node type.

Unrelated bug found, not fixed here: GraphDataWrapper::set_http_status_code is pub fn set_http_status_code(&mut self, _status_code: u16) {} — argument discarded, empty body. It is called on both parse paths, so a normal 200 from resources.create, update or edges.by_ids comes back with http_status_code: None. DataWrapper's version stores correctly, so the two wrappers disagree. That is a behaviour fix and wants its own PR.

🤖 Generated with Claude Code

@JosteinGj
JosteinGj force-pushed the refactor/remove-inert-config-and-auth-diagnostics branch from aadb203 to d3cd185 Compare September 24, 2026 09:19
@JosteinGj
JosteinGj force-pushed the docs/usable-api-reference branch from 5124b79 to 55d2041 Compare September 24, 2026 09:19
JosteinGj and others added 6 commits September 24, 2026 11:26
…DME reads

The docs.rs index opened with about forty lines of raw `pub use` and no
prose at all — nothing saying what the crate is or how to make one call.

- a crate-level `//!`: what it is, a runnable `create_api_service()`
  example, a table mapping each `ApiService` field to its module, then the
  four things a caller hits immediately — `DataWrapper`/`GraphDataWrapper`,
  id-or-externalId, `ResponseError` and its problem document, and the
  list/filter/search split.
- `[package.metadata.docs.rs] all-features = true`, so the `blocking`
  client is documented at all. docs.rs builds default-features-only, so a
  feature the README points callers at was absent from the reference.
  `doc_cfg` badges it, guarded by `cfg_attr(docsrs, ...)` so stable builds
  are unaffected.
- clears all five rustdoc warnings. Two were links into private items,
  which render as dead text rather than links: `DEFAULT_SCOPE` pointing at
  `OAuthConfig::effective_scope`, and `set_advanced_filter` at a private
  field. Both now say the thing instead of linking to it.

Verified clean on stable and on nightly with `--cfg docsrs`, which is what
docs.rs runs.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: jgjesdal <jostein@intellistream.ai>
The entry point and the type every caller starts from both had no docs, so
the two most-visited pages in the reference were a bare signature and a list
of bare field names.

`ApiService` now says what it is, that the services share one HTTP client
and token cache so the Arc should be cloned rather than the client rebuilt,
and that one client is one tenant. Each service field links to its module.

`create_api_service` documents what it reads from the environment, carries a
runnable example, and has a Panics section — it calls `from_env().unwrap()`,
so a missing BASE_URL panics at construction rather than on the first call,
and `DataHubConfig::from_env` + `ApiService::new` is the Result-based route.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: jgjesdal <jostein@intellistream.ai>
Nineteen of the twenty-three modules rendered on the docs.rs index as a
bare name with no description, including every service a caller starts
from. Each now says what it is, what it covers, and the one or two things
that will otherwise surprise you — events.list() returning the oldest
events, Function::related_resources always being empty, FileUpload::new
panicking on an unreadable path, a listener closing as idle if it is not
polled.

Hides four items that are public only because the services need them, as
one group so no survivor is left referencing a hidden name:
ApiServiceProvider, DataWrapperDeserialization, process_response and the
serde_helper module. doc(hidden) rather than pub(crate) — serde_helper's
id-as-string adapters are legitimately reusable by a downstream type's
own #[serde(with = ...)], and hiding does not restrict.

GraphNode and Identifiable stay visible deliberately: both appear as
bounds in public signatures, where hiding renders them as unclickable
bare names.

Four doc comments contradicted the api and are corrected here:
- labels::get said a miss returns empty items; it is a 404.
- EdgeProxy claimed it is returned from GET /functions, which answers
  RelatedNode and never populates it.
- TimeSeries::value_type said graph reads do not carry it; they do now.
- the subscriptions module is not "CRUD" — there is no update or get.

labels::delete's documented 400 was checked against the backend and left
alone: it really is a 400 with `fields`, not the 409 `would-strand` that
resources and edges answer with.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: jgjesdal <jostein@intellistream.ai>
Thirty-four public types rendered with no description at all, including the
ones a caller meets first: DataWrapper, ResponseError, Event, TimeSeries,
Resource, Dataset, Unit, Subscription and every service struct.

Service structs get a one-liner pointing at their module doc rather than
repeating it. Entity types say what the thing is and carry the one fact
that is not guessable from the field list — an Event is keyed by UUID and
its externalId is deliberately not unique; a Dataset's connected_data_sets
is input-only; a TimeSeries value_type cannot change after creation;
DatapointString is stringly-typed so a decimal never passes through an f64;
FileUpload::new panics on an unreadable path.

DataWrapper gets the longest entry, since it is the return type of nearly
every call and the "it is also a request body" trick is what makes
`create(&event)` work.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: jgjesdal <jostein@intellistream.ai>
Twenty-eight API calls still had no doc comment, so the reference showed a
bare signature for things like datasets.create, events.filter,
files.upload_file, timeseries.retrieve_datapoints and the whole units
service.

Each now names the endpoint it calls and carries what the signature cannot
say: that events.create stamps a UUID v7 so a retry dedups and can answer
202 when buffering spooled the batch; that resources.delete is refused with
409 would-strand; that files.delete is a soft delete; that
retrieve_datapoints takes a half-open window; that a supplied TOKEN is
never refreshed; that deleting a subscription with a live listener attached
is refused.

Leaves the builder setters and field getters alone. A one-line doc on
`set_name` saying it sets the name is noise, and there are several hundred
of them; the types they hang off are documented instead.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: jgjesdal <jostein@intellistream.ai>
Nothing was checking the documentation, so the two things that make a
reference actively wrong both happened silently.

A broken intra-doc link is not a build failure — rustdoc renders it as
dead text and carries on, so it only shows up on docs.rs, after release.
There were five in the tree before this branch. `-D warnings` on the
rustdoc build turns them into failures.

And the examples were never compiled: CI runs `cargo test --no-run`, which
does not build doctests at all. So the `create_api_service()` example on
the landing page would have rotted the moment a method was renamed, with
nothing to say so.

Only `--doc` is run here. Every other test in this crate needs a live
backend, which CI has no way to reach; the doctests are the documentation's
own examples and are pure construction, verified to pass with BASE_URL
pointed at a dead address and no credentials in the environment.

The doc build uses nightly with `--cfg docsrs` to match what docs.rs
actually runs, since `doc_cfg` — which badges the `blocking` feature — is
nightly-only.

Verified by injecting a broken link: the step exits 101.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: jgjesdal <jostein@intellistream.ai>
@JosteinGj
JosteinGj force-pushed the docs/usable-api-reference branch from 55d2041 to 7522e16 Compare September 24, 2026 09:27
@JosteinGj
JosteinGj force-pushed the refactor/remove-inert-config-and-auth-diagnostics branch from d3cd185 to b0df19e Compare September 24, 2026 09:27
JosteinGj and others added 2 commits September 24, 2026 14:48
…oc that it needs the feature

The doc_cfg badge on `blocking` was the only reason for nightly, in CI and in the docs.rs
rustdoc-args. The module doc now names the feature and shows the Cargo.toml line instead.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: jgjesdal <jostein@intellistream.ai>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: jgjesdal <jostein@intellistream.ai>
Base automatically changed from refactor/remove-inert-config-and-auth-diagnostics to chore/remove-dead-code September 30, 2026 10:41
@olavgg
olavgg merged commit 3bd047f into chore/remove-dead-code Sep 30, 2026
30 checks passed
@olavgg
olavgg deleted the docs/usable-api-reference branch September 30, 2026 10:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants