<!--
*empty*
---
-->
## Introduction to APIs
<div style="text-align:left; font-size:0.7em">
<br/>
<br/>Peter Dängeli, Elena Spadini
<br/>Workshop <i>Re-use of editions and text collections: The role of APIs</i>
<br/>Zurich, 29-30 January 2026
</div>
---
<div style="display: grid; grid-template-columns: 2fr 1fr; gap: 20px;">
<div class="r-stretch" style="font-size:huge;">
<div style="color:#FFC600;">
Table of contents<br/><br/>
<ol>
<li>APIs — An Analogous Example</li>
<li>Examples</li>
<li>Concepts and terms</li>
<li>Hands-on</li>
</ol>
</div>
</div>
<div style="background: #e8f5e9; padding: 15px; border-left: 3px solid #f4f4f4;">
<div class="r-stretch" style="font-size:large; color:black;">
<img src="https://pad.dsl.unibe.ch/uploads/59cef8dd-6836-40e6-8a24-fc65fbb07f57.png"/>
<figcaption><a href="https://pad.dsl.unibe.ch/resed-api-20260129">https://pad.dsl.unibe.ch/resed-api-20260129</a></figcaption>
</div>
</div>
</div>
---
<h2 style="color:#FFC600;">1. APIs — An Analogous Example</h2>
---
<img class="r-stretch" src="https://pad.dsl.unibe.ch/uploads/df108c6f-a36e-4679-bf84-99e250dde038.jpg" />
<figcaption style="font-size:large;">Apparel Processing Interface<figcaption/>
<figcaption style="font-size:small;">
Image credit: Empty cloakroom, Tallinn Linnahall (L. Kruusimäe) [<a href="https://www.pexels.com/photo/an-empty-cloakroom-5883622/">↗</a>]</figcaption>
<aside class="notes">
We interact with **systems** on a daily basis. Handing our coat and bag over to cloakroom staff at a concert hall or theatre may not be quite so frequent, but it is an example of an API-like transaction.
What objects exactly we hand over for safekeeping is up to us, but the **sequence of events** is predictable:
* We place our items on the counter, from where they are brought to storage.
* We receive a **tag** (or ticket) indicating where our items are stored; it allows staff to efficiently find them, but most importantly, it **identifies us as authorised** to retrieve them.
* Sometimes the service isn't free — we may need to **pay** before receiving the tag.
* We can retrieve the items ourselves, or we can give the tag to **someone else** to collect them on our behalf.
* When we return, we present the tag, it's placed back on the hanger, and our items are returned to us.
* We are free to retrieve our items whenever we want, as long as we remain **within service hours**.
## What we don't need to know
* We might have some insight into the storage system, but the hangers could just as well be in another room or building.
* We don't need to know how the storage is organised, how many staff members are working, or what route they take.
* The tag has no real meaning outside of this specific system — it's just a number or code that **only works in this context**.
</aside>
---
<img class="r-stretch" width="800px;" src="https://pad.dsl.unibe.ch/uploads/6e35891b-177e-4c3d-83b8-008f96113142.png" />
<figcaption style="font-size:large;">The key to retrieval<figcaption/>
<aside class="notes">
We interact with **systems** on a daily basis. Handing our coat and bag over to cloakroom staff at a concert hall or theatre may not be quite so frequent, but it is an example of an API-like transaction.
What objects exactly we hand over for safekeeping is up to us, but the **sequence of events** is predictable:
* We place our items on the counter, from where they are brought to storage.
* We receive a **tag** (or ticket) indicating where our items are stored; it allows staff to efficiently find them, but most importantly, it **identifies us as authorised** to retrieve them.
* Sometimes the service isn't free — we may need to **pay** before receiving the tag.
* We can retrieve the items ourselves, or we can give the tag to **someone else** to collect them on our behalf.
* When we return, we present the tag, it's placed back on the hanger, and our items are returned to us.
* We are free to retrieve our items whenever we want, as long as we remain **within service hours**.
## What we don't need to know
* We might have some insight into the storage system, but the hangers could just as well be in another room or building.
* We don't need to know how the storage is organised, how many staff members are working, or what route they take.
* The tag has no real meaning outside of this specific system — it's just a number or code that **only works in this context**.
</aside>
---
## Some characteristics
<div class="r-stretch" style="transform: scale(0.65); transform-origin: top center;">
|||
|---|---|
|**Well-defined interface** | clear, predictable rules |
|**Transactional** | request → response pattern |
|**Abstraction** | hides internal complexity |
|**Standardised** | consistent format and structure |
|**Authentication** | controls access (the "tag") |
|**Context-dependent** | only works within the system |
|**Stateless** | the tag needs to be presented each time |
</div>
---
#### The Transaction Flow
<div class="r-stretch" style="transform: scale(0.5); transform-origin: top center;">
```mermaid
sequenceDiagram
participant You
participant Counter
participant Storage
You->>Counter: Hand over items
Counter->>Storage: Store items
Counter->>You: Receive tag
Note over You,Counter: Time passes...
You->>Counter: Present tag
Storage->>Counter: Retrieve items
Counter->>You: Return items
```
</div>
---
---
<h2 style="color:#FFC600;">
2. Examples from GLAM
</h2>
---
## APIs in Digital Humanities
- Expose cultural heritage data (objects, images, metadata, OCR output).
- Allow reproducible, scriptable data collection.
- Sit between “the archive/database” and your analysis, visualisation, or teaching projects.
---
## Examples
- The MET
- Memoriav Memobase
- Open Library
---
<!-- THE MET 1 -->
<div style="font-size:0.7em">
## The MET
<!--Metropolitan Museum of Art Collection API-->
- **Brief description of API design:** Simple public REST API (no auth required) with search-first pattern: query `/search` for objectIDs, then retrieve details via `/objects/{id}`. It returns JSON with metadata, images (CC0 subset).
- **Main endpoints**
- [`https://collectionapi.metmuseum.org/public/collection/v1/search?`](https://collectionapi.metmuseum.org/public/collection/v1/search?)
- [`https://collectionapi.metmuseum.org/public/collection/v1/objects/{id}`](https://collectionapi.metmuseum.org/public/collection/v1/objects/{id})
- **Example query.** All "sunflower" objects:
- [`https://collectionapi.metmuseum.org/public/collection/v1/search?q=sunflower`](https://collectionapi.metmuseum.org/public/collection/v1/search?q=sunflower&hasImages=true)
</div>
---
<div style="font-size:0.7em">
<!-- Metropolitan Museum of Art Collection API -->
- **What you can build, for example**
- Gallery of artworks about sunflowers.
- Curated teaching galleries (e.g., "Women artists 1800-1900").
- Acquisition timeline visualisations by era/region.
</div>
---
<!-- THE MET 1 -->
<div style="font-size:0.7em">
## Memoriav Memobase
- **Brief description of API design:** REST-style HTTP API providing JSON(-LD) responses for cultural heritage records from Swiss institutions; supports search over records plus lookup of related entities (institutions, collections).
- **Main endpoints**
- Base URL: https://api.memobase.ch/
- Search records: https://api.memobase.ch/record/search?
- Get record info: https://api.memobase.ch/record/{id}
- Get record set info: https://api.memobase.ch/recordSet/{id}
- Get institution info: https://api.memobase.ch/institution/{id}
- API docs / data model: https://api.memobase.ch/documentation?concept=record
</div>
---
<div style="font-size:0.7em">
## Open Library
- **Brief description of API design**: RESTful catalog API from Internet Archive covering 20M+ books/editions. Supports searches by title/author/ISBN, returns works/editions/authors with covers/metadata. JSON responses.
- **Main endpoints**
- https://openlibrary.org/books
- https://openlibrary.org/authors
- https://openlibrary.org/covers
- https://openlibrary.org/subjects
- https://openlibrary.org/search
</div>
---
<div style="font-size:0.7em">
- **Example queries**
- Chekhov, *The Sea-Gull*, by ISBN: https://openlibrary.org/api/books?bibkeys=ISBN%3A9781853993213
- Editions of "Peter Pan": https://openlibrary.org/search.json?title=Peter+Pan
<br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/>
</div>
---
<div style="font-size:0.7em">
- **Example queries**
- Chekhov, *The Seagull*, by ISBN: https://openlibrary.org/api/books?bibkeys=ISBN%3A9781853993213
- Editions of "Peter Pan": https://openlibrary.org/search.json?title=Peter+Pan
- **Example of research questions**
- How do translation patterns reveal literary canon's global spread?
- What biases exist in subject headings over time?
<br/><br/><br/><br/><br/><br/><br/>
</div>
---
<div style="font-size:0.7em">
- **Example queries**
- Chekhov, *The Seagull*, by ISBN: https://openlibrary.org/api/books?bibkeys=ISBN%3A9781853993213
- Editions of "Peter Pan": https://openlibrary.org/search.json?title=Peter+Pan
- **Example of research questions**
- How do translation patterns reveal literary canon's global spread?
- What biases exist in subject headings over time?
- **Example of what can you build**
- https://www.dreambooks.club/
- Virtual bookshelves tracking editions/translations.
- Network graphs of publisher/author collaborations.
- See https://openlibrary.org/developers/api for more
</div>
---
---
<h3 style="color:#FFC600;">
3. Core Concepts for API Design
</h3>
<aside class="notes">
<!-- **"Anatomy of an API"** or **"How APIs Work: Key Concepts"**
- Brief intro: "Now that we've seen what APIs do, let's understand how they work" -->
We've seen what APIs are and explored some examples from cultural heritage institutions. Now we need a **shared vocabulary and conceptual framework** for discussing APIs.
Over the next 15 minutes, we'll cover the key concepts that will help us have productive conversations tomorrow about what kinds of APIs make sense for digital editions and how they could be structured.
This isn't about making you API developers (I wouldn't call myself one most days) —it's about understanding the design choices and trade-offs involved. When we talk about '*resources*' or '*granularity*' or '*authentication*', you'll know what those mean and why they matter for usability and sustainability.
Think of this as learning enough about architecture to have a meaningful conversation with an architect about what kind of building you need—not learning to construct it yourself.
By the end, you'll be able to critically evaluate: What data should we expose? How should it be structured? What's realistic for our project to maintain long-term?
</aside>
---
### Core Concepts
* Resources & Endpoints
* Requests & Responses
* Data Formats
* Parameters
<aside class="notes">
Now we get to the mechanics. These four concepts — **resources**, **requests**, **formats**, and **parameters** — are the essential vocabulary. We'll look at each briefly in turn.
</aside>
----
### Resources & Endpoints
<div style="display: grid; grid-template-columns: 2fr 1fr; gap: 20px;">
<div class="r-stretch" style="font-size:medium;">
<dl>
<dt style="color: turquoise;">Resource</dt>
<dd><strong>Any discrete piece of information the API exposes</strong></dd>
<br/>
<dt style="color: turquoise;">Endpoint</dt>
<dd><strong>The URL address where that resource lives</strong></dd>
<br/>
<br/>
<dt style="color: pink;">Recommendations</dt>
<dd>
<ul style="color: pink;">
<li>Two path segments per resource (<code>books</code>, <code>12345</code>)</li>
<li>Plural nouns (or singular, but no wild mix)</li>
<li>Nouns for resources (<code>objects</code>, not <code>getObjects</code>),<br/>verbs for actions (e.g. <code>convert</code>)</li>
</dd>
<br/>
<br/>
<dt style="color: orange;">DSE key question</dt>
<dd style="color: orange;">What units of an edition are meaningful to expose as resources?</dd>
</dl>
</div>
<div style="background: #e8f5e9; padding: 15px; border-left: 3px solid #f4f4f4;">
<div class="r-stretch" style="font-size:large; color:black;">
<p>Generic examples:</p>
<pre style="font-size: 0.6em; background: #fff; padding: 8px; border-radius: 3px;"><code>
📚 A book → `/books/12345`
🎨 An artwork → `/objects/456`
🌍 A place → `/places/zurich`
</code>
</pre>
</div>
</div>
</div>
<aside class="notes">
A resource is **any piece of information that can be identified and accessed independently**. The choice of what counts as a resource is a fundamental design decision (in the examples before we saw books, artworks, historical places, but it could also be a single glyph or an edition as a whole).
The endpoint is simply the URL address where a resource can be accessed. Think of it like an identifier in a library or an archive — a predictable way to locate a specific item.
Now here's where it gets interesting for digital editions: what are sensible resources in digital scholarly editions? Is it the whole text? Individual pages? Paragraphs? Annotations? Manuscript witnesses?
There's no single right answer — it depends on how you expect researchers to use your data. We'll explore this more tomorrow, but start thinking: what are the natural 'units' in your edition that scholars might want to reference or retrieve independently?
</aside>
----
#### Possible resources/endpoints in DSEs
<div style="width: 95%; margin: 0 auto;">
<div class="r-stretch" style="font-size:medium;">
<table style="width: 100%; border-collapse: collapse;">
<thead>
<tr style="background: #e8f5e9; border-bottom: 2px solid #4caf50; color: darkgrey;">
<th style="padding: 12px; text-align: left; width: 20%;">Granularity</th>
<th style="padding: 12px; text-align: left; width: 45%;">Example endpoint</th>
<th style="padding: 12px; text-align: left; width: 35%;">Use-case</th>
</tr>
</thead>
<tbody>
<tr style="border-bottom: 1px solid #ddd;">
<td style="padding: 10px;"><strong>Whole work</strong></td>
<td style="padding: 10px; font-family: monospace; font-size: 0.9em; background: #f5f5f5; color: black;"><code>/works/the-seagull</code></td>
<td style="padding: 10px;">Citation, overview metadata</td>
</tr>
<tr style="border-bottom: 1px solid #ddd;">
<td style="padding: 10px;"><strong>Witness/version</strong></td>
<td style="padding: 10px; font-family: monospace; font-size: 0.9em; background: #f5f5f5; color: black;"><code>/works/the-seagull/versions/1896-first</code></td>
<td style="padding: 10px;">Textual criticism, performance history</td>
</tr>
<tr style="border-bottom: 1px solid #ddd;">
<td style="padding: 10px;"><strong>Structural unit</strong></td>
<td style="padding: 10px; font-family: monospace; font-size: 0.9em; background: #f5f5f5; color: black;"><code>/works/the-seagull/acts/2/scenes/1</code></td>
<td style="padding: 10px;">Close reading, teaching</td>
</tr>
<tr style="border-bottom: 1px solid #ddd;">
<td style="padding: 10px;"><strong>Text segment</strong></td>
<td style="padding: 10px; font-family: monospace; font-size: 0.9em; background: #f5f5f5; color: black;"><code>/works/the-seagull/lines/156-160</code></td>
<td style="padding: 10px;">Quotation, reference</td>
</tr>
<tr style="border-bottom: 1px solid #ddd;">
<td style="padding: 10px;"><strong>Speech</strong></td>
<td style="padding: 10px; font-family: monospace; font-size: 0.9em; background: #f5f5f5; color: black;"><code>/works/the-seagull/speeches/masha-42</code></td>
<td style="padding: 10px;">Character analysis, dialogue study</td>
</tr>
<tr style="border-bottom: 1px solid #ddd;">
<td style="padding: 10px;"><strong>Annotation</strong></td>
<td style="padding: 10px; font-family: monospace; font-size: 0.9em; background: #f5f5f5; color: black;"><code>/annotations/scholarly-note-89</code></td>
<td style="padding: 10px;">Commentary layer</td>
</tr>
<tr style="border-bottom: 1px solid #ddd;">
<td style="padding: 10px;"><strong>Named entity</strong></td>
<td style="padding: 10px; font-family: monospace; font-size: 0.9em; background: #f5f5f5; color: black;"><code>/entities/persons/nina</code> or just <code>/persons/nina</code></td>
<td style="padding: 10px;">Character networks, prosopography</td>
</tr>
<tr>
<td style="padding: 10px;"><strong>Apparatus entry</strong></td>
<td style="padding: 10px; font-family: monospace; font-size: 0.9em; background: #f5f5f5; color: black;"><code>/apparatus/the-seagull/line-156/variants</code></td>
<td style="padding: 10px;">Textual scholarship, revision study</td>
</tr>
</tbody>
<caption><p style="margin-bottom: 20px;"><strong>Different levels of granularity (Chekhov's "Seagull"):</strong></p></caption>
</table>
<div style="background: #fff8e1; padding: 15px; border-left: 4px solid #ffc107; margin-top: 30px;">
<strong style="color: #f57c00;">Key insight:</strong>
<p style="margin-top: 10px; color: darkgrey;">Multiple resources can refer to the <em>same underlying content</em> but serve different scholarly needs.</p>
</div>
</div>
</div>
<aside class="notes">
Here's where resource design gets really interesting for editions. You have many possible ways to slice your content, and different resources serve different research questions.
A whole work resource might return metadata and structure—useful for citations and discovery. But a researcher doing close reading might want individual scenes or even line ranges as resources.
Someone studying textual transmission needs witnesses as discrete resources — note how we can access the 1896 first performance version specifically. Someone analyzing character networks needs entities. Someone examining editorial decisions or Chekhov's revisions needs apparatus entries.
Notice these aren't mutually exclusive — the same line of text (like Masha's famous "Why do you always wear black?") might be accessible through multiple endpoints: as part of a scene, as part of a line range, as a speech, or with its critical apparatus showing how Chekhov revised it between 1896 and 1904.
The challenge — and what we'll discuss tomorrow — is deciding which of these resources are **essential** for your users versus which would be nice-to-have but costly to implement and maintain. It is not feasible to expose everything in every possible way, and prioritization based on use cases is key.
One more thing: see how these URLs are predictable and hierarchical? That's intentional design — it makes your API intuitive. A researcher can almost guess the URL structure.
</aside>
----
### Requests & Responses
<div style="display: grid; grid-template-columns: 2fr 1fr; gap: 20px;">
<div class="r-stretch" style="font-size:medium;">
<dl>
<dt style="color: turquoise;">Request</dt>
<dd><strong>What you ask for</strong> (method + endpoint + parameters)</dd>
<br/>
<dt style="color: turquoise;">Response</dt>
<dd><strong>What you get back</strong> (status code + data)</dd>
<br/>
<br/>
<dt style="color: pink;">HTTP Methods</dt>
<dd>
<ul style="color: pink;">
<li><code>GET</code> — retrieve data (most common)</li>
<li><code>POST</code> — create new resource</li>
<li><code>PUT</code> — update existing resource</li>
<li><code>DELETE</code> — remove resource</li>
</ul>
</dd>
<br/>
<br/>
<dt style="color: orange;">DSE key question</dt>
<dd style="color: orange;">Should an edition API be read-only (<code>GET</code>) or allow contributions (<code>POST</code>)?</dd>
</dl>
</div>
<div style="background: #e8f5e9; padding: 15px; border-left: 3px solid #f4f4f4;">
<div class="r-stretch" style="font-size:large; color:black;">
<p><strong>Status Codes:</strong></p>
<pre style="font-size: 0.5em; background: #fff; padding: 8px; border-radius: 3px;"><code>
✅ 200 OK — Success
✨ 201 Created — New resource
🔄 304 Not Modified — Use cache
⚠️ 400 Bad Request — Invalid syntax
🔐 401 Unauthorised — Auth required
🚫 403 Forbidden — No permission
🔍 404 Not Found — Missing resource
⏱️ 429 Too Many — Rate limit hit
❌ 500 Server Error — API problem
🔧 503 Unavailable — Maintenance
</code>
</pre>
<p style="font-size:small;">Full list <a href="https://en.wikipedia.org/wiki/List_of_HTTP_status_codes">↗</a></p>
</div>
</div>
</div>
<aside class="notes">
The request-response pattern is the heartbeat of any API—just like our cloakroom transaction. You make a **request** to an endpoint, and the API sends back a **response**.
A request consists of three parts: the **HTTP method** (what action you want to perform), the **endpoint** (which resource), and optionally **parameters** (to filter or customise).
The **HTTP methods** tell the API what you want to do. `GET` is by far the most common — it just retrieves data without changing anything. `POST` creates new data, `PUT` updates existing data, `DELETE` removes it. For most edition APIs, offering GET—read-only access to texts and metadata is sufficient. Services such as the Transkribus platform also implement the other methods/verbs, always at the cost of more complexity (access privileges).
But here's a design question: do you want to allow contributions? Should researchers be able to POST annotations or corrections? That's a much more complex API to build and moderate.
The **response** always includes a **status code** — a three-digit number that tells you what happened. `200` means success. `404` means the resource doesn't exist — maybe someone requested a page number that isn't in your edition. `401` means they need to authenticate first. `429` means they've hit your rate limit.
These status codes are standardised across all HTTP APIs, so once you understand them, you can interpret responses from any API you encounter.
The focus of the workshop lies on `GET` scenarios as it is important to keep complexity in check. But if more collaborative use-cases come up in the discussions we can extend the concepts to API-based updates, too (`GET` + `POST`).
</aside>
<!--
<aside class="notes">
The request-response pattern is the heartbeat of any API—just like our cloakroom transaction. You make a **request** to an endpoint, and the API sends back a **response**.
A request consists of three parts: the **HTTP method** (what action you want to perform), the **endpoint** (which resource), and optionally **parameters** (to filter or customize).
</aside>
-->
----
### Data Formats
<div style="display: grid; grid-template-columns: 2fr 1fr; gap: 20px;">
<div class="r-stretch" style="font-size:medium;">
<dl>
<dt style="color: turquoise;">JSON (JavaScript Object Notation)</dt>
<dd><strong>The dominant format</strong> — lightweight, human-readable, universal support</dd>
<br/>
<dt style="color: turquoise;">XML (eXtensible Markup Language)</dt>
<dd><strong>Structured documents</strong> — verbose but semantic (think TEI)</dd>
<br/>
<dt style="color: turquoise;">Plain Text</dt>
<dd><strong>Just the content</strong> — no markup, maximum simplicity for text analysis</dd>
<br/>
<dt style="color: turquoise;">JSON-LD (JSON for Linked Data)</dt>
<dd><strong>JSON + semantics</strong> — connects to vocabularies, LOD principles</dd>
<br/>
<br/>
<dt style="color: pink;">Trade-offs</dt>
<dd>
<ul style="color: pink;">
<li>JSON: simple, widely adopted, but loses TEI richness</li>
<li>XML/TEI: preserves scholarly encoding, but less "API-native"</li>
<li>Plain text: perfect for NLP/analysis, but strips all structure</li>
<li>JSON-LD: best of both worlds, but adds complexity</li>
</ul>
</dd>
<br/>
<dt style="color: orange;">DSE key question</dt>
<dd style="color: orange;">Can you transform TEI to JSON meaningfully, or should you serve multiple formats?</dd>
</dl>
</div>
<div style="background: #f3e5f5; padding: 15px; border-left: 3px solid #f4f4f4;">
<div class="r-stretch" style="font-size:small; color:black;">
<p><strong>JSON:</strong></p>
<pre style="font-size: 0.6em; background: #fff; padding: 10px; border-radius: 3px;"><code>{
"work": "The Seagull",
"author": "Chekhov",
"act": 2,
"speaker": "Masha",
"line": 156,
"text": "Why do you always wear black?",
"variant_count": 2
}</code></pre>
<p><strong>XML/TEI:</strong></p>
<pre style="font-size: 0.6em; background: #fff; padding: 10px; border-radius: 3px;"><code><sp who="#masha">
<l n="156">
<app>
<rdg wit="#1896">Why do you
always wear black?</rdg>
<rdg wit="#1904">Why do you
wear black all the time?</rdg>
</app>
</l>
</sp></code></pre>
<p><strong>Plain text:</strong></p>
<pre style="font-size: 0.6em; background: #fff; padding: 10px; border-radius: 3px;"><code>Why do you always wear black?</code></pre>
<p><strong>JSON-LD:</strong></p>
<pre style="font-size: 0.6em; background: #fff; padding: 8px; border-radius: 3px;"><code>{
"@context": "schema.org",
"@type": "CreativeWork",
"author": "Chekhov",
"line": 156
}</code></pre>
</div>
</div>
</div>
<aside class="notes">
When an API responds to your request, it needs to format the data in some structured way. The most common format by far is **JSON**—JavaScript Object Notation. It's lightweight, easy to read, and every programming language can work with it effortlessly. Almost every modern API returns JSON by default.
But here's where digital editions face an interesting tension: **TEI XML** is the scholarly standard for encoding texts. It's rich, semantic, hierarchical—perfect for capturing textual complexity. But it's also verbose and less "native" to modern web APIs.
You have three main options:
First, **transform your TEI to JSON** for the API. This makes your API easy to consume but means deciding what TEI richness to preserve and what to simplify. You might lose nuance.
Second, **serve XML directly** through your API. This preserves your scholarly encoding completely, but makes your API less familiar to developers expecting JSON. It's perfectly valid—just less conventional.
Third, offer **plain text** as an option. Researchers doing distant reading, corpus analysis, or NLP will love you for it. It's the lowest barrier to entry for text analysis.
Fourth, use **JSON-LD**—JSON for Linked Data. This gives you JSON's simplicity plus semantic connections to controlled vocabularies and the Linked Open Data ecosystem. It's powerful but adds conceptual and technical overhead.
There's no wrong answer—it depends on the intended users. Are they mainly digital humanists comfortable with TEI? Or web developers building visualizations? Or metadata/data aggregators? It is possible to offer **multiple formats** and to let users request JSON or XML via content negotiation or a format parameter.
The key question for tomorrow: what representation best serves the research community while remaining maintainable for the developers?
</aside>
----
### Parameters
<div style="display: grid; grid-template-columns: 2fr 1fr; gap: 20px;">
<div class="r-stretch" style="font-size:medium;">
<dl>
<dt style="color: turquoise;">Path Parameters</dt>
<dd><strong>Part of the URL structure</strong> — identify specific resources<br/>
Example: <code>/works/the-seagull/acts/<strong style="color: #ff6b6b;">2</strong></code></dd>
<br/>
<dt style="color: turquoise;">Query Parameters</dt>
<dd><strong>After the <code>?</code></strong> — filter, sort, or customize results<br/>
Example: <code>/works?<strong style="color: #ff6b6b;">author=chekhov&year=1896</strong></code></dd>
<p style="text-align: center; font-size: 1.1em; margin-bottom: 25px;">
<span style="color: #4caf50; font-family: monospace;">/works/the-seagull</span><span style="color: #ff6b6b; font-family: monospace;">?speaker=nina&limit=10</span>
</p>
<p style="text-align: center; font-size: 0.9em; margin-bottom: 30px;">
<span style="color: #4caf50;">↑ Path parameters (navigation)</span>
<span style="padding: 0 20px;">|</span>
<span style="color: #ff6b6b;">↑ Query parameters (filtering)</span>
</p>
<br/>
<dt style="color: pink;">Common query parameters</dt>
<dd>
<ul style="color: pink;">
<li><code>limit</code> / <code>page</code> — pagination</li>
<li><code>sort</code> / <code>order</code> — control ordering</li>
<li><code>format</code> — request JSON, XML, or plain text</li>
<li><code>filter</code> — narrow by criteria (date, type, variants, annotations, etc.)</li>
<li><code>fields</code> — request only specific data</li>
</ul>
</dd>
<br/>
<br/>
<dt style="color: orange;">DSE key question</dt>
<dd style="color: orange;">What filtering makes sense for what use-case?<br/>
By date? By manuscript witness? By character? By annotation type?</dd>
</dl>
</div>
<div style="background: #fff3e0; padding: 15px; border-left: 3px solid #f4f4f4;">
<div class="r-stretch" style="font-size:small; color:black; overflow-y: scroll; height: 550px;">
<p><strong>Path parameters:</strong>
<pre style="font-size: 0.75em; background: #fff; padding: 10px; border-radius: 3px;"><code style="line-height: 2.5;">/works/<span style="color: #ff6b6b;">the-seagull</span>
/works/the-seagull/acts/<span style="color: #ff6b6b;">2</span>
/entities/persons/<span style="color: #ff6b6b;">nina</span></code></pre>
</p>
<p><strong>Query parameters:</strong>
<pre style="font-size: 0.75em; background: #fff; padding: 10px; border-radius: 3px;"><code style="line-height: 2.5;">/works?<span style="color: #ff6b6b;">author=chekhov</span>
/works/the-seagull/lines?<span style="color: #ff6b6b;">
speaker=masha&limit=10</span>
/annotations?<span style="color: #ff6b6b;">
type=scholarly&date_after=1896</span></code></pre>
</p>
<p><strong>Combined:</strong>
<pre style="font-size: 0.75em; background: #fff; padding: 10px; border-radius: 3px;"><code style="line-height: 2.5;">/works/<span style="color: #4caf50;">the-seagull</span>/lines?
<span style="color: #ff6b6b;">speaker=nina&format=json</span></code></pre>
</p>
<p><strong>More realistic:</strong>
<pre style="font-size: 0.7em; background: #fff; padding: 10px; border-radius: 3px; overflow: hidden;">
<code><span style="color: #888;">// All Chekhov works</span>
/works?<span style="color: #ff6b6b;">author=chekhov</span></code>
<code><span style="color: #888;">// Nina's lines, JSON format</span>
/works/<span style="color: #4caf50;">the-seagull</span>/lines?
<span style="color: #ff6b6b;">speaker=nina&format=json</span></code>
<code><span style="color: #888;">// Lines with variants, 1896 version</span>
/works/<span style="color: #4caf50;">the-seagull</span>/lines?
<span style="color: #ff6b6b;">has_variants=true&
witness=1896-first</span></code>
<code><span style="color: #888;">// Paginated annotations</span>
/annotations?
<span style="color: #ff6b6b;">work=the-seagull&</span>
<span style="color: #ff6b6b;">type=scholarly&</span>
<span style="color: #ff6b6b;">limit=20&page=1</span></code>
<code><span style="color: #888;">// Plain text of Act 2</span>
/works/<span style="color: #4caf50;">the-seagull</span>/acts/2?
<span style="color: #ff6b6b;">format=txt</span></code></pre>
</p>
</div>
</div>
<aside class="notes">
Parameters are how users customize their API requests. There are two main types, and understanding the difference is important.
**Path parameters** are part of the URL structure itself. They identify *which* resource you want. When you request `/works/the-seagull/acts/2`, those values—"the-seagull" and "2"—are path parameters. They're navigating the resource hierarchy. They're required and specific.
**Query parameters** come after the question mark and let you filter, sort, or modify the response. They're optional and flexible. For example, `/works?author=chekhov&year=1896` uses query parameters to find all works by Chekhov from 1896.
Query parameters are very powerful for edition APIs. They might include:
- **Pagination**: `limit=50&page=2` — essential for large result sets
- **Filtering**: `speaker=nina` or `witness=1896-first` or `has_variants=true`
- **Format selection**: `format=xml` or `format=txt` — let users choose their preferred format
- **Field selection**: `fields=text,line_number` — return only what they need, reducing bandwidth
- **Sorting**: `sort=line_number&order=asc`
Tomorrow we may discuss if specific use-cases are better served by one of these query types and what parameters make sense for what case.
If you're encoding letters, maybe `date_from`, `date_to`, `correspondent`, `location`.
If you're encoding drama, maybe `speaker`, `act`, `has_stage_directions`.
If you're encoding a critical edition, maybe `witness`, `has_variants`, `editor_note_type`.
Don't try to support every possible parameter—start with the filters researchers actually need. You can always add more later, but removing parameters is a breaking change.
Good parameter design makes an API intuitive. Users should be able to guess what parameters might exist based on your content structure.
</aside>
---
### Taken together: REST Architecture
<div style="display: grid; grid-template-columns: 2fr 1fr; gap: 20px;">
<div class="r-stretch" style="font-size:medium;">
<p><strong>REST = REpresentational State Transfer</strong></p>
<p style="font-size: 0.9em; margin-bottom: 30px;">An architectural style (not a protocol) for designing web APIs</p>
<dl>
<dt style="color: turquoise;">Core principles:</dt>
<dd>
<ul style="color: turquoise;">
<li><strong>Resource-based</strong> — Everything has a URL identifier</li>
<li><strong>Stateless</strong> — Each request is self-contained</li>
<li><strong>Standard methods</strong> — Use HTTP verbs (<code>GET</code>, <code>POST</code>, etc.)</li>
<li><strong>Multiple representations</strong> — Same data, different formats</li>
</ul>
</dd>
<br/>
<br/>
<dt style="color: pink;">Why REST dominates:</dt>
<dd>
<ul style="color: pink;">
<li>Built on existing web infrastructure (HTTP)</li>
<li>Predictable patterns reduce learning curve</li>
<li>Language and platform independent</li>
<li>Scales well for read-heavy applications (like editions)</li>
</ul>
</dd>
<br/>
<dt style="color: orange;">DSE benefit</dt>
<dd style="color: orange;">REST conventions imply less custom documentation, more intuitive APIs, and easier long-term maintenance — critical in scarcely funded contexts and for small teams.</dd>
</dl>
</div>
<div style="background: #e3f2fd; padding: 15px; border-left: 3px solid #f4f4f4;">
<div class="r-stretch" style="font-size:medium; color:black;">
<p><strong>RESTful = predictable</strong></p>
<br/>
<p style="font-size: 0.85em;">If you know:</p>
<pre style="font-size: 0.8em; background: #fff; padding: 10px; border-radius: 3px;"><code>/works/the-seagull</code></pre>
<p style="font-size: 0.85em;">You can guess:</p>
<pre style="font-size: 0.8em; background: #fff; padding: 10px; border-radius: 3px;"><code>/works/uncle-vanya
/works/three-sisters
/works</code></pre>
<br/>
<p style="font-size: 0.85em;">Because REST follows <strong>conventions</strong>, not arbitrary decisions</p>
</div>
</div>
</div>
<aside class="notes">
REST stands for **REpresentational State Transfer**. It's an architectural style — a set of principles for designing networked applications — created by Roy Fielding in 2000 (PhD thesis). It's not a protocol or a standard you must follow perfectly, but a design philosophy that makes APIs more intuitive and maintainable.
Most modern web APIs are RESTful, or at least REST-inspired.
**Resource-based design**: We've already seen this — everything is a resource with a URL. This makes APIs browsable and logical.
**Stateless interactions**: Remember the cloakroom? Each transaction is independent. The API doesn't "remember" your previous requests. You include everything needed (like your authentication token) with each request. This makes APIs simpler to build, easier to scale, and more reliable. If one request fails, it doesn't break the next one.
**Standard HTTP methods**: REST uses the methods already built into HTTP—GET for retrieval, `POST` for creation, `PUT` for updates, `DELETE` for removal. You don't have to invent your own verbs or conventions. This means developers already know how your API works before they even read your documentation.
**Multiple representations**: A RESTful API can return the same resource in different formats. `/works/the-seagull?format=json` versus `?format=xml`. The resource is the same; the representation changes based on what the client needs.
Why is REST the dominant architectural style for APIs? Because it's built on the web's existing infrastructure. You're not adding a new protocol or requiring special software. It's predictable—once you understand REST conventions, you can often guess how an API works. And critically for small edition teams: it's easier to document and sustain because you're following established patterns, not custom designs.
You don't need to be a RESTafarian and go all the way to perfect RESTfulness. But following REST principles where reasonable makes APIs more intuitive for users and more maintainable a small team.
</aside>
---
### The Rest of the Story:</br> Practical Considerations
* Access Control
* Handling Scale & Errors
* Documentation
* Key Design Decisions
* API Planning: Balancing Ambition and Reality
* Approaches Beyond REST
----
### Access Control
<div style="display: grid; grid-template-columns: 2fr 1fr; gap: 20px;">
<div class="r-stretch" style="font-size:medium;">
<dl>
<dt style="color: turquoise;">Authentication</dt>
<dd><strong>Who are you?</strong> — Verifying identity before granting access</dd>
<br/>
<dt style="color: turquoise;">Authorization</dt>
<dd><strong>What can you do?</strong> — Determining permissions for different users</dd>
<br/>
<br/>
<dt style="color: pink;">Common methods:</dt>
<dd>
<ul style="color: pink;">
<li><strong>API Keys</strong> — Simple tokens in URL or header<br/>
<code style="font-size: 0.85em;">?api_key=abc123xyz</code></li>
<li><strong>OAuth tokens</strong> — More secure, time-limited access</li>
<li><strong>No authentication</strong> — Fully open (public domain content)</li>
</ul>
</dd>
<br/>
<br/>
<dt style="color: violet;">Rate Limiting</dt>
<dd style="color: violet;"><strong>Protecting your infrastructure</strong> — Limiting requests per hour/day<br/>
<!--<span style="font-size: 0.9em;">Like service hours at the cloakroom: prevents abuse, ensures fair access</span></dd>-->
<!--<dd style="color: lilac;"><strong>Crawler resilience</strong> — Keeping services up and accessible in times of AI bots is not trivial<br/>-->
<span style="font-size: 0.9em;">prevents abuse, ensures fair access, and shields against crawler/bot overload</span></br>
<br/>
<br/>
<dt style="color: orange;">DSE key questions</dt>
<dd style="color: orange;">
<ul>
<li>Should the API be fully public or require registration?</li>
<li>What usage patterns can the infrastructure handle?</li>
<li>How to balance openness with sustainability?</li>
</ul>
</dd>
</dl>
</div>
<div style="background: #fff3e0; padding: 15px; border-left: 3px solid #f4f4f4;">
<div class="r-stretch" style="font-size:small; color:black;">
<p><strong>Public API (no auth):</strong></p>
<pre style="font-size: 0.75em; background: #fff; padding: 10px; border-radius: 3px;"><code>GET /works/the-seagull
→ 200 OK
{data...}</code></pre>
<p><strong>With API key:</strong></p>
<pre style="font-size: 0.75em; background: #fff; padding: 10px; border-radius: 3px;"><code>GET /works/the-seagull
?api_key=abc123
→ 200 OK
{data...}</code></pre>
<p><strong>Rate limit exceeded:</strong></p>
<pre style="font-size: 0.75em; background: #fff; padding: 10px; border-radius: 3px;"><code>GET /works/the-seagull
→ 429 Too Many Requests
{
"error": "Rate limit exceeded",
"retry_after": 3600
}</code></pre>
<p><strong>Rate limit headers:</strong></p>
<pre style="font-size: 0.7em; background: #fff; padding: 8px; border-radius: 3px;"><code>X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 247
X-RateLimit-Reset: 1643385600</code></pre>
</div>
</div>
</div>
<aside class="notes">
Authentication and authorization are about **controlling access** to your API. They're related but different concepts.
**Authentication** asks "who are you?"—it's about verifying identity. **Authorization** asks "what are you allowed to do?"—it's about permissions. You might authenticate someone but not authorize them to access certain resources.
The simplest method is **API keys** — unique tokens you generate for each user. They can pass it as a query parameter or in a request header. It's straightforward but not the most secure — anyone with the key can use it. **OAuth** tokens are more sophisticated — they're time-limited, can be revoked, and are better for sensitive data. But they add complexity.
Many edition APIs, especially for public domain content, require **no authentication at all**. Tey are offering open access to scholarship. That's wonderful, but it is still important to think about infrastructure.
This is where **rate limiting** comes in. Rate limiting protects an API from being overwhelmed. It might allow 1000 requests per hour per user, or 10,000 per day. This prevents abuse (someone scraping your entire database) and ensures fair access for all users.
When someone hits their limit, you return a 429 status code. Good APIs also include headers showing the limit, how many requests remain, and when the limit resets. This lets users pace themselves.
**Should you require authentication?** If your content is openly licensed and your server can handle traffic, maybe not. But if you have sensitive materials, need usage statistics, or want to prevent abuse, authentication makes sense. Even then, spikes can be enormous. Currently, we're seeing aggressive automated scraping for training data. A small edition project's server can be overwhelmed by a single poorly-configured bot/crawler. Rate limiting isn't just about fairness anymore — it's about keeping your service accessible at all when bots are consuming resources at scale.
**What rate limits are realistic?** Think about your server capacity and typical use cases. A researcher doing exploratory queries needs different limits than someone bulk-downloading your corpus.
The tension is real: you want maximum openness and accessibility, but you also need to protect limited infrastructure. There's no universal answer — it depends on your content, your resources, and your user community.
</aside>
----
### Handling Scale & Errors
<div style="display: grid; grid-template-columns: 2fr 1fr; gap: 20px;">
<div class="r-stretch" style="font-size:medium;">
<dl>
<dt style="color: turquoise;">Pagination</dt>
<dd><strong>Breaking large datasets into manageable chunks</strong></dd>
<dd style="margin-top: 8px;">Common patterns:
<ul style="font-size: 0.9em; margin-top: 8px;">
<li><code>limit</code> & <code>offset</code> — Skip/take pattern</li>
<li><code>page</code> & <code>per_page</code> — Page-based navigation</li>
<li><code>cursor</code> — Token-based (more stable for changes, but uncommon for DSE)</li>
</ul>
</dd>
<br/>
<br/>
<dt style="color: pink;">Error Responses</dt>
<dd style="color: pink;">
<strong>Status codes aren't enough—provide details!</strong>
<ul style="margin-top: 8px;">
<li>Error message (human-readable)</li>
<li>Error code (machine-readable)</li>
<li>Helpful context (what went wrong, how to fix)</li>
</ul>
</dd>
<br/>
<br/>
<dt style="color: orange;">DSE considerations</dt>
<dd style="color: orange;">
<ul>
<li>What's a reasonable default page size? (20? 50? 100?)</li>
<li>Should users control page size, or fix it for performance?</li>
<li>What errors are users likely to encounter?</li>
<li>Can you provide helpful error messages?</li>
</ul>
</dd>
</dl>
</div>
<div style="background: #e8f5e9; padding: 15px; border-left: 3px solid #f4f4f4;">
<div class="r-stretch" style="font-size:small; color:black;">
<p><strong>Pagination example:</strong></p>
<pre style="font-size: 0.75em; background: #fff; padding: 10px; border-radius: 3px;"><code>GET /works/the-seagull/lines
?limit=20&offset=40
→ 200 OK
{
"total": 2847,
"limit": 20,
"offset": 40,
"results": [...]
}</code></pre>
<p><strong>Good error response:</strong></p>
<pre style="font-size: 0.7em; background: #fff; padding: 10px; border-radius: 3px;"><code>GET /works/the-seagal
→ 404 Not Found
{
"error": "Work not found",
"code": "WORK_NOT_FOUND",
"message": "No work exists with
identifier 'the-seagal'",
"suggestion": "Did you mean
'the-seagull'?"
}</code></pre>
<p><strong>Bad error response:</strong></p>
<pre style="font-size: 0.75em; background: #fff; padding: 10px; border-radius: 3px;"><code>→ 500 Internal Server Error
{
"error": "NullPointerException"
}</code></pre>
</div>
</div>
</div>
<aside class="notes">
When your API returns large datasets—like all 2,847 lines of The Seagull — you can't send everything at once. That's slow for users and expensive for your server. This is where **pagination** comes in.
There are several pagination patterns. The most common is **limit and offset** — "give me 20 results, starting from position 40." It's intuitive and easy to implement. **Page-based** pagination is similar: "give me page 3, with 20 results per page." Both work well for stable datasets.
**Cursor-based** pagination is more sophisticated — you get a token pointing to your position in the dataset. If data changes between requests (new lines added, for example), cursors handle this more gracefully than offsets. But they're more complex to implement.
For editions, you need to decide: What's a reasonable default page size? 20 items works for lists of works. 100 might make sense for lines in a scene. Should users control this with a `per_page` parameter, or do you fix it for performance reasons?
Including metadata in paginated responses helps users navigate without guessing: total count, current offset or page, and ideally links to next/previous pages.
Now, **error handling**. We've talked about status codes—404, 401, 500—but status codes alone aren't enough. When something goes wrong, users need to understand *what* and *why*.
A good error response includes a human-readable message, a machine-readable error code (so applications can handle specific cases), and ideally helpful context. It could go as far as similarity-based feedback (look at the example: someone requested "the-seagal" (typo); the API could just say "404 Not Found." but instead, it suggests "Did you mean 'the-seagull'?").
Bad error responses expose internal details ("NullPointerException") or generic messages that don't help users recover. Error messages are part of an API's user experience.
Common errors for edition APIs include: invalid line numbers, requesting a witness that doesn't exist, malformed date parameters. Anticipation may allow to provide helpful guidance.
<!--And here's a consideration: if your edition serves an international community, can you provide error messages in multiple languages, perhaps via an `Accept-Language` header? It's extra work but dramatically improves accessibility.
Pagination and error handling might seem like implementation details, but they're part of your API's sustainability. Good patterns here reduce support requests and make your API more pleasant to use long-term.-->
</aside>
----
### Documentation
<div style="display: grid; grid-template-columns: 2fr 1fr; gap: 20px;">
<div class="r-stretch" style="font-size:medium;">
<p style="font-size: 1.1em; margin-bottom: 25px;"><span style="color: #f57c00;">Documentation facilitates re-use, but also maintenance and monitoring.</span></p>
<dl>
<dt style="color: turquoise;">Good documentation covers many areas:</dt>
<dd>
<ul style="color: turquoise;">
<li><strong>Overview</strong> — What does this API do? Who's it for?</li>
<li><strong>Authentication</strong> — How do I get access?</li>
<li><strong>Base URL</strong> — Where do I send requests?</li>
<li><strong>Endpoints</strong> — Complete list with descriptions</li>
<li><strong>Parameters</strong> — What can I customize?</li>
<li><strong>Response formats</strong> — What do I get back?</li>
<li><strong>Examples</strong> — Real requests and responses</li>
<li><strong>Error codes</strong> — What can go wrong?</li>
<li><strong>Rate limits</strong> — Usage constraints</li>
</ul>
</dd>
<br/>
<dt style="color: pink;">Documentation tools:</dt>
<dd style="color: pink;">
<ul>
<li><strong>OpenAPI/Swagger</strong> — Industry standard, generates interactive docs</li>
<li><strong>Static docs</strong> — Written markdown/HTML pages</li>
<li><strong>API explorers</strong> — Let users try requests in browser</li>
</ul>
</dd>
<br/>
<dt style="color: orange;">DSE reality check</dt>
<dd style="color: orange;"><strong>Documentation is often the hardest part to maintain.</strong><br/>
It won't write itself, but LLMs are good at it.</dd>
</dl>
</div>
<div style="background: #f3e5f5; padding: 15px; border-left: 3px solid #f4f4f4;">
<div class="r-stretch" style="font-size:small; color:black;">
<p><strong>Example documentation:</strong></p>
<div style="background: #fff; padding: 12px; border-radius: 3px; font-size: 0.75em;">
<p style="margin: 0; font-weight: bold;">GET /works/:work_id/lines</p>
<p style="margin: 8px 0 0 0; color: #666;">Retrieve lines from a specific work</p>
<hr style="margin: 10px 0; border: none; border-top: 1px solid #eee;">
<p style="margin: 8px 0 4px 0; font-weight: bold;">Parameters:</p>
<ul style="margin: 0; padding-left: 20px; font-size: 0.95em;">
<li><code>speaker</code> (string, optional) — Filter by character</li>
<li><code>limit</code> (integer, optional) — Results per page (default: 50)</li>
</ul>
<p style="margin: 12px 0 4px 0; font-weight: bold;">Example request:</p>
<pre style="margin: 0; background: #f5f5f5; padding: 6px; border-radius: 2px; font-size: 0.9em;"><code>GET /works/the-seagull/lines
?speaker=nina&limit=10</code></pre>
<p style="margin: 12px 0 4px 0; font-weight: bold;">Response:</p>
<pre style="margin: 0; background: #f5f5f5; padding: 6px; border-radius: 2px; font-size: 0.85em;"><code>{
"total": 127,
"results": [
{"line": 42, "text": "..."}
]
}</code></pre>
</div>
</div>
</div>
</div>
<aside class="notes">
Documentation is essential for adaptation and re-use. You can build the most elegant, well-designed API in the world, but if people don't know how to use it, it's useless.
Unfortunately, **documentation is often the hardest part to maintain** (especially for small edition teams). The might be stable, but are the docs being updated when a new parameter is added? When the error response format changes? When pagination is added?
Good documentation isn't just a nice-to-have—it's essential infrastructure. Let's talk about what it needs.
First, an **overview**: What does this API provide? Who should use it? What kind of data can they access? This orients users before they dive into technical details.
Then, **authentication instructions**: If you require API keys, how do people get them? What headers or parameters do they include?
The **base URL**: Where do requests go? Is it `https://api.yourproject.org/v1/` or something else?
A **complete list of endpoints** with descriptions. What resources can users access? What does each endpoint return?
For each endpoint, document **parameters**: required vs. optional, data types, default values, validation rules.
Show **response formats** with real examples—not just "returns JSON," but actual sample responses showing the structure.
Include **error documentation**: What status codes might users encounter? What do error responses look like?
And crucially, provide **working examples**. Show actual requests and responses. Let people copy-paste and try immediately.
There are tools that help. **OpenAPI** (formerly Swagger) is the industry standard — you write a specification file describing your API, and tools generate interactive documentation automatically. Users can try requests right in the browser, seeing real responses. It's fantastic, but it requires keeping that spec file updated.
**Static documentation**—markdown or HTML pages—is simpler but more manual. You write it, you maintain it, you host it.
**API explorers** let users make requests without writing code — lowering the barrier to entry dramatically.
The silver bullet: **Plan for documentation from the start.** But that's hard for organically growing projects. Too often we build the API first and think "we'll document it later." Later never comes, or it's rushed and incomplete.
Ideally, documentation is considered as part of an API's sustainability. Is it maintainable? Will future colleagues or your future self understand how to update it? Can parts of it be automated (generating examples from tests, for instance)?
For small teams, this might mean designing a simpler API that you can document thoroughly rather than a complex one with patchy docs. Users can work with a simple, well-documented API, but they can't work with a powerful, undocumented one.
</aside>
----
### Key Design Decisions
<div style="display: grid; grid-template-columns: 2fr 1fr; gap: 20px;">
<div class="r-stretch" style="font-size:medium;">
<dl>
<dt style="color: turquoise;">Versioning</dt>
<dd><strong>How to evolve your API without breaking existing applications</strong></dd>
<dd style="margin-top: 8px;">Common strategies:
<ul style="font-size: 0.9em; margin-top: 8px;">
<li><strong>URL versioning:</strong> <code>/v1/works</code>, <code>/v2/works</code></li>
<li><strong>Header versioning:</strong> <code>Accept: application/vnd.api+json;version=2</code></li>
<li><strong>No versioning:</strong> Only add, never break (friendliest to consumers, but hardest to sustain)</li>
</ul>
</dd>
<br/>
<br/>
<dt style="color: pink;">Granularity</dt>
<dd style="color: pink;">
<strong>Finding the right level of detail</strong>
<ul style="margin-top: 8px;">
<li><strong>Too coarse:</strong> "Here's the entire 50MB TEI file" 🚫</li>
<li><strong>Too fine:</strong> One API call per <code>g</code>, <code>l</code>, <code>y</code>, <code>p</code>, <code>h</code> 🚫</li>
<li><strong>Just right:</strong> Meaningful scholarly units ✓</li>
</ul>
</dd>
<br/>
<br/>
<dt style="color: violet;">Content Negotiation</dt>
<dd style="color: violet;">
<strong>Let users/consumers request their preferred format</strong><br/>
<span style="font-size: 0.9em;">Via parameter: <code>?formader: <code>Accept: application/xml</code></span>
</dd>
<br/>
<br/>
<dt style="color: turquoise;">Maintenance Reality</dt>
<dd style="color: turquoise;">
<strong>Every feature is a long-term commitment</strong><br/>
<span style="font-size: 0.9em;">Can we support this in 2 years? 5 years? After XY leaves the project?</span>
</dd>
</dl>
</div>
<div style="background: #e3f2fd; padding: 15px; border-left: 3px solid #f4f4f4;">
<div class="r-stretch" style="font-size:small; color:black;">
<p><strong>Versioning example:</strong></p>
<pre style="font-size: 0.7em; background: #fff; padding: 10px; border-radius: 3px;"><code><span style="color: #888;">// Version 1 (original)</span>
GET /v1/works/the-seagull
{
"title": "The Seagull",
"author": "Chekhov"
}</code>
<code><span style="color: #888;">// Version 2 (enhanced)</span>
GET /v2/works/the-seagull
{
"title": "The Seagull",
"author": {
"name": "Anton Chekhov",
"id": "chekhov-anton",
"gnd": "118638289"
},
"year": 1896
}</code></pre>
<p><strong>Granularity levels:</strong></p>
<pre style="font-size: 0.7em; background: #fff; padding: 10px; border-radius: 3px;"><code><span style="color: #888;">// Too coarse:</span>
/works/the-seagull/full
→ 50MB of TEI XML</code>
<code><span style="color: #888;">// Just right:</span>
/works/the-seagull/acts/2
→ Meaningful unit</code>
<code><span style="color: #888;">// Too fine:</span>
/works/the-seagull/words/1847
→ Single word "black"</code></pre>
</div>
</div>
</div>
<aside class="notes">
Now we get to some critical design decisions that shape an API's long-term sustainability.
**Versioning** is about how you evolve an API without breaking existing usage and applications. Imagine you launch version 1, and researchers build tools that depend on it. A year later, you want to improve the structure — maybe return author information as an object instead of a string. If you just change it, you break everyone's code.
Versioning solves this. The most common approach is **URL versioning**—you put the version number right in the path: `/v1/works` and `/v2/works`. Both can coexist. Users of v1 aren't affected when you launch v2, and they can migrate on their own timeline.
**Header versioning** is more elegant but less visible — users specify the version in a request header. It keeps URLs cleaner but makes the API slightly less intuitive.
Some teams try to avoid versioning entirely by only adding features, never changing or removing them. This works for a while but becomes unsustainable — cruft and complexity accumulate, technical debt builds up.
The hard question: **When do you deprecate old versions?** You can't maintain v1 forever, but shutting it down breaks tools people depend on. You need a deprecation policy: "We'll support each version for at least 2 years after the next version launches."
**Granularity** is about finding the right level of detail. We touched on this with resources — what units should you expose?
Too coarse is when you only offer giant dumps: "Here's the entire TEI file, 50 megabytes, parse it yourself." That's not an API, it's just file hosting. Users have to do all the work.
Too fine is exposing absurdly small units: individual words, individual characters. Nobody needs to make separate API calls for each word (unless in the rare case where it is heavily annotated). The overhead isn't worth it.
Just right depends on your content and users. For drama: acts and scenes make sense. For correspondence: individual letters. For critical editions: maybe apparatus entries or witnesses. Think about **meaningful scholarly units** — what would someone cite or analyze independently?
**Content negotiation** allows users to request different formats. We talked about offering JSON, XML, and plain text. Users can specify their preferred format via a query parameter (`?format=xml`) or via HTTP headers (`Accept: application/xml`). Headers are more "proper" REST, but parameters are more visible and easier for beginners.
And then there's the big picture: **maintenance reality**. Every feature added is a long-term commitment. That cool experimental endpoint? It'll need to be documented, supported, updated when the data structure changes, and eventually deprecated gracefully.
Here's the question that needs asking for every feature: **Can we maintain this in 2 years? 5 years? After the original developer leaves the project?**
Edition projects often outlive their initial teams. If your API design requires deep technical knowledge to maintain, what happens when that person moves on? This is why simple, well-documented, conventional designs often beat clever, optimised, custom ones.
</aside>
----
### API Planning
<div style="width: 90%; margin: 0 auto;">
<div class="r-stretch" style="font-size:medium; color: black;">
<div style="text-align: center; margin-bottom: 30px;">
<p style="font-size: 1.2em; color: #f57c00;"><strong>Balancing Ambition and Reality</strong></p>
</div>
<div style="display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 20px; margin-bottom: 40px;">
<div style="background: #ffebee; padding: 20px; padding-left:0px; border-radius: 8px; border-top: 4px solid #f44336;">
<h4 style="color: #c62828; margin-top: 0;">Underplanning</h4>
<p style="font-size: 0.9em;"><strong>"Just dump everything"</strong></p>
<ul style="font-size: 0.85em;">
<li>One giant endpoint</li>
<li>No structure or filtering</li>
<li>Users do all the work</li>
<li>Technically an API, but unusable</li>
</ul>
</div>
<div style="background: #e8f5e9; padding: 20px; padding-left:10px; border-radius: 8px; border-top: 4px solid #4caf50;">
<h4 style="color: #2e7d32; margin-top: 0;">Sweet Spot</h4>
<p style="font-size: 0.9em;"><strong>Core functionality that serves 80% of needs</strong></p>
<ul style="font-size: 0.85em;">
<li style=" margin-left:-30px;">Start with use cases</li>
<li style=" margin-left:-30px;">Essential resources only</li>
<li style=" margin-left:-30px;">Well-documented</li>
<li style=" margin-left:-30px;">Sustainable to maintain</li>
</ul>
</div>
<div style="background: #fff3e0; padding: 20px; padding-left:10px; border-radius: 8px; border-top: 4px solid #ff9800;">
<h4 style="color: #e65100; margin-top: 0;">Overplanning</h4>
<p style="font-size: 0.9em;"><strong>"The perfect API"</strong></p>
<ul style="font-size: 0.85em;">
<li style=" margin-left:-20px;">Every possible endpoint</li>
<li style=" margin-left:-20px;">Complex relationships</li>
<li style=" margin-left:-20px;">Never finished/launched</li>
<li style=" margin-left:-20px;">Unmaintainable complexity</li>
</ul>
</div>
</div>
<div style="background: #e3f2fd; padding: 25px; border-radius: 8px; border-left: 5px solid #2196f3;">
<h4 style="color: #1565c0; margin-top: 0;">How to Find the Sweet Spot</h4>
<ol style="font-size: 0.95em; line-height: 1.6;">
<li><strong>Start with use cases:</strong> What do researchers actually need to do?</li>
<li><strong>Identify core resources:</strong> What 3-5 resources serve most needs?</li>
<li><strong>Design for iteration:</strong> Launch simple, add features based on actual usage</li>
<li><strong>Ask the sustainability questions:</strong>
<ul style="margin-top: 8px;">
<li>Can we document this thoroughly?</li>
<li>Can we maintain it in 2 years? 5 years?</li>
<li>What happens when the developer leaves?</li>
<li>Is this complexity actually serving user needs?</li>
</ul>
</li>
</ol>
</div>
<div style="text-align: center; margin-top: 30px; padding: 20px; background: #fff8e1; border-radius: 8px;">
<p style="font-size: 1.1em; color: #f57c00; margin: 0;"><strong>💡 Remember: A simple, well-maintained API beats a complex, abandoned one.</strong></p>
</div>
</div>
</div>
<aside class="notes">
Planning an API may be seen as a spectrum, from **underplanning** to **overplanning** with a golden zone in between. It pays off to think thoroughly about a new API and this thinking should be based on actual use-cases (not hypothetical ones, but real research questions from the community). What do people want to do with your data? Quote passages? Compare witnesses? Analyze character networks? Find letters by date range?
<!--Let's talk about the **underplanning pitfall** first. This is when you think "we'll just expose our data via an API" without actually designing for use cases. You create one endpoint that dumps your entire database or serves your complete TEI files with no structure or filtering.
Technically, yes, that's an API. But it's not useful. Users have to parse enormous responses, filter through irrelevant data, and essentially rebuild the structure you should have provided. You've shifted all the complexity onto them. This isn't sustainable — not for users, and ironically not for you either, because you'll get constant support requests asking how to work with your data.
The opposite extreme is **overplanning**. This is when you design the perfect, comprehensive API that exposes every possible resource at every possible granularity with every possible relationship and filtering option. You spend months or years planning and building, trying to anticipate every conceivable use case.
The problem? Perfect is the enemy of done. These projects often never launch, or they launch so late that requirements have changed. And even if you do launch, the complexity makes maintenance a nightmare. Every data structure change ripples through dozens of endpoints. Documentation is overwhelming. New team members can't understand the system.
The **sweet spot** is designing core functionality that serves 80% of user needs.-->
From those use cases, the **essential resources** can be identified. Maybe 3-5 core resource types that enable those research questions. Not every conceivable slice of an edition's data, just the ones that matter most. A thoughtful design is complemented by sound documentation and — this is key — **the actual launch**. Iteration then happens based on actual usage patterns, not guesses. When users consistently ask for something that doesn't exist, is is worth adding it. When something sees no usage, maybe deprecate it more advisable than maintaining it forever.
These **sustainability questions** should shape the decision framework: For every feature you're considering, ask:
Can we document this thoroughly? If it can't be explained clearly, users can't use it effectively.
Can it be maintained in 2 years? 5 years? The content will change, data structures might evolve. Is this feature worth updating every time?
What happens when the original developer leaves? Can her successor understand and maintain this? Is it conventional enough that someone new can figure it out?
And critically: **Is this complexity actually serving user needs?** Or are you building it because it's technically interesting? Because it might be useful someday? Honesty wins.
Here's the hard truth: **A simple, well-maintained API beats a complex, abandoned one every single time.**
How will digital scholarly editions and their APIs endure? By keeping things sustainable, documented, focused.
</aside>
----
### Beyond REST: Other Approaches
<p style="text-align: center; font-size: medium; margin-bottom: 15px;">REST covers 95% of edition use cases, but there are a few alternatives:</p>
<div style="transform: scale(0.75); transform-origin: top center; width: 85%; margin: 0 auto; color: black;">
<div class="r-stretch" style="font-size:medium;">
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 30px; margin-bottom: 30px;">
<div style="background: #f3e5f5; padding: 10px; border-radius: 8px; border-left: 4px solid #9c27b0;">
<h4 style="color: #6a1b9a; margin-top: 0;">GraphQL</h4>
<p style="font-size: 0.9em; margin-bottom: 12px;"><strong>What it is:</strong> Query language where clients request exactly the data they need</p>
<p style="font-size: 0.85em; margin-bottom: 12px;"><strong>Good for:</strong> Complex, deeply interconnected data; reducing over-fetching</p>
<p style="font-size: 0.85em;"><strong>Trade-off:</strong> More complex to implement and maintain; steeper learning curve</p>
<pre style="font-size: 0.7em; background: #fff; padding: 10px; border-radius: 3px; margin-top: 12px;"><code>{
work(id: "the-seagull") {
title
lines(speaker: "nina") {
text
}
}
}</code></pre>
</div>
<div style="background: #e8f5e9; padding: 10px; border-radius: 8px; border-left: 4px solid #4caf50;">
<h4 style="color: #2e7d32; margin-top: 0;">SPARQL</h4>
<p style="font-size: 0.9em; margin-bottom: 12px;"><strong>What it is:</strong> Query language for RDF/Linked Data</p>
<p style="font-size: 0.85em; margin-bottom: 12px;"><strong>Good for:</strong> Semantic web integration; </p>federated queries across datasets</p>
<p style="font-size: 0.85em;"><strong>Trade-off:</strong> Requires RDF modeling; <br/>relatively niche user base</p>
<pre style="font-size: 0.7em; background: #fff; padding: 10px; border-radius: 3px; margin-top: 12px;"><code>SELECT ?work ?title
WHERE {
?work a :DramaticWork ;
:author :Chekhov ;
:title ?title .
}</code></pre>
</div>
<div style="background: #e3f2fd; padding: 10px; border-radius: 8px; border-left: 4px solid #2196f3;">
<h4 style="color: #1565c0; margin-top: 0;">gRPC</h4>
<p style="font-size: 0.9em; margin-bottom: 12px;"><strong>What it is:</strong> High-performance RPC framework using Protocol Buffers</p>
<p style="font-size: 0.85em; margin-bottom: 12px;"><strong>Good for:</strong> Microservices; internal APIs; real-time performance</p>
<p style="font-size: 0.85em;"><strong>Trade-off:</strong> Not web-friendly; requires specialised tooling</p>
</div>
<div style="background: #fff3e0; padding: 10px; border-radius: 8px; border-left: 4px solid #ff9800;">
<h4 style="color: #e65100; margin-top: 0;">JSON-RPC / XML-RPC</h4>
<p style="font-size: 0.9em; margin-bottom: 12px;"><strong>What it is:</strong> Simple remote procedure call protocols</p>
<p style="font-size: 0.85em; margin-bottom: 12px;"><strong>Good for:</strong> Simple, action-oriented APIs (less common today)</p>
<p style="font-size: 0.85em;"><strong>Trade-off:</strong> Less standardised than REST; smaller ecosystem</p>
</div>
</div>
<div style="background: #fff8e1; padding: 10px; border-radius: 8px; border-left: 5px solid #ffc107; text-align: center;">
<p style="font-size: 1em; color: #f57c00; margin: 0;"><strong>For most digital scholarly editions: REST is best.</strong></p>
<p style="font-size: 0.9em; margin: 10px 0 0 0;">It's well-understood, well-documented, sustainable, and covers the vast majority of use cases.</p>
</div>
</div>
</div>
<aside class="notes">
You might encounter other API architectures in the Digital Humanities, GLAM, or web landscape, so it's worth knowing they exist — even if REST remains the best choice for most edition projects.
**GraphQL** has gotten a lot of attention in recent years. Instead of REST's fixed endpoints, GraphQL lets clients write queries requesting exactly the data they need. Want just the title and Nina's lines from The Seagull? You can request precisely that, nothing more. This is powerful for complex, interconnected data where REST might require multiple requests or return lots of irrelevant information.
But GraphQL is **more complex to implement and maintain**. You need specialised server libraries, and users need to learn the query language. For most editions, this complexity isn't worth it — REST with good parameter filtering achieves similar results with less overhead.
**SPARQL** is the query language for RDF and Linked Data. If you're fully committed to the semantic web — modeling your data as RDF triples, linking to authorities and vocabularies — SPARQL endpoints make sense (and we'll see one later in the workshop). They enable incredibly powerful federated queries across multiple datasets.
But SPARQL has a steep learning curve, both for implementers and users. The user base is smaller than REST. Unless Linked Open Data is central to your project's mission, SPARQL might be overengineering.
**gRPC** is a high-performance protocol developed by Google, using binary serialization (Protocol Buffers) instead of text-based JSON. It's fast and efficient — great for microservices architectures or internal APIs where different services need to communicate.
But it's not web-friendly. You can't just type a URL in a browser or use curl from the command line. It requires special tooling. For public-facing edition APIs, this is usually a non-starter.
**JSON-RPC and XML-RPC** are older, simpler remote procedure call protocols. Instead of resources and HTTP methods, you just call named functions with parameters. They're straightforward but less standardised than REST, with smaller ecosystems of tools and libraries.
The baseline: **For most digital scholarly editions, start with REST** as it is the path of least resistance and is well-understood by developers across disciplines. There are abundant tools, libraries, and examples. Documentation patterns are established. Hosting and scaling are straightforward.
If you have specific needs — truly complex interconnected data, deep Linked Data integration, performance-critical internal services — then consider alternatives. But evaluate them honestly against REST. Often, what seems like a need for GraphQL or SPARQL can be met with thoughtful REST design.
And remember sustainability: will your successor understand and maintain GraphQL? Can you find developers who know SPARQL when you need help? REST's ubiquity is a sustainability feature, not just a convenience.
It is worth knowing that these alternatives exist and to understand what problems they solve. And while the use-case based conceptual would align well, we decided to solely focus on the REST architecture for this workshop and introduction to APIs.
</aside>
---
---
<h2 style="color:#FFC600;">
4. Hands-on
</h2>
---
Try it out:
[https://openlibrary.org/swagger/docs](https://openlibrary.org/swagger/docs)
<div style="font-size:0.7em"><br/>
Example: find all the works by Friedrich Dürrenmatt
- Open the section GET /search.json and click 'Try it out'
- Write 'Dürrenmatt' in the query field 'q'
- Execute and look for the author key in the result
- Dürrenmatt author key (or OLID) is 'OL4331255A'
- Go to the section GET /authors/{olid}/works.json and click 'Try it out'
- Insert the OLID number and execute
</div>
---
### Resources (the other kind)
<div style="width: 90%; margin: 0 auto;">
<div class="r-stretch" style="font-size:small;">
<div style="background: #e8f5e9; padding: 25px; border-radius: 8px; border-left: 4px solid #4caf50; margin-bottom: 25px; color: #4C4E52;">
<h4 style="color: #2e7d32; margin-top: 0;">Literature</h4>
<ul style="font-size: 0.95em; line-height: 1.7; columns: 1;">
<li><strong>Mike Amundsen</strong>, <em>Design and Build Great Web APIs. Robust, Reliable, and Resilient</em>, The Pragmatic Programmers 2020</li>
<li><strong>Mike Amundsen</strong>, <em>RESTful Web API Patterns & Practices Cookbook. Connecting and Orchestrating Microservices and Distributed Data</em>, O'Reilly 2022</li>
<li><strong>Matthias Biehl</strong>, <em>API Architecture. The Big Picture for Building APIs</em>, API University Series 2015</li>
<li><strong>James Gough, Daniel Bryant & Mathew Auburn</strong>, <em>Mastering API Architecture. Design, Operate, and Evolve API-Based Systems</em>, O'Reilly 2023</li>
<li><strong>Arnaud Lauret</strong>, <em><a href="https://ieeexplore.ieee.org/book/11079742">The Design of Web APIs</a></em>, Manning 2025</li>
<li><strong>Mark Massé</strong>, <em>REST API Design Rulebook. Designing Consistent RESTful Web Service Interfaces</em>, O'Reilly 2012</li>
<li><strong>Brian Mulloy</strong>, <em><a href="https://cloud.google.com/files/apigee/apigee-web-api-design-the-missing-link-ebook.pdf">Web API Design. Crafting Interfaces that Developers Love</a></em>, 2018<br/>
<span style="font-size: 0.85em; color: #f57c00;">→ A good degree of opinionated and openly licensed as CC-BY-SA</span></li>
</ul>
<hr style="margin: 18px 0; border: none; border-top: 1px solid #c8e6c9;">
<p style="font-size: 0.9em; margin: 12px 0 0 0; line-height: 1.5;">Some ideas and concepts were bounced to <strong>Perplexity</strong>, <strong>Qwen AI</strong> and <strong>Claude Sonnet 4.5</strong>, and <strong>Gemini's Nano Banana Pro</strong> generated the Soviet-times cloakroom hanger tag.</p>
</div>
<div style="background: #e3f2fd; padding: 25px; border-radius: 8px; border-left: 4px solid #2196f3; color: #4C4E52;">
<h4 style="color: #1565c0; margin-top: 0;">Useful to Experiment</h4>
<ul style="font-size: 0.95em; line-height: 1.9;">
<li><strong><a href="https://rapid.rocks/api-designer/index.html">RAPID API Designer</a></strong> — Browser-based API designer by the RAPID community
<span style="font-size: 0.85em;">(<a href="https://github.com/oasis-open/odata-rapid">github.com/oasis-open/odata-rapid</a>)</span></li>
<li><strong><a href="https://petstore.swagger.io">Swagger Petstore</a></strong> — OpenAPI / Swagger sandbox</li>
<li><strong><a href="https://hoppscotch.io">Hoppscotch</a></strong> — Fast, lightweight open source API development suite (alternative to Postman)
<span style="font-size: 0.85em;">(<a href="https://github.com/hoppscotch/hoppscotch">github.com/hoppscotch/hoppscotch</a>)</span></li>
<li><strong><a href="https://reqbin.com">ReqBin</a></strong> — Online REST & SOAP API testing tool</li>
<li><strong><a href="https://httpbin.org">HTTPBin</a></strong> — Simple HTTP Request & Response Service</li>
</ul>
</div>
</div>
</div>
<aside class="notes">
This presentation drew on several excellent resources about API design — if you want to go deeper, these books are all worth checking. Mike Amundsen's books are particularly strong on practical patterns and modern API architecture. Arnaud Lauret's "The Design of Web APIs" is comprehensive and recent. And Brian Mulloy's shorter guide is freely available and refreshingly opinionated — great for getting clear, actionable advice quickly.
On the tools side, these are all free resources you can use to experiment with APIs. RAPID and Swagger let you design and test APIs in your browser. Hoppscotch is a modern, open-source alternative to Postman if you need a more full-featured client. ReqBin and HTTPBin are great for quick testing and understanding how HTTP works.
I encourage you to play with these tools — the best way to understand APIs is to use them, not just read about them. Try making requests, see what responses look like, experiment with parameters.
</aside>
---
{"title":"Intro to APIs (for DH)","tags":"presentation, resed","slideOptions":{"transition":"slide","navigationMode":"linear","previewLinks":true}}