7.1 KiB
fid REST API (v1)
Token-based JSON REST API for the fid inventory app, modeled after ppb/archive's API. Base URL:
https://fid.fhi.mpg.de/api/v1/<command>[/<id>]
Requests are POST with a JSON body (except where noted GET also works).
Responses are always JSON with a success field (1 or 0); on failure
there's also an error field. HTTP status codes are set as well (200 on
success, 401/403/404/503 on the various failure cases) but success is the
authoritative field to check.
Unlike the archive API, fid's device table already has descriptive column
names (f_name, l_type, f_mac, ...) instead of a generic f0..f31
scheme, so there's a single get/fields shape — no getraw equivalent
needed. fid also has no per-entry file attachments, so there are no
upload/download endpoints.
Authentication
login performs an LDAP simple bind against 141.14.132.180:389
(uid=<user>,ou=people,dc=ppb,dc=rz-berlin,dc=mpg,dc=de) — the same
mechanism the web login uses. The user must also exist in the local user
table (for role/grp), same requirement as the web UI. Tokens are random
64-char hex strings stored in the api_token table with a 24h expiry.
login
curl -s -X POST -d '{"user":"USER","password":"PASSWORD"}' https://fid.fhi.mpg.de/api/v1/login
{ "success": 1, "token": "64-char-hex-token" }
renew
Issues a new token and invalidates the old one.
curl -s -X POST -d '{"token":"TOKEN"}' https://fid.fhi.mpg.de/api/v1/renew
{ "success": 1, "token": "new-64-char-hex-token" }
Every other endpoint below requires "token":"TOKEN" in the request body.
Reading
list
Ids of all active (non-deleted) devices.
curl -s -X POST -d '{"token":"TOKEN"}' https://fid.fhi.mpg.de/api/v1/list
{ "success": 1, "ids": [19, 21, 27, "..."] }
Optionally pass "columns":["f_name","f_ip",...] to get partial device
records instead of bare ids — only the requested columns (plus id) are
selected, so a caller building a table over every device doesn't have to
pull all ~30 columns for each row:
curl -s -X POST -d '{"token":"TOKEN","columns":["f_name","f_ip"]}' https://fid.fhi.mpg.de/api/v1/list
{ "success": 1, "devices": [{"id":"19","f_name":"twilightzone","f_ip":"141.14.142.157"}, "..."] }
get
Full device record(s). Ids as a comma-separated list in the URL, or as an array in the body.
curl -s -X POST -d '{"token":"TOKEN"}' https://fid.fhi.mpg.de/api/v1/get/40
curl -s -X POST -d '{"token":"TOKEN","ids":[40,41]}' https://fid.fhi.mpg.de/api/v1/get
{
"success": 1,
"devices": [
{
"id": "40",
"user": "ropers",
"grp": "ppb",
"rm": "0",
"f_name": "buntfink",
"l_dep": "3",
"f_os": "None",
"f_mac": "00:04:00:9a:87:10",
"...": "... (all device columns)"
}
]
}
search
Same substring/regex search across text fields as the web UI's search box.
Also accepts the same optional "columns":[...] as list, returning
matching devices instead of bare ids.
curl -s -X POST -d '{"token":"TOKEN","key":"mina"}' https://fid.fhi.mpg.de/api/v1/search
{ "success": 1, "ids": [104, 244, 1723] }
types / departments
Value lists for the l_type / l_dep select fields.
curl -s -X POST -d '{"token":"TOKEN"}' https://fid.fhi.mpg.de/api/v1/types
{ "success": 1, "types": [{"id":"1","name":"Desktop"}, {"id":"2","name":"Server"}] }
curl -s -X POST -d '{"token":"TOKEN"}' https://fid.fhi.mpg.de/api/v1/departments
{ "success": 1, "departments": [{"id":"1","name":"AC"}, {"id":"2","name":"CP"}] }
vlans
Value list for the l_vlan select field.
curl -s -X POST -d '{"token":"TOKEN"}' https://fid.fhi.mpg.de/api/v1/vlans
{ "success": 1, "vlans": [{"id":"10","name":"FHI"}, {"id":"400","name":"GNZ"}] }
fields
Column metadata for the device table (name, input type, whether it's
mandatory on new). Key order in the JSON object is the DB column order
(same as the web UI's edit form) - the CLI's interactive form relies on it
for field layout.
curl -s -X POST -d '{"token":"TOKEN"}' https://fid.fhi.mpg.de/api/v1/fields
{
"success": 1,
"fields": {
"f_name": { "name": "Name", "type": "text", "mandatory": 1 },
"l_dep": { "name": "Department", "type": "select", "mandatory": 1 },
"c_selfadmin": { "name": "Self Admin", "type": "checkbox", "mandatory": 0 }
}
}
Writing
Requires role <= 2 (same restriction edit.php applies to the whole app
for the web UI). Field validation mirrors edit.php: on new, f_name,
l_dep, f_os and f_contact are mandatory; f_ip (must be in
172.16.0.0/12, 141.14.128.0/20, 10.0.0.0/8 or 141.14.248.0/23),
f_mac (aa:bb:cc:dd:ee:ff) and f_acquisition (mm.dd.yyyy) are format-
checked when present. edit only validates/updates the fields you actually
send (partial update), unlike the web form which always resubmits every
field.
new
curl -s -X POST -d '{"token":"TOKEN","f_name":"newhost","l_dep":1,"f_os":"Linux","f_contact":"Mike"}' https://fid.fhi.mpg.de/api/v1/new
{ "success": 1, "id": 4701 }
Ownership (user/grp columns) defaults to the logged-in user; only
role 0 (admin) can set them explicitly via "user":"...","grp":"...".
edit
curl -s -X POST -d '{"token":"TOKEN","f_comment":"replaced disk"}' https://fid.fhi.mpg.de/api/v1/edit/4701
{ "success": 1, "id": 4701 }
Same access rule as the web UI's chkaccess(): role 0 can edit anything,
role 1 anything in their own user/group, role 2 only their own entries,
role >2 nothing.
delete / recover
Soft-delete (sets rm=1) / undelete (rm=0) — same as the web UI, no hard
delete via the API.
curl -s -X POST -d '{"token":"TOKEN"}' https://fid.fhi.mpg.de/api/v1/delete/4701
curl -s -X POST -d '{"token":"TOKEN"}' https://fid.fhi.mpg.de/api/v1/recover/4701
{ "success": 1, "id": 4701 }
Implementation notes
- Router: Apache
RewriteRuleinconfig/fid-apache.confmaps/api/v1/<cmd>[/<id>]to/api/v1.php?cmd=<cmd>&idparam=<id>. - Handler:
api/v1.php— self-contained, usesmysqliwith prepared statements throughout (does not use the app's legacymysql_*compat shim, despite that being auto-prepended for the rest of the app). - Tokens live in a new
api_tokentable (token,user,role,grp,created,expires) in thefiddatabase. - Not implemented / known limitations: no rate limiting, no per-token
scoping beyond role/user/grp, no audit log of API writes,
get/listonly return active (rm=0) devices (no way to fetch deleted ones via the API yet). - The
devicetable's text is a mix of genuine latin1 bytes and (from years of inconsistent form submissions) UTF-8 bytes stored raw in a latin1 column —json_encode()requires valid UTF-8 and silently returnsfalse(i.e. an empty response body, no error) if it isn't.respond()runs every string throughfix_utf8()first, which leaves already-valid UTF-8 alone and reinterprets everything else as latin1. Found vialistwithcolumnsreturning an empty body for the full (~3000 row) result set.