Add Outline API client library foundation
Implements a first vertical slice of the Outline RPC API (auth, documents, collections, users) covering the structural patterns used across the whole API: single object, paginated list, tree, create/update, delete, search. Chosen as the basis for future CLI and GUI clients built on top of this crate. - Handwritten client (not codegen) against the vendored OpenAPI spec, since Outline's API is uniformly POST /api/<resource>.<action> with JSON bodies and inline/anonymous schemas that generators handle poorly - Async (reqwest + tokio) Client, cheaply cloneable, no &mut self methods - thiserror-based Error with ErrorKind classification and boxed API error context; forward-compatible models (unknown fields ignored, unknown string-enum values preserved via a catch-all variant) since the API is unversioned and self-hosted instances vary in age - Pagination via Page<T>/Paginator with next_page/collect_all/into_stream - wiremock-based test suite plus a spec-coverage test guarding against typos in RPC method names
This commit is contained in:
@@ -0,0 +1,68 @@
|
||||
# outline
|
||||
|
||||
An async Rust client library for the [Outline](https://www.getoutline.com) knowledge base API.
|
||||
|
||||
This crate is the foundation for building Outline clients (CLI, GUI, ...) on
|
||||
top of a shared, well-tested API layer. It only talks to the API — no CLI or
|
||||
GUI code lives here.
|
||||
|
||||
## Quickstart
|
||||
|
||||
```rust,no_run
|
||||
use outline::Client;
|
||||
|
||||
# async fn run() -> outline::Result<()> {
|
||||
let client = Client::new("ol_api_...")?;
|
||||
|
||||
let me = client.auth().info().await?;
|
||||
println!("Signed in as {} ({})", me.user.name, me.team.name);
|
||||
|
||||
let mut documents = client.documents().list().collection_id("col_123").paginate();
|
||||
while let Some(page) = documents.next_page().await? {
|
||||
for document in page.items {
|
||||
println!("{}", document.title);
|
||||
}
|
||||
}
|
||||
# Ok(())
|
||||
# }
|
||||
```
|
||||
|
||||
For a self-hosted instance or an OAuth access token, use [`Client::builder`]:
|
||||
|
||||
```rust,no_run
|
||||
use std::time::Duration;
|
||||
use outline::Client;
|
||||
|
||||
# fn run() -> outline::Result<()> {
|
||||
let client = Client::builder()
|
||||
.base_url("https://wiki.example.com")
|
||||
.access_token("...")
|
||||
.timeout(Duration::from_secs(10))
|
||||
.build()?;
|
||||
# let _ = client;
|
||||
# Ok(())
|
||||
# }
|
||||
```
|
||||
|
||||
## Design notes
|
||||
|
||||
The Outline API is RPC-style: every endpoint is `POST /api/<resource>.<action>`
|
||||
with a JSON body and a `{ok, data, pagination, policies}` envelope. This crate
|
||||
mirrors that with a single internal request primitive; resources are exposed
|
||||
as scoped accessors (`client.documents()`, `client.collections()`, ...).
|
||||
|
||||
Because the API is unversioned and self-hosted instances vary in age, models
|
||||
are deliberately forward-compatible: unknown fields are ignored and unknown
|
||||
string-enum values are preserved rather than causing deserialization to fail.
|
||||
|
||||
## Status
|
||||
|
||||
This crate currently covers a first vertical slice of the API — `auth`,
|
||||
`documents`, `collections`, `users` — chosen to validate the request/response
|
||||
patterns (single object, paginated list, tree, create/update, delete, search)
|
||||
used across the rest of the API. Broader endpoint coverage, automatic retry
|
||||
on rate limiting, and streaming exports are planned but not yet implemented.
|
||||
|
||||
## License
|
||||
|
||||
MIT OR Apache-2.0
|
||||
Reference in New Issue
Block a user