HTTP API of globus-ilias-rest — a REST service for POPCORN → ILIAS synchronization.
The service is implemented with Fastify in app.js and starts onsettings.port (default 4101). The active config is settings.$NODE_ENV.json
(see settings.js).
http://<host>:4101
In production the service is usually served behind a reverse proxy, e.g.https://globusfm-dev2.minervis.com/popcorn.
Every request must pass the auth token as a query parameter:
?token=<authtoken>
authtoken is defined in settings.$NODE_ENV.json.
Requests without a valid token are rejected with 403 after a 500 ms delay
(anti brute-force / DoS measure):
{ "status": "error", "error": "access denied" }
Exceptions that do not require a token:
/api/version/ui/ (static frontend)Most error responses use a consistent shape:
{ "status": "error", "msg": "not found" }
Some routes use message or error instead of msg; this is noted per route.
| Method | Path | Auth | Purpose |
|---|---|---|---|
| GET | /api/version |
no | Service version |
| GET | /api/search/user |
yes | Search users (returns usr_ids) |
| POST | /api/search/reindex |
yes | Rebuild the user search index |
| GET | /api/user |
yes | List/search users (paged) |
| GET | /api/user/count |
yes | Total number of (numeric-login) users |
| GET | /api/user/login/:login |
yes | Get one user by login |
| GET | /api/user/userid/:userid |
yes | Get one user by usr_id |
| GET | /api/user/teilnahmen/:userId |
yes | Memberships of a user |
| POST | /api/user |
yes | Import/create a user in ILIAS |
| DELETE | /api/user/:usr_id |
yes | Delete a user in ILIAS |
| GET | /api/ref_id/:ref_id |
yes | Resolve ref_id → obj_id |
| GET | /api/obj_id/:obj_id |
yes | Resolve obj_id → ref_id |
| GET | /api/kurs |
yes | List all courses |
| GET | /api/kurs/:refId |
yes | Get one course |
| GET | /api/kurs/items/:refId |
yes | Course item tree (recursive) |
| GET | /api/kurs/:refId/teilnehmer |
yes | Course members |
| GET | /api/kurs/:refId/teilnehmer/:userId |
yes | Single course member |
| GET | /api/kurs/:refId/lp |
yes | Learning progress |
| GET | /api/kurs/:refId/teilnehmerByRole |
yes | Course members via role |
| GET | /api/kurs/:refId/roles |
yes | Roles assigned in a course |
| POST | /api/kurs/:refId/status/:usrId |
yes | Set status + passed for a member |
| GET | /api/kurs/:refId/offline |
yes | Get offline flag of a course |
| POST | /api/kurs/:refId/offline |
yes | Set offline flag of a course |
| DELETE | /api/kurs/:refId/teilnehmer/:usrId |
yes | Unenroll a member (abmelden) |
| GET | /api/kurs/rolle/admin |
yes | Courses with admin role |
| GET | /api/kurs/rolle/noadmin |
yes | Courses without assigned admin role |
| GET | /api/ping |
yes | Ping the ILIAS PHP component |
| GET | /ui/* |
no | Built Vue frontend (SPA) |
Returns the service version from package.json. No token required.
Response 200
{ "version": "0.1" }
Pings the custom ILIAS PHP component (lib/libIlias.js → ping).
Response 200 — forwarded from the PHP component, e.g.
{ "method": "GET", "command": "ping", "status": "ok" }
Response 500
{ "status": "error", "error": "<error>" }
Full-text search over the user index (lib/search.js, FlexSearch). The index is
built from login firstname lastname institution department.
Query parameters
| Name | Required | Description |
|---|---|---|
search |
yes | Search term |
Response 200 — array of matching usr_ids (numbers):
[ 23300, 23301 ]
Response 422 — when search is missing:
{ "status": "error", "msg": "no search" }
Rebuilds the user search index from the database.
Response 200
{ "status": "ok", "msg": "reindexed in 231 ms" }
Paged list / search of users.
Query parameters
| Name | Default | Description |
|---|---|---|
offset |
0 |
Offset |
limit |
10 |
Max results |
search |
— | Optional search term (uses the search index) |
Response 200
{
"total": 11066,
"offset": 0,
"limit": 10,
"data": [
{
"usr_id": 23300,
"login": "134942",
"firstname": "Aksana",
"lastname": "Donhauser",
"gender": "f",
"email": "alex@minervis.com",
"institution": "Globus Baumarkt St. Wendel",
"street": "",
"city": "",
"zipcode": "",
"country": "",
"department": "MITARBEITER | FARBEN/TAPETEN/BODENBEL.",
"active": 1
}
]
}
Only users whose
loginis numeric (login REGEXP '^[0-9]+$') are returned.
If the query fails, an empty result is returned:{ "total": 0, "offset": 0, "limit": 0, "data": [] }.
Total number of users (numeric login). Uses db.getUserCount() without filters.
Response 200
11066
Get a single user by login.
Path parameters
| Name | Description |
|---|---|
login |
ILIAS login |
Response 200 — user object (same fields as /api/user) plus all user-defined
fields merged in as top-level keys.
Response 404
{ "status": "error", "msg": "not found" }
Get a single user by usr_id.
Path parameters
| Name | Description |
|---|---|
userid |
numeric usr_id |
Response 200 — user object incl. user-defined fields.
Response 404 — { "status": "error", "msg": "not found" }
Response 500 — if userid is missing or not numeric:
{ "status": "error", "msg": "userid error" }
Memberships of a user (rows from obj_members with member = 1), enriched with
object title and learning-progress status.
Path parameters
| Name | Description |
|---|---|
userId |
numeric usr_id |
Response 200 — array of
[
{
"obj_id": 32212,
"ref_id": 213,
"usr_id": 6,
"title": "112 Feuerwehr ist da",
"status": 2,
"passed": 1,
"status_changed": "2025-07-03T11:26:20.000Z"
}
]
Response 500 — invalid userId: { "status": "error", "msg": "userId error" }
Import (create/update) a user in ILIAS via the custom PHP component.
Body (JSON) — POPCORN/SOAP-style user object:
{
"login": "123456789",
"passwd": "123456789",
"passwd_type": "plain",
"firstname": "Adolfo",
"lastname": "de la Cruz",
"email": "alex@example.com",
"gender": "m",
"department": "Bananenpflücker",
"institution": "Globus Budapest",
"role": 4,
"udf": {
"Markt": "Markt UDF 2",
"Marktnummer": "Marktnummer UDF 2",
"Personalnummer": "Personal UDF 2"
}
}
The keys of udf are user-defined-field names; they are mapped to field ids
via udf_definition before the request is forwarded to ILIAS.
Response 200 — result forwarded from the PHP component.
If a
udfkey does not match a defined field name, the request fails
(udfMap[key]isundefined).
Delete a user in ILIAS.
Path parameters
| Name | Description |
|---|---|
usr_id |
numeric usr_id |
Response 200 — result forwarded from the PHP component.
Response 500 — invalid usr_id: { "status": "error", "msg": "userId error" }
Resolve a ref_id (tree/reference id) to an obj_id.
Response 200
{ "ref_id": 213, "obj_id": 32212 }
Response 404 — { "status": "error", "msg": "not found" }
Resolve an obj_id to a ref_id.
Response 200
{ "ref_id": 213, "obj_id": 32212 }
Response 404 — { "status": "error", "msg": "not found" }
List all courses (type = 'crs', not deleted).
Response 200 — array of
[
{
"ref_id": 213,
"obj_id": 32212,
"title": "112 Feuerwehr ist da",
"description": "...",
"type": "crs",
"offline": 0
}
]
Get a single course by ref_id.
Response 200 — single object
{
"ref_id": 213,
"obj_id": 32212,
"title": "112 Feuerwehr ist da",
"description": "...",
"type": "crs",
"create_date": "2024-01-01 00:00:00",
"offline": 0
}
Response 404 — { "status": "error", "msg": "not found" }
Recursive tree of items contained in a course (crs_items, recursive CTE).
Response 200 — array of
[
{ "parent_id": 213, "obj_id": 36450, "ref_id": 597, "title": "asdf123", "type": "tst" }
]
Response 404 — { "status": "error", "msg": "not found" }
Course members.
Response 200 — array of
[
{
"parent_id": 213,
"ref_id": 597,
"obj_id": 36450,
"title": "asdf123",
"type": "tst",
"usr_id": 6,
"login": "root",
"firstname": "root",
"lastname": "user",
"active": 1,
"passed": 1,
"status": 2,
"status_changed": "2025-10-22T07:42:36.000Z"
}
]
Response 404 — { "status": "error", "msg": "not found" }
Single course member.
Response 200 — single member object (same fields as above).
Response 404 — { "status": "error", "msg": "not found" }
Learning progress of a course.
Query parameters
| Name | Description |
|---|---|
raw |
If present (any non-empty value, e.g. ?raw=1), returns raw sub-object rows instead of the aggregated view |
Response 200 (raw) — one row per tracked sub-object and user:
[
{
"usr_id": 6,
"login": "root",
"firstname": "root",
"lastname": "user",
"obj_id": 32212,
"item_id": 597,
"lpmode": 5,
"item_obj_id": 36450,
"type": "tst",
"status": 2,
"status_changed": "2025-10-22T07:42:36.000Z",
"percentage": 100,
"completed": 0
}
]
Response 200 (aggregated) — one row per user, sub-object statuses combined
via lib/libLp.js:
[
{
"usr_id": 6,
"login": "root",
"firstname": "root",
"lastname": "user",
"status": 1,
"status_changed": "2025-10-22T09:45:56.000Z"
}
]
status values:
| Value | Meaning |
|---|---|
0 |
not attempted (noch nicht bearbeitet) |
1 |
in progress (in Bearbeitung) |
2 |
passed (bestanden) |
3 |
failed (nicht bestanden) |
Response 404 — { "status": "error", "msg": "not found" }
Course members resolved through the course's member role
(rbac_ua joined via the role whose description matches Member%<obj_id>).
Response 200 — array of
[ { "role_id": 12345, "usr_id": 6, "firstname": "root", "lastname": "user" } ]
Roles assigned in a course (rbac_pa).
Response 200 — array of
[
{
"rol_id": 12345,
"ref_id": 213,
"obj_id": 999,
"type": "role",
"title": "il_crs_member_32212",
"description": "Member of course 32212"
}
]
Set the learning-progress status and passed flag for a course member. Writes
both ut_lp_marks (status + status_changed) and obj_members (passed).
Path parameters
| Name | Description |
|---|---|
refId |
course ref_id |
usrId |
user usr_id |
Body (JSON) — both fields required
{ "passed": 1, "status": 2 }
Response 200
{ "status": "ok" }
Response 400 — missing arguments:
{ "status": "error", "msg": "argument error", "statusCode": 400 }
Response 500 — e.g. when the affected rows don't match:
{ "status": "error", "msg": "<message>" }
Get the offline flag of a course.
Response 200
{ "offline": 0 }
Response 500
{ "status": "error", "message": "<message>" }
Set the offline flag of a course.
Body (JSON)
{ "offline": 1 }
Response 200
{ "offline": 1 }
Response 500
{ "status": "error", "message": "<message>" }
Unenroll a member ("abmelden") via the custom PHP component.
Path parameters
| Name | Description |
|---|---|
refId |
course ref_id |
usrId |
user usr_id |
Response 200 — result forwarded from the PHP component.
Response 404 — { "status": "error", "msg": "Teilnahme not found" }
Response 500 — { "status": "error", "msg": "<message>" }
Courses that have an admin role assigned (role title contains admin).
Response 200 — array of
[
{
"crs_obj_id": 32212,
"crs_ref_id": 213,
"crs_title": "112 Feuerwehr ist da",
"rol_id": 12345,
"role": "il_crs_admin_32212"
}
]
Response 500 — { "status": "error", "error": "<error>" }
Courses whose admin role exists but has no user assigned (no rbac_ua entry).
Response 200 — same shape as /api/kurs/rolle/admin.
Response 500 — { "status": "error", "error": "<error>" }
Serves the built Vue single-page app from vue/dist (registered with@fastify/static, prefix /ui/). No token required.
Any route that does not match an API route or a static file returns the SPA
fallback vue/dist/index.html.