-
-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Endpoints
Page | Screenshot | URL Endpoints → Controllers | Templates | Models | Reference PRs | Maintainer |
---|---|---|---|---|---|---|
Homepage | ![]() |
/ |
home.html |
@mekarpeles |
||
Books Page | ![]() |
/books/OL{edition_id}M/ /works/OL{work_id}W/ |
type/edition/view.html |
Edition + Work which extend core/models.py
|
Unified Books Page: Merging Work & Edition UI #123 | @jimchamp |
Subjects Page | ![]() |
/subjects/{subject} |
subjects.html |
@jimchamp |
||
Search Page | ![]() |
/search?q={query} |
work_search.html |
@cdrini |
||
Account Creation | ![]() |
/account/create |
create.html |
@cdrini |
||
Account Login | ![]() |
/account/login |
login.html |
@cdrini |
||
My Books Page | ![]() |
/account/books → /people/{username}/books
|
account/view.html |
My Books page interim Mobile Navigation Fixes #6860 |
@mekarpeles @szgrune
|
An Explorer's Map to the Chasm Which is Open Library -- A mapping of url routes (endpoints) and the files in which they appear. Informed via: grep -ri "path = "[/]" *
`## Infogami`
`Infogami default routes:`
`infogami/core/code.py: path = "/account/login"`
`infogami/core/code.py: path = "/account/register"`
`infogami/core/code.py: path = "/account/logout"`
`infogami/core/code.py: path = "/account/forgot_password"`
`infogami/core/code.py: path = "/account/reset_password"`
`infogami/core/code.py: path = "/account/preferences"`
`infogami/core/code.py: path = "/account/preferences/change_password"`
`infogami/core/code.py: path = "/favicon.ico"`
`infogami/plugins/api/code.py: path = "/api/(.*)"`
`infogami/plugins/api/code.py: path = "/account/login"`
`infogami/plugins/wikitemplates/code.py: path = "/account/preferences/template_preferences"`
`vendor/infogami/infogami/core/code.py: path = "/account/login"`
`vendor/infogami/infogami/core/code.py: path = "/account/register"`
`vendor/infogami/infogami/core/code.py: path = "/account/logout"`
`vendor/infogami/infogami/core/code.py: path = "/account/forgot_password"`
`vendor/infogami/infogami/core/code.py: path = "/account/reset_password"`
`vendor/infogami/infogami/core/code.py: path = "/account/preferences"`
`vendor/infogami/infogami/core/code.py: path = "/account/preferences/change_password"`
`vendor/infogami/infogami/core/code.py: path = "/favicon.ico"`
`vendor/infogami/infogami/infobase/client.py: path = "/" + sitename + path`
`vendor/infogami/infogami/plugins/api/code.py: path = "/api/(.*)"`
`vendor/infogami/infogami/plugins/api/code.py: path = "/account/login"`
`vendor/infogami/infogami/plugins/wikitemplates/code.py: path = "/account/preferences/template_preferences"`
`## Open Library`
`Home Page:`
`openlibrary/plugins/openlibrary/home.py: path = "/"`
`Admin & Devops Endpoints:`
`openlibrary/admin/code.py: path = "/admin/?"`
`openlibrary/plugins/admin/code.py: path = "/admin(?:/.*)?"`
`openlibrary/plugins/admin/mem.py: path = "/memory"`
`openlibrary/plugins/admin/mem.py: path = "/memory/type/(.*)"`
`openlibrary/plugins/admin/mem.py: path = "/memory/id/(.*)"`
`openlibrary/plugins/openlibrary/dev_instance.py: path = "/_dev/process_ebooks"`
`Entities:`
`Books:`
`openlibrary/core/models.py: types.register_type('^/books/[^/]*$', '/type/edition')`
`openlibrary/plugins/books/code.py:add_hook("books", books)`
`openlibrary/plugins/upstream/addbook.py: path = "(/books/.*)/daisy"`
`openlibrary/plugins/upstream/addbook.py: path = "(/books/OL\d+M)/edit"`
`openlibrary/plugins/upstream/addbook.py: path = "/books/add"`
`openlibrary/plugins/openlibrary/code.py: path = "/addbook"`
`openlibrary/plugins/openlibrary/code.py: path = r"/(isbn|oclc|lccn|ia|ISBN|OCLC|LCCN|IA)/([^/]*)(/.*)?" [bookpage]`
`Works:`
`openlibrary/core/models.py: types.register_type('^/works/[^/]*$', '/type/work')`
`openlibrary/plugins/upstream/addbook.py: path = "(/works/OL\d+W)/edit"`
`Authors:`
`openlibrary/core/models.py: types.register_type('^/authors/[^/]*$', '/type/author')`
`openlibrary/plugins/openlibrary/authors.py: path = "/authors"`
`openlibrary/plugins/upstream/merge_authors.py: path = "/authors/merge"`
`openlibrary/plugins/worksearch/code.py: path = "/authors/(OL\d+A)/merge-works"`
`openlibrary/plugins/upstream/addbook.py: path = "(/authors/OL\d+A)/edit"`
`openlibrary/plugins/upstream/addbook.py: path = "/authors/_autocomplete"`
`Lists:`
`openlibrary/plugins/openlibrary/lists.py: path = "/lists"`
`plugins/openlibrary/lists.py: path = "(/(?:people|books|works|authors|subjects)/[^/]+)/lists"`
`plugins/openlibrary/lists.py: path = "(/people/\w+/lists/OL\d+L)/delete"`
`plugins/openlibrary/lists.py: path = "(/(?:people|books|works|authors|subjects)/[^/]+)/lists"`
`plugins/openlibrary/lists.py: path = "(/people/[^/]+/lists/OL\d+L)"`
`plugins/openlibrary/lists.py: path = "(/people/\w+/lists/OL\d+L)/seeds"`
`plugins/openlibrary/lists.py: path = "(/people/\w+/lists/OL\d+L)/editions"`
`plugins/openlibrary/lists.py: path = "(/people/\w+/lists/OL\d+L)/editions"`
`plugins/openlibrary/lists.py: path = "(/people/\w+/lists/OL\d+L)/subjects"`
`plugins/openlibrary/lists.py: path = "(/people/\w+/lists/OL\d+L)/embed"`
`plugins/openlibrary/lists.py: path = "(/people/\w+/lists/OL\d+L)/export"`
`plugins/openlibrary/lists.py: path = "(/people/[^/]+/lists/OL\d+L)/feeds/(updates).(atom)"`
`Languages:`
`openlibrary/core/models.py: types.register_type('^/languages/[^/]*$', '/type/language')`
`openlibrary/plugins/upstream/addbook.py: path = "/languages/_autocomplete"`
`Cover Images:`
`openlibrary/plugins/upstream/code.py: path = "(/books/OL\d+M)/cover"`
`openlibrary/plugins/upstream/code.py: path = "(/authors/OL\d+A)/photo"`
`openlibrary/plugins/upstream/covers.py: path = "(/books/OL\d+M)/add-cover"`
`openlibrary/plugins/upstream/covers.py: path = "(/works/OL\d+W)/add-cover"`
`openlibrary/plugins/upstream/covers.py: path = "(/authors/OL\d+A)/add-photo"`
`openlibrary/plugins/upstream/covers.py: path = "(/books/OL\d+M)/manage-covers"`
`openlibrary/plugins/upstream/covers.py: path = "(/works/OL\d+W)/manage-covers"`
`openlibrary/plugins/upstream/covers.py: path = "(/authors/OL\d+A)/manage-photos"`
`openlibrary/plugins/upstream/code.py: path = "/images/.*"`
`Special Book Collections:`
`openlibrary/plugins/openlibrary/borrow_home.py: path = "/read"`
`openlibrary/plugins/openlibrary/borrow_home.py: path = "/borrow"`
`MARC Records:`
`openlibrary/views/showmarc.py: path = "/show-marc/(.*)"`
`openlibrary/views/showmarc.py: path = "/show-records/ia:(.*)"`
`openlibrary/views/showmarc.py: path = "/show-records/amazon:(.*)"`
`openlibrary/views/showmarc.py: path = "/show-records/(.*):(\d+):(\d+)"`
`Statistics:`
`openlibrary/views/loanstats.py: path = "/stats"`
`openlibrary/views/loanstats.py: path = "/stats/lending(?:/(libraries|regions|countries|collections|subjects|format)/(.+))?"`
`openlibrary/views/loanstats.py: path = "/stats/waitinglists"`
`Themes:`
`openlibrary/plugins/theme/code.py: path = "/theme"`
`openlibrary/plugins/theme/code.py: path = "/theme/files"`
`openlibrary/plugins/theme/code.py: path = "/theme/files/(.+)"`
`openlibrary/plugins/theme/code.py: path = "/theme/modifications"`
`openlibrary/plugins/theme/code.py: path = "/theme/manage"`
`openlibrary/plugins/theme/code.py: path = "/theme/git-merge"`
`Recent Changes:`
`openlibrary/plugins/upstream/recentchanges.py: path = "/recentchanges"`
`openlibrary/plugins/upstream/recentchanges.py: path = "/recentchanges(/[^/0-9][^/]*)"`
`openlibrary/plugins/upstream/recentchanges.py: path = "/recentchanges/(\d\d\d\d(?:/\d\d)?(?:/\d\d)?)(/[^/]*)?"`
`openlibrary/plugins/upstream/recentchanges.py: path = "/recentchanges/goto/(\d+)"`
`openlibrary/plugins/upstream/recentchanges.py: path = "/recentchanges/\d\d\d\d/\d\d/\d\d/[^/]*/(\d+)"`
`Lending, Borrowing, & Availability:`
`openlibrary/plugins/upstream/borrow.py: path = "/borrow/notify"`
`openlibrary/plugins/upstream/borrow.py: path = "(/books/.*)/borrow"`
`openlibrary/plugins/upstream/borrow.py: path = "(/books/.*)/_borrow_status"`
`openlibrary/plugins/upstream/borrow.py: path = "(/books/.*)/borrow_admin"`
`openlibrary/plugins/upstream/borrow.py: path = "(/books/.*)/borrow_admin_no_update"`
`openlibrary/plugins/upstream/borrow.py: path = r"/ia_loan_status/(.*)"`
`openlibrary/plugins/upstream/borrow.py: path = r"/ia_auth/(.*)"`
`openlibrary/plugins/upstream/borrow.py: path = r"/borrow/receive_notification"`
`openlibrary/plugins/openlibrary/api.py: path = "/availability"`
`User Accounts & Auth:`
`openlibrary/plugins/upstream/account.py: path = "(/account/.*)"`
`openlibrary/plugins/upstream/account.py: path = "/account/create"`
`openlibrary/plugins/upstream/account.py: path = "/account/login"`
`openlibrary/plugins/upstream/account.py: path = "/account/verify/([0-9a-f]*)"`
`openlibrary/plugins/upstream/account.py: path = "/account/verify"`
`openlibrary/plugins/upstream/account.py: path = "/account/email"`
`openlibrary/plugins/upstream/account.py: path = "/account/email/verify/([0-9a-f]*)"`
`openlibrary/plugins/upstream/account.py: path = "/account/email/verify"`
`openlibrary/plugins/upstream/account.py: path = "/account/password"`
`openlibrary/plugins/upstream/account.py: path = "/account/password/forgot"`
`openlibrary/plugins/upstream/account.py: path = "/account/password/reset/([0-9a-f]*)"`
`openlibrary/plugins/upstream/account.py: path = "/account/notifications"`
`openlibrary/plugins/upstream/account.py: path = "/account/loans"`
`Data Dumps:`
`openlibrary/plugins/upstream/data.py: path = "/data/ol_dump(|_authors|_editions|_works|_deworks)_latest.txt.gz"`
`openlibrary/plugins/upstream/data.py: path = "/data/ol_cdump_latest.txt.gz"`
`openlibrary/plugins/upstream/data.py: path = "/data/ol_dump(|_authors|_editions|_works)_(\d\d\d\d-\d\d-\d\d).txt.gz"`
`openlibrary/plugins/upstream/data.py: path = "/data/ol_cdump_(\d\d\d\d-\d\d-\d\d).txt.gz"`
`Search:`
`openlibrary/plugins/search/code.py: path = "/search"`
`openlibrary/plugins/worksearch/languages.py: path = "/languages"`
`openlibrary/plugins/worksearch/code.py: path = "/search/edition"`
`openlibrary/plugins/worksearch/code.py: path = "/search"`
`openlibrary/plugins/worksearch/subjects.py: path = "/subjects"`
`openlibrary/plugins/worksearch/publishers.py: path = "/publishers"`
`Importing:`
`openlibrary/plugins/importapi/code.py:add_hook("import", importapi)`
`openlibrary/plugins/importapi/code.py:add_hook("ils_search", ils_search)`
`openlibrary/plugins/importapi/code.py:add_hook("ils_cover_upload", ils_cover_upload)`
`openlibrary/plugins/importapi/code.py:add_hook("import/ia", ia_importapi)`
`Infobase Connection:`
`vendor/infogami/infogami/plugins/api/code.py:add_hook("get", infobase_request)`
`vendor/infogami/infogami/plugins/api/code.py:add_hook("things", infobase_request)`
`vendor/infogami/infogami/plugins/api/code.py:add_hook("versions", infobase_request)`
`vendor/infogami/infogami/plugins/api/code.py:add_hook("get_many", infobase_request)`
`vendor/infogami/infogami/plugins/api/code.py:add_hook("write", infobase_request)`
`vendor/infogami/infogami/plugins/api/code.py:add_hook("save_many", infobase_request)`
`Suggest API?:`
`openlibrary/plugins/openlibrary/code.py: path = "/suggest/search"`
`openlibrary/plugins/openlibrary/code.py: path = "/suggest/blurb/(.*)"`
`openlibrary/plugins/openlibrary/code.py: path = "/suggest/thumbnail"`
`Site / Domain Administration:`
`openlibrary/plugins/openlibrary/code.py: path = "/robots.txt"`
`openlibrary/plugins/openlibrary/code.py: path = "/health"`
`openlibrary/plugins/openlibrary/code.py: path = "/system/invalidate"`
`openlibrary/plugins/openlibrary/code.py: path = "/debug/memory"`
`openlibrary/plugins/openlibrary/code.py: path = "/debug/backdoor"`
`admin/code.py: path = "(/(?:images|js|css)/.*)"`
`types.register_type('^/usergroup/[^/]*$', '/type/usergroup')`
`types.register_type('^/permission/[^/]*$', '/type/permission')`
`types.register_type('^/(css|js)/[^/]*$', '/type/rawtext')`
`Informational:`
`openlibrary/plugins/openlibrary/borrow_home.py: path = "/borrow/about"`
`Library Partners:`
`openlibrary/core/models.py: types.register_type('^/libraries/[^/]*$', '/type/library')`
`openlibrary/plugins/openlibrary/libraries.py: path = "/libraries/dashboard"`
`openlibrary/plugins/openlibrary/libraries.py: path = "/(libraries/pending-\d+)"`
`openlibrary/plugins/openlibrary/libraries.py: path = "/libraries/register"`
`openlibrary/plugins/openlibrary/libraries.py: path = "/libraries/locations.txt"`
`openlibrary/plugins/openlibrary/libraries.py: path = "/libraries/stats"`
`openlibrary/plugins/openlibrary/libraries.py: path = "/libraries/stats/(.*).csv"`
`openlibrary/plugins/openlibrary/libraries.py: path = "(/libraries/[^/]+)/notes"`
`APIs & Services:`
`openlibrary/plugins/openlibrary/api.py: path = "(/works/OL\d+W)/editions"`
`openlibrary/plugins/openlibrary/api.py: path = "(/authors/OL\d+A)/works"`
`openlibrary/plugins/openlibrary/code.py: path = "/details/([a-zA-Z0-9_-]*)(?:/leaf(\d+))?"`
`openlibrary/plugins/openlibrary/dev_instance.py: path = "/is_loaned_out/.*"`
`openlibrary/plugins/books/code.py: path = r"/api/volumes/(brief|full)/(oclc|lccn|issn|isbn|htid|olid|recordnumber)/(.+)"`
`openlibrary/plugins/books/code.py: path = r"/api/volumes/(brief|full)/json/(.+)"`
In openlibrary/plugins/openlibrary/lists.py
GET /lists/search?q=
POST https://openlibrary.org/api/new.json
Body (minimum):
{
"type": {"key": "/type/work"},
"title": "<Work Title>",
"authors": [{"type": "/type/author_role", "author": {"key": "/authors/<olid>"}}]
}
Returns the created work's OLID.
In file openlibrary/plugins/upstream/addbook.py:
GET https://openlibrary.org/books/(OL...M)/edit
Parameters:
name="_delete"
Permissions:
User must be Administrator
Notes:
Deleting the last Edition of a Work via this endpoint will remove the Work also.
RESTful API Delete:
PUT https://openlibrary.org/works/(OL...W).json
Body:
{
"type": { "key": "/type/delete" },
"_comment": "<Reason for deletion>"
}
Permissions:
User must be Administrator
Notes:
Deleting a Work that still has editions will succeed, leaving orphaned Editions, potentially without Authors if the Author was only present on the Work. Care must be taken when deleting Works that this does not occur. Deleting the last Work of an Author will not remove the Author record.
RESTful API
GET https://openlibrary.org/books/(OL...M).json
GET https://openlibrary.org/books/(OL...M).rdf
RESTful API Edit:
PUT https://openlibrary.org/books/(OL...M).json
Body:
{
< complete **JSON** body of current record from GET request, modified as desired >
"_comment": "<Description of changes>"
}
In file openlibrary/plugins/upstream/addbook.py:
https://openlibrary.org/books/(OL...M)/edit
Parameters:
name="_delete"
Permissions:
User must be Administrator
RESTful API Delete:
PUT https://openlibrary.org/books/(OL...M).json
Body:
{
"type": { "key": "/type/delete" },
"_comment": "<Reason for deletion>"
}
Permissions:
User must be Administrator
Notes:
Deleting the last Edition of a Work will NOT remove the Work. It has to be cleared separately.
POST /api/import
The raw POST data is parsed by parse_body()
which intends to accept:
- XML (rdf | opds | MARCMXL)
- JSON edition format (schema)
- MARC binary
POST /api/import/ia
POST body:
{
"identifier": "<ocaid>",
"require_marc": "false",
"bulk_marc": "false",
"local_id": "<optional local_id config key>"
}
Example data to import a single archive.org item:
{ "identifier": "europe1890194500wink" }
Example data to import one record from a bulk MARC, identifier format ocaid/filename:offset:length
:
{ "bulk_marc": "true", "identifier": "talis-openlibrary-contribution/talis-openlibrary-contribution.mrc:1353778212:578" }
If importing from a partner's MARC records where we want to store their local_id
(in practice this is expected to be a scannable barcode) the optional local_id
parameter can be supplied which will read the configuration from an entry under https://openlibrary.org/local_ids to extract an id from any controlfield (e.g. 100$
) or any other MARC subfield (e.g. 919$a
) as specified in the "id_location"
of that entry. Example: "local_id": "trent"
.
See: openlibrary/plugins/worksearch/subjects.py
https://openlibrary.org/search/subjects
https://openlibrary.org/dev/docs/api/recentchanges
edit types: create, update, register (old form of user create by AccountBot), bulk_update (starting 2009-03), add-book (starting 2010-08), add-cover (starting 2010-08), edit-book (starting 2010-08), lists (starting 2010-11), new-account (replaced register),
https://openlibrary.org/recentchanges/2009/12/31/bulk_update.json?bot=true&offset=0&limit=100
offset: default 0, max 10000 limit: default 100, max 1000
- Imports @scottbarnes
- Import Endpoints
- Import Core APIs
-
Imports Dashboard (
/imports
)
- Borrowing
- Reading Log
- TODO ask @jimchamp
- Lists
- TODO ask @cdrini
- Community Tags / Observations
- TODO ask @jimchamp
-
Author Merges
-
Work Merges
-
Merge Queue
-
ILE (Integrated Librarian Environment)
To send API requests directly from your local environment without a third-party app or plugin, simple run your API calls in the browser's console. E.g.
const data ={}
await fetch('http://localhost:8080/people/openlibrary/lists.json', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(data)
}).then(r => r.json())
This useful trick avoids the need to sync cookies in order to send requests via a third-party application.
Welcome to the Open Library Handbook! Here you will learn how to...
- Get Set Up
- Understand the Codebase
- Contribute to the Front-end
- Contribute to the Back-end
- Manage your developer environment
- Lookup Common Recipes
- Participate in the Community
Developer Guides
- BookWorm / Affiliate Server
- Developing the My Books & Reading Log
- Developing the Books page
- Understanding the "Read" Button
Other Portals
- Design
- Librarianship
- Communications
- Staff (internal)
Legacy
Orphaned Editions Planning