--- # Library API Documentation - Manual API Docs Example | Oxidoc (lib/index) --- title: Library API Documentation - Manual API Docs Example | Oxidoc description: Example of writing manual API documentation with Oxidoc. Create library reference pages with full control over layout alongside auto-generated OpenAPI docs. --- # Library API Documentation This section demonstrates how to write **manual API documentation** using Oxidoc. Unlike the auto-generated [API Reference](/api) which parses an OpenAPI spec, manual API docs give you full control over the content and layout. Manual API docs are ideal for: - Libraries and packages (Rust crates, npm packages, Python modules) - Projects with only a few endpoints that don't need a full OpenAPI spec - Internal tools where you want richer explanations than a spec provides - SDK documentation with code examples in multiple languages ## How It Works This entire `/lib` section lives in a separate `lib/` content directory — independent from the main `docs/` directory. Oxidoc supports multiple content directories, each with its own sidebar and URL path. Here is the config that powers this section: [routing] header_links = [ { label = "Docs", href = "/" }, { label = "Lib", href = "/lib" }, { label = "API", href = "/api" }, ] navigation = [ { path = "/", dir = "docs", groups = [...] }, { path = "/lib", dir = "lib", groups = [ { group = "Library API", pages = [ "index", "manual-api", "library-example", ] }, ] }, { path = "/api", openapi = "./openapi.yaml" }, ] Key points: - `dir = "lib"` tells Oxidoc to scan the `lib/` directory for `.rdx` files - Each content directory gets its own sidebar navigation - Search works across **all** sections — docs, lib, and API pages are all searchable together - You can add as many content directories as you need Learn how to write API documentation manually in RDX. A complete example documenting a library's public API. --- # Writing Manual API Docs - Hand-Crafted References (lib/manual-api) --- title: Writing Manual API Docs - Hand-Crafted References description: Learn how to write manual API documentation in Oxidoc using RDX components. Create structured reference pages with code examples and parameter tables. --- # Writing Manual API Docs When your project doesn't have an OpenAPI spec — or when you want more control over how your API is presented — you can write API documentation manually using RDX components. This page shows the patterns you can use. ## Documenting an Endpoint Use a combination of headings, code blocks, tables, and callouts to describe each endpoint clearly. Here is a complete example of a single endpoint documented manually: --- ### `POST /api/users` Stable Create a new user account. **Parameters** | Parameter | Type | Required | Description | |:----------|:-----|:---------|:------------| | `name` | string | Yes | The user's display name | | `email` | string | Yes | Email address | | `role` | string | No | Role assignment (default: `"member"`) | **Request body** ```json { "name": "Alice", "email": "alice@example.com", "role": "admin" } ``` **Response (201 Created)** ```json { "id": 42, "name": "Alice", "email": "alice@example.com", "role": "admin", "created_at": "2025-01-15T10:30:00Z" } ``` **Code examples** ```bash curl -X POST https://api.example.com/api/users \ -H "Content-Type: application/json" \ -d '{"name": "Alice", "email": "alice@example.com"}' ``` ```javascript const response = await fetch("https://api.example.com/api/users", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ name: "Alice", email: "alice@example.com" }), }); ``` ```python import requests response = requests.post( "https://api.example.com/api/users", json={"name": "Alice", "email": "alice@example.com"}, ) ``` This endpoint requires a valid API key in the `Authorization` header. --- ## Patterns Used Above The example above uses these RDX features — all of which you can see in action on this page: - **Headings** with inline code for the method and path - **Badge** component to show endpoint status (Stable, Beta, Deprecated) - **Tables** for parameters - **Fenced code blocks** for request/response JSON - **Tabs** for multi-language code examples - **Callout** for authentication notes ## Organizing API Docs For larger APIs, use sidebar groups to organize endpoints by resource: { path = "/lib", dir = "lib", groups = [ { group = "Overview", pages = ["index"] }, { group = "Users", pages = ["users/create", "users/list", "users/get"] }, { group = "Projects", pages = ["projects/create", "projects/list"] }, ] } Each page in `lib/users/create.rdx` documents one endpoint or a closely related set of endpoints. ## Tips Use Badge components to mark endpoint status: Stable Beta Deprecated Use Callout blocks to highlight authentication requirements, rate limits, or other important notes that apply to specific endpoints. --- # Library API Example - Sample Reference Page (lib/library-example) --- title: Library API Example - Sample Reference Page description: A complete example of documenting a library's public API with Oxidoc. Demonstrates function signatures, parameter tables, and interactive code samples. --- # Library API Example This page shows a complete example of documenting a library's public API using manual RDX documentation. We'll document a fictional `oxidoc-store` key-value storage library. --- ## oxidoc-store A fast, typed key-value store for Rust applications. cargo add oxidoc-store --- ## `Store::new` Create a new in-memory store. use oxidoc_store::Store; let store = Store::new(); | Parameter | Type | Description | |:----------|:-----|:------------| | _(none)_ | — | Creates an empty store with default settings | **Returns:** `Store` — A new store instance. --- ## `Store::with_capacity` Create a store with pre-allocated capacity. let store = Store::with_capacity(1000); | Parameter | Type | Description | |:----------|:-----|:------------| | `capacity` | `usize` | Number of entries to pre-allocate | **Returns:** `Store` — A new store with the given capacity. Use `with_capacity` when you know the approximate number of entries to avoid reallocations. --- ## `Store::set` Stable Insert or update a key-value pair. store.set("user:1", User { name: "Alice", age: 30 }); | Parameter | Type | Description | |:----------|:-----|:------------| | `key` | `&str` | The key to store under | | `value` | `impl Serialize` | The value to store (must implement `serde::Serialize`) | **Returns:** `Option` — The previous value if the key already existed, or `None`. --- ## `Store::get` Stable Retrieve a value by key. let user: Option = store.get("user:1"); | Parameter | Type | Description | |:----------|:-----|:------------| | `key` | `&str` | The key to look up | **Returns:** `Option` — The value deserialized to type `T`, or `None` if not found. --- ## `Store::delete` Remove a key-value pair. let removed: bool = store.delete("user:1"); | Parameter | Type | Description | |:----------|:-----|:------------| | `key` | `&str` | The key to remove | **Returns:** `bool` — `true` if the key existed and was removed. --- ## `Store::list` Beta List all keys matching a prefix. let user_keys: Vec = store.list("user:"); | Parameter | Type | Description | |:----------|:-----|:------------| | `prefix` | `&str` | Key prefix to filter by | **Returns:** `Vec` — All keys starting with the given prefix. --- ## `Store::persist` New Save the store to disk. store.persist("./data/store.bin")?; | Parameter | Type | Description | |:----------|:-----|:------------| | `path` | `impl AsRef` | File path to write to | **Returns:** `Result<()>` — Error if the file cannot be written. `persist` acquires an exclusive file lock. Do not call from multiple processes simultaneously. --- ## `Store::load` Load a store from a previously persisted file. let store = Store::load("./data/store.bin")?; | Parameter | Type | Description | |:----------|:-----|:------------| | `path` | `impl AsRef` | File path to read from | **Returns:** `Result` — The restored store, or an error if the file is missing or corrupt. --- ## Full Example use oxidoc_store::Store; use serde::{Serialize, Deserialize}; fn main() -> Result<(), Box> { let store = Store::new(); // Insert data store.set("config:theme", "dark"); store.set("config:lang", "en"); // Retrieve let theme: Option = store.get("config:theme"); println!("Theme: {:?}", theme); // List by prefix let configs = store.list("config:"); println!("Config keys: {:?}", configs); // Persist to disk store.persist("./app.store")?; Ok(()) }