guides

getting started

curl it and follow the links

getting started

gnu.foo is a hypermedia api — curl it and follow the links.

the root

curl gnu.foo

gnu.foo proxies cli requests to api.gnu.foo — use either. browser requests serve the web ui, cli clients get plain text. all api urls below work with both domains.

every response includes _links with available actions — no docs needed to navigate. that's the point of hypermedia.

using tools

tools take positional args as path segments:

curl gnu.foo/tools/base64/encode/hello-world

pipe stdin:

echo "hello world" | curl -d @- gnu.foo/tools/base64/encode

hit a tool with no args for its help text:

curl gnu.foo/tools/base64

content negotiation

the api detects your client from the User-Agent header:

client format
curl, wget, httpie plain text with action hints
everything else hal+json with hypermedia links

override detection with the accept header or ?json query param:

curl -H "Accept: application/json" gnu.foo/tools
curl gnu.foo/tools?json

supported media types: application/json, application/hal+json, application/vnd.hal+json. requesting something else from a non-cli client returns 406.

auth

all read endpoints and tool execution are public — no auth needed.

routes not explicitly public default to requiring authentication via one of:

  • api keyX-API-Key header
  • session — better auth session (cookie or bearer token via /api/auth)

see authentication for details.

http methods

method purpose
GET retrieve resources, browse collections
POST execute tools, create resources
PUT full resource replacement
PATCH partial update
DELETE remove resources

errors

errors follow rfc 9457 problem details. every error includes a resolvable type uri, status code, and hal _links:

{
  "type": "https://api.gnu.foo/errors/not-found",
  "title": "not found",
  "status": 404,
  "detail": "the requested resource does not exist.",
  "_links": { "self": { "href": "/tools/nonexistent" } }
}

the error type uri resolves to its definition — curl gnu.foo/errors/not-found returns what the error means and an example response.

common status codes:

status meaning
400 bad request — malformed body or missing fields
401 unauthorized — auth required but not provided
403 forbidden — insufficient permissions or scopes
404 not found
406 not acceptable — unsupported media type
409 conflict — resource already exists
412 precondition failed — etag mismatch
429 rate limit exceeded — check Retry-After header
500 server error

conditional requests and caching

the api supports etag-based caching. responses include Cache-Control and ETag headers:

curl -H "If-None-Match: W/\"abc\"" gnu.foo/tools

a 304 Not Modified means nothing changed — use your cached copy.

tips

curl -s gnu.foo/tools | jq         # format json
curl -I gnu.foo/tools              # headers only
curl -v gnu.foo/tools              # verbose