Thanks for writing this up.
So I think there's a much more straightforward way to approach
this, and it's the way we've long planned to do this in Zotero
proper: to have the Zotero app essentially mirror the web API,
such that tools designed to work with the web API could trivially
be adapted to work against a local installation, immediately
benefitting from private data storage and/or lower latency. Some
basic extensions could allow for any other functionality to be
performed by local tools.
There are already two Zotero APIs: the web API and the local
JavaScript API. The web API, which is used by Zotero itself for
syncing, provides a cleanly defined API for accessing all data in
Zotero — it's well documented and widely supported by an array of
libraries and tools. The JavaScript API is less well documented
outside of the Zotero source code but lets you do essentially
anything you want in Zotero, and it's obviously used by an
increasingly large ecosystem of Zotero plugins.
I think creating a whole other local API, with ad hoc endpoints
for specific tasks, would be a mistake, splintering development
resources and reproducing existing work for no real reason.
Zotero can already generate web-API-style JSON for all data
objects (because that's what's used for syncing), and we already
have the beginnings of code to parse an incoming API-style path
and return API JSON. Select a collection and run this to see an
example:
var c = ZoteroPane.getSelectedCollection();
var path = `library/collections/${c.key}/items`; //
would also support 'users/1234'
for web API
compatibility
var params = Zotero.API.Data.parsePath(path);
var results = await
Zotero.API.getResultsFromParams(params);
return results;
Finishing that work and hooking it up to the built-in HTTP server
would be fairly trivial. Write requests will take some more work,
but the behavior is all clearly defined. (It could probably even
share part of a test suite with the dataserver.)
In the end, most existing libraries or tools could likely be
pointed at a local installation just by changing the host, perhaps
with a few other tweaks to remove various assumptions. So then if
you were more comfortable writing Python than JavaScript (or
didn't want to dig through Zotero source code), you could use
pyzotero to script operations to clean up a local Zotero database.
The primary objection, I assume, will be that the web API is more
limited than local Zotero. That's true, but I think there are
better ways to address that. I see basically three categories of
limitations:
1) Functionality that's not yet implemented in the web API but
could be. E.g., the web API currently supports
"Title/Creator/Year" search and "Title/Creator/Year + Full-Text"
search, but that's just because we've never reproduced the Zotero
app's advanced search functionality on the dataserver. But since
it already exists locally, it's easy to expose. Similarly, there's
no way to get the actual item results from saved searches online,
but supporting
…/searches/{searchKey}/items
locally
would be trivial.
2) Functionality that's not implemented in the web API because
it's about actions that only exist in the app, but that still
applies to data objects referenced by the API. E.g., selecting
items or opening a PDF doesn't make sense via the web API, but I
could imagine using an HTTP header to trigger a Zotero UI action
on a set of objects defined by the scope of the URL, so that
POST
/library/items/B2FDK42M
with
Zotero-Action: select
would select a single item (equivalent to launching
zotero://select/library/items/B2FDK42M
),
and
POST
/library/items?tag=to%20read&sort=dateAdded&direction=desc&limit=5
with
Zotero-Action: open-pdf
would open the PDFs
belonging to the five most recently added items with the "to read"
tag.
3) Functionality that's not implemented in the web API because it
involves Zotero app internals. This could be addressed just by
adding an endpoint to run arbitrary privileged JavaScript, the
same as BBT's debug-bridge. We've never done this, but with
appropriate security precautions, we could, allowing local apps to
kick off whatever functionality they wanted and optionally return
results.
Related to (3), we've put in some work towards being able to save
JS snippets and trigger them either manually or via keyboard
shortcuts (the latter similar to the old keyconfig extension for
Firefox and Thunderbird). I think this would better address some
of the repeated tasks mentioned in the linked doc that have no
real reason to run outside of Zotero. Ultimately, the language of
the Zotero app is JavaScript, and if effort is going to be put
towards improving Zotero's scriptability, the first priority would
be generating better JS API documentation from the Zotero source
code so that it's easier for people to do what they want to do,
whether from a plugin, manually from within Zotero, or from an
external app POSTing some JS and getting a response.
We can try to hook up some of the above soon to get this started,
and if others would like to help implement parts of the web API
after that, that'd be great. But I'd strongly discourage folks
from creating a whole other dev environment — at least one that
you encourage others to use — rather than building off of the two
very powerful, widely supported APIs we already have.
- Dan