Skip to content

omnischolar/openlibrary

Omnischolar Open Library: an author's books, one record per edition with ISBNs, publisher and cover, for the Merger to group - no key.

Floor
Provider · Omnischolar
Version
1.x
Conformance suite
not wired
Verified for real
Its README does not say
Licence
MIT
composer require omnischolar/openlibrary:1.x-dev

Open Library, the Internet Archive's catalogue of books, for omnisense/omnischolar: an author's books - by their Open Library id or their name, every spelling of it - one record per edition, each with its ISBNs, publisher, date and cover (the Merger groups the editions of a book); a book by ISBN or Open Library id; a search; an author's page. The source calls Open Library's JSON API, without a key:

Operation Request
works($author) GET https://openlibrary.org/search.json?q=author_key:<OL...A> or ?author=<name>, &fields=&sort=&limit=&page=; then works/<OL...W>/editions.json?limit=50 for each work with several editions
work($id) GET .../isbn/<isbn>.json or books/<OL...M>.json, then search.json?q=key:<work> for the authors' names; OL...W: search.json?q=key:/works/<id>
search($query) GET .../search.json?q=<text>&title=&author=
author($id) GET .../authors/<OL...A>.json; a name: search/authors.json?q=<name>&limit=1 first

Covers are served from https://covers.openlibrary.org/b/id/<id>-L.jpg (OpenLibrarySource::COVERS). The base address is OpenLibrarySource::BASE_URI (https://openlibrary.org/).

Installation

composer require omnischolar/openlibrary

Requires PHP 8.2, omnisense/omnischolar (1.x) and symfony/http-client (6.4, 7 or 8). In a Symfony application with OmnischolarBundle, the factory is registered as soon as the package is installed.

Credentials

None. Open Library asks its callers to name themselves in the User-Agent, with a contact (the mailto), and allows about three calls a second to a named caller: the default throttle leaves 0.4 s between two.

Options

Option Type Default Required
editions bool true no one record per edition (a work's editions read in one more call each); false: one record per work
throttle float 0.4 no seconds between two calls
mailto string null no added to the User-Agent
user_agent string omnischolar/1.x (+https://github.com/glitchr-omnisense/omnischolar) and the mailto no
base_uri string https://openlibrary.org/ no

editions is read with PHP's (bool): give a real boolean.

Capabilities

capabilities(): author, works, work, search, covers.

Operation Supported Reads
author() yes OL...A, or the first author record a name finds
works() yes OL...A (only the books filed under it), or a name (every author record of that name: "Monica Neagoy", "MONICA NEAGOY", "Monica M. Neagoy")
work() yes ISBN (that edition), OL...M (an edition), OL...W (a work); an OL...A is refused
search() yes text (q), title, author

Behaviour

Query. from/to → first_publish_year:[from TO to]; types without BOOK gives an empty page without a call; domains is refused; openAccess is not read. sort: oldest → old, relevance → Open Library's own, any other → new. limit 1 to 100; the cursor is a page number (from 1), the next one given while a full page came and the total is not reached; Page::$total is numFound.

Editions. With editions: true, each work with more than one edition is read again (editions.json, 50 at most) and gives one record per edition: a page of 25 works may cost as many calls - hence the throttle. A work with a single edition is read from the search alone.

A book. Title and subtitle, type book, authors (each name once; ALL CAPS put in title case; their Open Library ids), year and date (Open Library's free-text date read as ISO 8601: "Feb 18, 2020" is 2020-02-18, "March 2012" 2012-03, else the year found in it), publisher, edition statement, description as abstract, language (MARC codes as ISO 639-1 where there is one), the edition's page, its cover; identifiers: the edition's and the work's Open Library ids, every ISBN (as ISBN-13). With editions: false: the work's first publication year, every ISBN of every edition, its cover.

An author. Name, the Open Library id and the ORCID when the record has one, the personal and alternate names, the Open Library page, the record's links and its Wikidata page, the biography.

Example

<?php

require __DIR__.'/vendor/autoload.php';

use Omnischolar\OpenLibrary\OpenLibrarySourceFactory;
use Symfony\Component\HttpClient\HttpClient;

$openlibrary = (new OpenLibrarySourceFactory(HttpClient::create()))->create(['mailto' => getenv('OMNISCHOLAR_MAILTO') ?: null]);

$w = $openlibrary->work('9781412996600');
echo $w->fullTitle(), "\n  ", $w->publisher, ', ', $w->date, ', ', implode(' ', $w->isbns()), "\n  cover: ", $w->cover, "\n";
Planting the seeds of algebra, PreK-2: explorations for the early grades
  Corwin Press, 2012, 9781412996600
  cover: 

(called live on 2026-10-26 at 14:18 UTC, from the core's harness image, without a mailto; that edition has no cover on Open Library)

From the core's harness, the editions grouped by the Merger: docker compose run --rm omnischolar merge openlibrary:"Monica Neagoy" crossref:"Monica Neagoy".

In Symfony:

omnischolar:
    sources:
        openlibrary: { factory: openlibrary, options: { mailto: '%env(OMNISCHOLAR_MAILTO)%' } }

Errors

Case Result
an unknown book or author null
an identifier it does not read, an OL...A given to work(); domains NotSupportedException
another 4xx ProviderException
a 429 RateLimitedException
a 5xx, a timeout UnavailableException

Verified, and not

Tested offline: Tests/OpenLibrarySourceTest.php (6 tests), on MockHttpClient with answers recorded on 2026-10-04 - search.json?author=Monica Neagoy (nine works, three author records), the editions of the two works that have two, her author page, an edition by ISBN and its work; the Merger grouping the editions of Planting the Seeds of Algebra, PreK-2 (2012, filed twice, and 2016) into one book, and keeping the two volumes of the Méthode de Singapour CE1 apart. Called live on 2026-10-04 and on 2026-10-26 (the example above).

Limits of the service: books only - no articles, no citations, no metrics, rarely an abstract. Its records are entered by hand: the same book is sometimes filed twice (two works with one ISBN: the Merger joins them), an author is sometimes split into several records (searching by name covers them), some text is badly encoded.

Responsibility

An independent, unofficial client, not affiliated with the Internet Archive (Open Library). Whoever runs it complies with the Internet Archive's terms (archive.org/about/terms): see the README's Responsibility section.

Propose a change docs/index.md