Skip to content

Commit 42a5c9c

Browse files
authored
Merge pull request #10 from sensein/claude/schema-registry-meta-model-2upt56
docs: add REST API reference to README
2 parents 3e9f63c + 997eaa0 commit 42a5c9c

1 file changed

Lines changed: 196 additions & 0 deletions

File tree

README.md

Lines changed: 196 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,202 @@ the entire registry, or a CSV diff between two schemas.
9898

9999
---
100100

101+
## API Reference
102+
103+
**Base URL:** `https://sensein.group/NeuroGhost`
104+
105+
The registry exposes two kinds of endpoints:
106+
107+
| Type | Transport | Auth | Status |
108+
|------|-----------|------|--------|
109+
| Read (schemas, alignments, provenance) | Static JSON via GitHub Pages | None | ✅ Live |
110+
| Transform (field mapping between schemas) | Serverless function (planned) | None | 🔜 Planned |
111+
112+
CORS is open on all endpoints. No API key required.
113+
114+
---
115+
116+
### `GET /data/registry.json`
117+
118+
Returns the full registry at the current version: all sources, classes,
119+
properties, and pre-computed cross-schema alignments.
120+
121+
```bash
122+
curl https://sensein.group/NeuroGhost/data/registry.json
123+
```
124+
125+
**Response**
126+
```json
127+
{
128+
"registry_version": "1.7.0",
129+
"generated_at": "2026-07-23T12:40:24Z",
130+
"sources": [
131+
{ "label": "bbqs", "version": "1.0.0", "class_count": 29 },
132+
{ "label": "bids", "version": "1.9.0", "class_count": 1 },
133+
{ "label": "dandi", "version": "0.6.8", "class_count": 20 },
134+
{ "label": "nwb", "version": "2.7.0", "class_count": 53 }
135+
],
136+
"classes": [
137+
{
138+
"uid": "8003dcad-...",
139+
"iri": "https://registry.sensein.io/obj/Subject",
140+
"name": "Subject",
141+
"definition": "A research participant.",
142+
"abstract": false,
143+
"source": "bbqs",
144+
"properties": [
145+
{
146+
"uid": "807f8fec-...",
147+
"name": "age",
148+
"definition": "Age in years.",
149+
"datatype": "xsd:integer",
150+
"multivalued": false,
151+
"required": false,
152+
"source": "bbqs"
153+
}
154+
],
155+
"alignments": [
156+
{
157+
"target_uid": "f4f8e4a4-...",
158+
"target_name": "Participant",
159+
"target_source": "bids",
160+
"distance": 0.12,
161+
"method": "composite",
162+
"scores": { "iri": 0.0, "name": 0.08, "desc": 0.19, "slot": 0.0 }
163+
}
164+
]
165+
}
166+
]
167+
}
168+
```
169+
170+
`distance` ranges from **0.0** (identical) to **1.0** (unrelated).
171+
172+
---
173+
174+
### `GET /data/versions/{version}.json`
175+
176+
Frozen snapshot of the registry at a specific version. Snapshots never change.
177+
178+
```bash
179+
curl https://sensein.group/NeuroGhost/data/versions/1.2.0.json
180+
```
181+
182+
Same shape as `registry.json`. To list available versions, check the
183+
`registry_version` field of the live registry and the `data/versions/`
184+
directory.
185+
186+
---
187+
188+
### `GET /data/provenance.json`
189+
190+
Changelog — every schema ingestion: who submitted it, when, and which registry
191+
version it produced.
192+
193+
```bash
194+
curl https://sensein.group/NeuroGhost/data/provenance.json
195+
```
196+
197+
---
198+
199+
### Client-side filtering
200+
201+
There are no server-side query parameters (static files). Filter in your
202+
client after fetching:
203+
204+
```js
205+
const reg = await fetch("https://sensein.group/NeuroGhost/data/registry.json")
206+
.then(r => r.json());
207+
208+
// All classes from one schema
209+
const bbqs = reg.classes.filter(c => c.source === "bbqs");
210+
211+
// Close alignments across any two schemas (distance < 0.35)
212+
const pairs = reg.classes.flatMap(c =>
213+
c.alignments
214+
.filter(a => a.distance < 0.35)
215+
.map(a => ({ from: `${c.source}/${c.name}`, to: `${a.target_source}/${a.target_name}`, distance: a.distance }))
216+
);
217+
```
218+
219+
---
220+
221+
### `GET /api/transform` — field mapping *(planned)*
222+
223+
Returns the computed field-to-field mapping between two schemas, derived from
224+
the alignment graph. No data is sent — this is purely a schema-level lookup.
225+
226+
```
227+
GET /api/transform?from=bbqs&to=bids
228+
```
229+
230+
**Planned response**
231+
```json
232+
{
233+
"from": "bbqs",
234+
"to": "bids",
235+
"mappings": [
236+
{
237+
"from_class": "Subject",
238+
"to_class": "Participant",
239+
"distance": 0.12,
240+
"field_mappings": [
241+
{ "from_field": "age", "to_field": "age", "confidence": 0.97 },
242+
{ "from_field": "species", "to_field": "species", "confidence": 0.91 },
243+
{ "from_field": "subject_id", "to_field": "participant_id","confidence": 0.85 }
244+
]
245+
}
246+
]
247+
}
248+
```
249+
250+
Because the alignment data is already in `registry.json`, this endpoint can be
251+
pre-computed at export time and served as a static file — no compute layer
252+
needed.
253+
254+
---
255+
256+
### `POST /api/transform` — data transform *(planned)*
257+
258+
Send a dataset in one schema's format; receive it mapped to another. Unlike the
259+
GET above, this requires a live compute layer (a serverless function that reads
260+
the field-mapping and rewrites the payload).
261+
262+
```bash
263+
curl -X POST https://sensein.group/NeuroGhost/api/transform \
264+
-H "Content-Type: application/json" \
265+
-d '{
266+
"from": "bbqs",
267+
"to": "bids",
268+
"data": {
269+
"subject_id": "sub-01",
270+
"age": 24,
271+
"species": "Homo sapiens"
272+
}
273+
}'
274+
```
275+
276+
**Planned response**
277+
```json
278+
{
279+
"from": "bbqs",
280+
"to": "bids",
281+
"result": {
282+
"participant_id": "sub-01",
283+
"age": 24,
284+
"species": "Homo sapiens"
285+
},
286+
"unmapped_fields": [],
287+
"warnings": []
288+
}
289+
```
290+
291+
This will be implemented as a lightweight serverless function (Cloudflare Worker
292+
or equivalent) that reads the static registry alignment map and applies field
293+
renaming. Not yet live.
294+
295+
---
296+
101297
## Adding your own schema
102298

103299
The easiest way, no setup required:

0 commit comments

Comments
 (0)