|
| 1 | +# Makeability Lab public REST API |
| 2 | + |
| 3 | +A **public, read-only** JSON API over the lab's already-public content |
| 4 | +(publications, projects, grants, people, and project leadership). It lets |
| 5 | +external sites treat this website as the source of truth instead of duplicating |
| 6 | +content. Introduced in #1268. |
| 7 | + |
| 8 | +- **Base URL:** `https://makeabilitylab.cs.washington.edu/api/v1/` |
| 9 | + (test server: `https://makeabilitylab-test.cs.washington.edu/api/v1/`) |
| 10 | +- **Format:** JSON. Read-only — only `GET`/`HEAD`/`OPTIONS`. |
| 11 | +- **Auth:** none. All data is already public on the site. |
| 12 | +- **Cross-origin:** enabled (`Access-Control-Allow-Origin: *`) on `/api/` only, |
| 13 | + so browser-side JavaScript can fetch it directly. |
| 14 | +- **Versioned:** everything lives under `/api/v1/`. See *Stability contract*. |
| 15 | + |
| 16 | +Built on Django REST Framework. In local dev (`DEBUG=True`) the endpoints also |
| 17 | +render a **browsable HTML API** — just open them in a browser. |
| 18 | + |
| 19 | +## Pagination |
| 20 | + |
| 21 | +List endpoints are paginated (page-number style): |
| 22 | + |
| 23 | +```json |
| 24 | +{ "count": 157, "next": "...?page=2", "previous": null, "results": [ ... ] } |
| 25 | +``` |
| 26 | + |
| 27 | +- `?page=<n>` — page number. |
| 28 | +- `?page_size=<n>` — items per page (default **25**, max **100**). |
| 29 | + |
| 30 | +A "top 5 most recent" list is just `?page_size=5` on an endpoint whose default |
| 31 | +order is newest-first. |
| 32 | + |
| 33 | +## Endpoints |
| 34 | + |
| 35 | +### Publications — `GET /api/v1/publications/` |
| 36 | + |
| 37 | +Default order: **newest first** (`-date`). Optional, combinable filters: |
| 38 | + |
| 39 | +| Param | Example | Meaning | |
| 40 | +|-------------|------------------------|---------------------------------------| |
| 41 | +| `project` | `?project=sidewalk` | Publications attached to a project (by `short_name`). | |
| 42 | +| `author` | `?author=jonfroehlich` | Publications by a person (by `url_name`). | |
| 43 | +| `year` | `?year=2024` | Publications in a calendar year. | |
| 44 | +| `type` | `?type=Conference` | By venue type (`Conference`, `Journal`, `Poster`, …). | |
| 45 | +| `ordering` | `?ordering=title` | One of `date`, `-date`, `title`, `-title`. | |
| 46 | + |
| 47 | +`GET /api/v1/publications/<id>/` adds a formatted `citation_html` and raw |
| 48 | +`bibtex`, plus `book_title`, `publisher`, `isbn`, `num_pages`, `peer_reviewed`. |
| 49 | + |
| 50 | +**Example — a "Recent Publications" widget** (client-side, e.g. on an academic |
| 51 | +page): |
| 52 | + |
| 53 | +```js |
| 54 | +const r = await fetch( |
| 55 | + "https://makeabilitylab.cs.washington.edu/api/v1/publications/" + |
| 56 | + "?author=jonfroehlich&page_size=5" |
| 57 | +); |
| 58 | +const { results } = await r.json(); |
| 59 | +results.forEach(p => { |
| 60 | + // p.title, p.year, p.forum_name, p.authors[].name, p.pdf_url, p.official_url |
| 61 | +}); |
| 62 | +``` |
| 63 | + |
| 64 | +### Projects — `GET /api/v1/projects/` |
| 65 | + |
| 66 | +Only **publicly visible** projects (`is_visible=True`). Detail and |
| 67 | +sub-resources are keyed by `short_name`: |
| 68 | + |
| 69 | +- `GET /api/v1/projects/<short_name>/` — summary, about, website, dates, |
| 70 | + keywords, umbrellas, thumbnail. |
| 71 | +- `GET /api/v1/projects/<short_name>/publications/` — the project's pubs. |
| 72 | +- `GET /api/v1/projects/<short_name>/grants/` — grants funding the project. |
| 73 | +- `GET /api/v1/projects/<short_name>/people/` — everyone with a role on the |
| 74 | + project, each as a `{ person, role, lead_project_role, start_date, end_date, |
| 75 | + is_active }` record (a person may appear more than once for multiple roles). |
| 76 | +- `GET /api/v1/projects/<short_name>/leadership/` — **all** leadership across |
| 77 | + all time (current *and* past), grouped: |
| 78 | + `{ pis, co_pis, student_leads, postdoc_leads, research_scientist_leads }`, |
| 79 | + each a list of role records ordered newest-start first. A person appears once |
| 80 | + per lead role they've held (so a past student lead who later became PI shows |
| 81 | + up in both). Each record's `is_active` flag lets you separate current from |
| 82 | + past leadership. |
| 83 | + |
| 84 | +### Grants — `GET /api/v1/grants/` |
| 85 | + |
| 86 | +Filters: `?project=<short_name>`, `?sponsor=<sponsor short_name>`. Each grant |
| 87 | +includes its `sponsor`, `funding_amount`, `grant_id`, `grant_url`, and the |
| 88 | +`projects` it funds. |
| 89 | + |
| 90 | +### People — `GET /api/v1/people/` |
| 91 | + |
| 92 | +Actual lab members (people with at least one Position); external co-authors are |
| 93 | +not listed here even though they appear as publication `authors`. Detail by |
| 94 | +`url_name`: `GET /api/v1/people/<url_name>/` — name, current title, bio, |
| 95 | +thumbnail, and public social/web links (ORCID, Google Scholar, GitHub, etc.). |
| 96 | + |
| 97 | +> **Note:** `email` is intentionally **not** exposed by the API to avoid making |
| 98 | +> it an email-harvesting surface, even where it appears on a member page. |
| 99 | +
|
| 100 | +## Stability contract |
| 101 | + |
| 102 | +- **`v1` fields are additive-only.** New fields may be added; existing field |
| 103 | + names and meanings will not change or be removed within `v1`. Breaking changes |
| 104 | + ship as `/api/v2/`. |
| 105 | +- Don't hardcode pagination page sizes as a proxy for "all" — page through |
| 106 | + `next`, or set `page_size` explicitly (≤100). |
| 107 | +- URLs in responses (PDFs, thumbnails, page links) are absolute and safe to use |
| 108 | + directly. |
| 109 | + |
| 110 | +## Implementation notes (for maintainers) |
| 111 | + |
| 112 | +Code lives in `website/api/` (`serializers.py`, `views.py`, `urls.py`, |
| 113 | +`middleware.py`), mounted at `/api/` by the root URLconf |
| 114 | +(`makeabilitylab/urls.py`). Config is the `REST_FRAMEWORK` block in |
| 115 | +`settings.py`. CORS is a tiny in-repo middleware |
| 116 | +(`website.api.middleware.ApiCorsMiddleware`), scoped to `/api/`, rather than a |
| 117 | +third-party package. Tests: `website/tests/test_api.py`. |
| 118 | + |
| 119 | +**Deliberately deferred** (add on the same pattern when needed): write |
| 120 | +endpoints, auth / API keys, request throttling, and Talks/Posters/Videos |
| 121 | +resources. |
0 commit comments