lino-rest-api

lino-rest-api

A REST API framework and client that speak Links Notation instead of JSON, in JavaScript, Python and Rust.

Everything the HTTP standards expect of a REST service — content negotiation, conditional requests, problem details, collection pagination, automatic HEAD/OPTIONS/405, CORS, a service description and an OpenAPI document — is provided out of the box, with LINO as the default wire format and JSON as a fallback.

The three implementations speak the same wire, byte for byte, so a value encoded by any of them carries the same entity tag. That wire is written down in the specification and every package ships its executable form as a conformance suite.

Install

npm install lino-rest-api        # JavaScript, on Node.js or Bun
pip install lino-rest-api        # Python 3.13, any ASGI server
cargo add lino-rest-api          # Rust, on axum

A service in three languages

import { MemoryStore, createLinoApp } from "lino-rest-api";

const app = createLinoApp({ title: "Tasks API", version: "1.0.0" });
app.resource("/tasks", new MemoryStore(), { name: "task" });
app.get("/health", () => ({ status: "ok" }));
app.listen(8000);
from lino_rest_api import MemoryStore, create_lino_app

app = create_lino_app(title="Tasks API", version="1.0.0")
app.resource("/tasks", MemoryStore(), name="task")
app.get("/health", lambda request: {"status": "ok"})
use lino_rest_api::{MemoryStore, ResourceOptions, create_lino_app, object, serve, string};
use std::sync::Arc;

let mut app = create_lino_app();
app.resource("/tasks", Arc::new(MemoryStore::new()), ResourceOptions::new().with_name("task"));
app.get_fn("/health", "Liveness probe", |_request| Ok(object([("status", string("ok"))])));
serve(app, "0.0.0.0:8000").await?;

Each one answers the same request the same way:

curl -H 'Accept: text/lino' http://localhost:8000/tasks/1
(
  title "Write the specification"
  done true
  id 1
)

What you get

Capability Behaviour
Representations text/lino, text/lino-line, text/lino-compact, application/json
Negotiation Accept with quality values, Vary: Accept, 406 and 415 as problem details
Errors RFC 9457 problem details as application/problem+lino
Collections limit, offset, sort, fields, field filters, Link pagination
Conditional requests Strong ETag per representation, 304, 412, 428
Uniform interface Automatic HEAD, OPTIONS with Allow, 405 for a known path
Cross-origin requests Preflight and simple-request CORS, including exposed headers
Description /.well-known/lino-api and /.well-known/openapi.json (OpenAPI 3.1)

Guides

Reference

Case studies

Project

The source, the issue tracker and the releases live on GitHub. The code is released into the public domain under the Unlicense.