Skip to content

Commit e3da99e

Browse files
committed
Update API documentation
1 parent c148362 commit e3da99e

1 file changed

Lines changed: 242 additions & 0 deletions

File tree

public/API.html

Lines changed: 242 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,8 @@ <h1 id="api-100">API (1.0.0)</h1>
5959
<li><a href="#create">Create</a></li>
6060
<li><a href="#bulk-create">Bulk Create</a></li>
6161
<li><a href="#custom-query">Custom Query</a></li>
62+
<li><a href="#text-search">Text Search</a></li>
63+
<li><a href="#phrase-search">Phrase Search</a></li>
6264
<li><a href="#http-post-method-override">HTTP POST Method Override</a></li>
6365
</ul>
6466
</li>
@@ -504,6 +506,246 @@ <h3 id="custom-query">Custom Query</h3>
504506
<span>}</span>
505507
</code></pre>
506508
</p>
509+
<h3 id="text-search">Text Search</h3>
510+
<table>
511+
<thead>
512+
<tr>
513+
<th>Pattern</th>
514+
<th>Payload</th>
515+
<th>Response</th>
516+
</tr>
517+
</thead>
518+
<tbody>
519+
<tr>
520+
<td><code class="language-plaintext highlighter-rouge">/search?limit=100&skip=0</code></td>
521+
<td><code class="language-plaintext highlighter-rouge">{JSON} or "string"</code></td>
522+
<td>200 <code class="language-plaintext highlighter-rouge">[{JSON}]</code></td>
523+
</tr>
524+
</tbody>
525+
</table>
526+
<ul>
527+
<li><strong><code class="language-plaintext highlighter-rouge">{JSON}</code></strong>—An object with a <code class="language-plaintext highlighter-rouge">searchText</code> property containing the text to search for, and an optional <code class="language-plaintext highlighter-rouge">options</code> property for search configuration</li>
528+
<li><strong><code class="language-plaintext highlighter-rouge">"string"</code></strong>—Alternatively, a plain string to search for</li>
529+
<li><strong>Response: <code class="language-plaintext highlighter-rouge">[{JSON}]</code></strong>—An array of annotation objects matching the search, sorted by relevance score</li>
530+
</ul>
531+
<p>
532+
The Text Search endpoint performs a full-text search across annotation text content in both IIIF Presentation API 3.0 and 2.1 resources. This endpoint searches for exact word matches (case-insensitive) and tokenizes the search text, finding documents that contain all the search terms anywhere in their text content.
533+
</p>
534+
<p>
535+
The search covers multiple text fields depending on the IIIF version:
536+
</p>
537+
<ul>
538+
<li><strong>IIIF 3.0 fields:</strong> <code class="language-plaintext highlighter-rouge">body.value</code>, <code class="language-plaintext highlighter-rouge">bodyValue</code>, and nested structures in <code class="language-plaintext highlighter-rouge">items</code> and <code class="language-plaintext highlighter-rouge">annotations</code></li>
539+
<li><strong>IIIF 2.1 fields:</strong> <code class="language-plaintext highlighter-rouge">resource.chars</code>, <code class="language-plaintext highlighter-rouge">resource.cnt:chars</code>, and nested structures in AnnotationLists, Canvas <code class="language-plaintext highlighter-rouge">otherContent</code>, and Manifest sequences</li>
540+
</ul>
541+
<p>
542+
Search behavior:
543+
</p>
544+
<ul>
545+
<li>Searches are case-insensitive</li>
546+
<li>Standard linguistic analysis is applied (stemming, stop words, etc.)</li>
547+
<li>Multi-word searches find documents containing <strong>all</strong> the words (AND logic)</li>
548+
<li>Partial word matches are NOT supported (use wildcards for that)</li>
549+
<li>Results are sorted by relevance score (highest first)</li>
550+
<li>A <code class="language-plaintext highlighter-rouge">__rerum.score</code> property is added to each result indicating match quality</li>
551+
</ul>
552+
<p>
553+
The <code class="language-plaintext highlighter-rouge">limit</code> and <code class="language-plaintext highlighter-rouge">skip</code> URL parameters can be used for pagination. By default, <code class="language-plaintext highlighter-rouge">limit=100</code> and <code class="language-plaintext highlighter-rouge">skip=0</code>. It is recommended to use a limit of 100 or less for optimal performance.
554+
</p>
555+
<p class="alert">
556+
Note: This endpoint requires MongoDB Atlas Search indexes named "presi3AnnotationText" and "presi2AnnotationText" to be configured on the database.
557+
</p>
558+
<p>
559+
<div class="exHeading">Javascript Example (JSON Object)</div>
560+
<pre><code class="jsExample">
561+
<span>const search_results = await fetch("https://devstore.rerum.io/v1/api/search?limit=50&skip=0", {</span>
562+
<span class="ind1">method: "POST",</span>
563+
<span class="ind1">headers:{</span>
564+
<span class="ind2">"Content-Type": "application/json; charset=utf-8"</span>
565+
<span class="ind1">},</span>
566+
<span class="ind1">body: JSON.stringify({</span>
567+
<span class="ind2">"searchText": "medieval manuscript illumination"</span>
568+
<span class="ind1">})</span>
569+
<span>})</span>
570+
<span>.then(resp => resp.json())</span>
571+
<span>.catch(err => {throw err})</span>
572+
</code></pre>
573+
</p>
574+
<p>
575+
<div class="exHeading">Javascript Example (Plain String)</div>
576+
<pre><code class="jsExample">
577+
<span>const search_results = await fetch("https://devstore.rerum.io/v1/api/search", {</span>
578+
<span class="ind1">method: "POST",</span>
579+
<span class="ind1">headers:{</span>
580+
<span class="ind2">"Content-Type": "application/json; charset=utf-8"</span>
581+
<span class="ind1">},</span>
582+
<span class="ind1">body: JSON.stringify("medieval manuscript")</span>
583+
<span>})</span>
584+
<span>.then(resp => resp.json())</span>
585+
<span>.catch(err => {throw err})</span>
586+
</code></pre>
587+
</p>
588+
<p>
589+
<div class="exHeading">Here is what the response <code>resp</code> looks like:</div>
590+
<pre><code class="respExample">
591+
<span>[</span>
592+
<span class="ind1">{</span>
593+
<span class="ind2">"@id": "https://devstore.rerum.io/v1/id/abcdef1234567890",</span>
594+
<span class="ind2">"type": "Annotation",</span>
595+
<span class="ind2">"body": {</span>
596+
<span class="ind3">"value": "This medieval manuscript contains beautiful illumination..."</span>
597+
<span class="ind2">},</span>
598+
<span class="ind2">"__rerum":{</span>
599+
<span class="ind3">...,</span>
600+
<span class="ind3">"score": 4.567</span>
601+
<span class="ind2">}</span>
602+
<span class="ind1">},</span>
603+
<span class="ind1">{</span>
604+
<span class="ind2">"@id": "https://devstore.rerum.io/v1/id/1234567890abcdef",</span>
605+
<span class="ind2">"type": "Annotation",</span>
606+
<span class="ind2">"bodyValue": "Study of manuscript illumination from the medieval period",</span>
607+
<span class="ind2">"__rerum":{</span>
608+
<span class="ind3">...,</span>
609+
<span class="ind3">"score": 3.892</span>
610+
<span class="ind2">}</span>
611+
<span class="ind1">},</span>
612+
<span class="ind1">...</span>
613+
<span>]</span>
614+
</code></pre>
615+
<p class="alert">
616+
Results are returned sorted by relevance score in descending order. The <code>__rerum.score</code> property indicates match quality.
617+
</p>
618+
</p>
619+
<h3 id="phrase-search">Phrase Search</h3>
620+
<table>
621+
<thead>
622+
<tr>
623+
<th>Pattern</th>
624+
<th>Payload</th>
625+
<th>Response</th>
626+
</tr>
627+
</thead>
628+
<tbody>
629+
<tr>
630+
<td><code class="language-plaintext highlighter-rouge">/search/phrase?limit=100&skip=0</code></td>
631+
<td><code class="language-plaintext highlighter-rouge">{JSON} or "string"</code></td>
632+
<td>200 <code class="language-plaintext highlighter-rouge">[{JSON}]</code></td>
633+
</tr>
634+
</tbody>
635+
</table>
636+
<ul>
637+
<li><strong><code class="language-plaintext highlighter-rouge">{JSON}</code></strong>—An object with a <code class="language-plaintext highlighter-rouge">searchText</code> property containing the phrase to search for, and an optional <code class="language-plaintext highlighter-rouge">options</code> property (default <code>slop: 2</code>)</li>
638+
<li><strong><code class="language-plaintext highlighter-rouge">"string"</code></strong>—Alternatively, a plain string phrase to search for</li>
639+
<li><strong>Response: <code class="language-plaintext highlighter-rouge">[{JSON}]</code></strong>—An array of annotation objects matching the phrase search, sorted by relevance score</li>
640+
</ul>
641+
<p>
642+
The Phrase Search endpoint performs a proximity-based search for multi-word phrases, finding documents where search terms appear near each other in sequence. This is more precise than standard text search for multi-word queries while still being flexible enough to allow for minor variations.
643+
</p>
644+
<p>
645+
The phrase search uses a "slop" value (default: 2) that allows up to 2 intervening words between search terms. This means the words don't need to be directly adjacent, providing flexibility while maintaining phrase coherence.
646+
</p>
647+
<p>
648+
Like the standard text search, this endpoint searches across both IIIF Presentation API 3.0 and 2.1 resources, covering the same text fields.
649+
</p>
650+
<p>
651+
Phrase matching examples with slop: 2:
652+
</p>
653+
<ul>
654+
<li><code>"medieval manuscript"</code> matches:
655+
<ul>
656+
<li>✓ "medieval manuscript"</li>
657+
<li>✓ "medieval illuminated manuscript"</li>
658+
<li>✓ "manuscript from medieval times"</li>
659+
<li>✗ "medieval art with many beautiful decorated manuscripts" (too many words between)</li>
660+
</ul>
661+
</li>
662+
<li><code>"Bryan Haberberger"</code> matches:
663+
<ul>
664+
<li>✓ "Bryan Haberberger"</li>
665+
<li>✓ "Bryan the Haberberger"</li>
666+
<li>✓ "Bryan A. Haberberger"</li>
667+
<li>✗ "Bryan loves to eat hamburgers with Haberberger" (too many words between)</li>
668+
</ul>
669+
</li>
670+
</ul>
671+
<p>
672+
Use cases:
673+
</p>
674+
<ul>
675+
<li>Finding exact or near-exact phrases</li>
676+
<li>Searching for names or titles</li>
677+
<li>Looking for specific multi-word concepts</li>
678+
<li>When you need more precision than standard search but more flexibility than exact matching</li>
679+
</ul>
680+
<p>
681+
The <code class="language-plaintext highlighter-rouge">limit</code> and <code class="language-plaintext highlighter-rouge">skip</code> URL parameters work the same as in the standard text search endpoint for pagination support.
682+
</p>
683+
<p>
684+
<div class="exHeading">Javascript Example</div>
685+
<pre><code class="jsExample">
686+
<span>const phrase_results = await fetch("https://devstore.rerum.io/v1/api/search/phrase?limit=50", {</span>
687+
<span class="ind1">method: "POST",</span>
688+
<span class="ind1">headers:{</span>
689+
<span class="ind2">"Content-Type": "application/json; charset=utf-8"</span>
690+
<span class="ind1">},</span>
691+
<span class="ind1">body: JSON.stringify({</span>
692+
<span class="ind2">"searchText": "illuminated manuscript"</span>
693+
<span class="ind1">})</span>
694+
<span>})</span>
695+
<span>.then(resp => resp.json())</span>
696+
<span>.catch(err => {throw err})</span>
697+
</code></pre>
698+
</p>
699+
<p>
700+
<div class="exHeading">Javascript Example with Custom Slop</div>
701+
<pre><code class="jsExample">
702+
<span>const phrase_results = await fetch("https://devstore.rerum.io/v1/api/search/phrase", {</span>
703+
<span class="ind1">method: "POST",</span>
704+
<span class="ind1">headers:{</span>
705+
<span class="ind2">"Content-Type": "application/json; charset=utf-8"</span>
706+
<span class="ind1">},</span>
707+
<span class="ind1">body: JSON.stringify({</span>
708+
<span class="ind2">"searchText": "illuminated manuscript",</span>
709+
<span class="ind2">"options": {</span>
710+
<span class="ind3">"slop": 5</span>
711+
<span class="ind2">}</span>
712+
<span class="ind1">})</span>
713+
<span>})</span>
714+
<span>.then(resp => resp.json())</span>
715+
<span>.catch(err => {throw err})</span>
716+
</code></pre>
717+
</p>
718+
<p>
719+
<div class="exHeading">Here is what the response <code>resp</code> looks like:</div>
720+
<pre><code class="respExample">
721+
<span>[</span>
722+
<span class="ind1">{</span>
723+
<span class="ind2">"@id": "https://devstore.rerum.io/v1/id/fedcba0987654321",</span>
724+
<span class="ind2">"type": "Annotation",</span>
725+
<span class="ind2">"body": {</span>
726+
<span class="ind3">"value": "The beautifully illuminated medieval manuscript..."</span>
727+
<span class="ind2">},</span>
728+
<span class="ind2">"__rerum":{</span>
729+
<span class="ind3">...,</span>
730+
<span class="ind3">"score": 5.234</span>
731+
<span class="ind2">}</span>
732+
<span class="ind1">},</span>
733+
<span class="ind1">{</span>
734+
<span class="ind2">"@id": "https://devstore.rerum.io/v1/id/9876543210fedcba",</span>
735+
<span class="ind2">"type": "Annotation",</span>
736+
<span class="ind2">"bodyValue": "This manuscript features illuminated letters",</span>
737+
<span class="ind2">"__rerum":{</span>
738+
<span class="ind3">...,</span>
739+
<span class="ind3">"score": 4.781</span>
740+
<span class="ind2">}</span>
741+
<span class="ind1">},</span>
742+
<span class="ind1">...</span>
743+
<span>]</span>
744+
</code></pre>
745+
<p class="alert">
746+
Phrase search is generally faster than wildcard search and provides a good balance of precision and recall. Results are sorted by relevance with the <code>__rerum.score</code> property indicating match quality.
747+
</p>
748+
</p>
507749
<h3 id="http-post-method-override">HTTP POST Method Override</h3>
508750
<p class="alert"> This section is non-normative. </p>
509751
<p>

0 commit comments

Comments
 (0)