{"id":20885868,"url":"https://github.com/zotero/zotero-api-node","last_synced_at":"2026-03-15T16:40:18.585Z","repository":{"id":17872064,"uuid":"20809890","full_name":"zotero/zotero-api-node","owner":"zotero","description":"Zotero API client for Node.js","archived":false,"fork":false,"pushed_at":"2017-07-14T06:15:31.000Z","size":148,"stargazers_count":30,"open_issues_count":7,"forks_count":6,"subscribers_count":9,"default_branch":"master","last_synced_at":"2024-10-30T11:03:35.323Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"agpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/zotero.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2014-06-13T16:07:51.000Z","updated_at":"2024-10-13T17:16:08.000Z","dependencies_parsed_at":"2022-08-04T21:15:38.701Z","dependency_job_id":null,"html_url":"https://github.com/zotero/zotero-api-node","commit_stats":null,"previous_names":["inukshuk/zotero-node"],"tags_count":8,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zotero%2Fzotero-api-node","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zotero%2Fzotero-api-node/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zotero%2Fzotero-api-node/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zotero%2Fzotero-api-node/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/zotero","download_url":"https://codeload.github.com/zotero/zotero-api-node/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":225148801,"owners_count":17428430,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-18T08:14:52.639Z","updated_at":"2026-03-15T16:40:13.553Z","avatar_url":"https://github.com/zotero.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"Zotero-Node\n===========\n[![Build Status](https://travis-ci.org/inukshuk/zotero-node.svg?branch=master)](https://travis-ci.org/inukshuk/zotero-node)\n[![Coverage Status](https://img.shields.io/coveralls/inukshuk/zotero-node.svg)](https://coveralls.io/r/inukshuk/zotero-node?branch=master)\n\nA Zotero API client package for Node.js. This package tries to make it\nas easy as possible to bootstrap a Zotero client application in Node.js;\nit comes with hardly any runtime dependencies and provides four simple\nabstractions to interact with Zotero: `Client`, `Library`, `Message`,\n`Stream`.\n\nClients handle the HTTPS connection to a Zotero data server, observing\nany rate-limiting directives issued by the server; you can configure\nsettings (like API versions, default headers etc.) for each Client.\nEach Library represents a Zotero user or group library and is associated\nwith a Client instance; a Library offers many convenience methods to\nmake it easy to construct Zotero API requests. Each request and the\ncorresponding response are then encapsulated in a Message instance, wich\nprovides accessors and an extendable body parser collection to handle\nthe various formats supported by Zotero. The Stream class, finally,\nuses a WebSocket connection to access the Zotero Streaming API, manages\nthe subscription list locally, and automatically tries to re-open\nprematurely closed connections.\n\nQuickstart\n----------\nInstall the NPM package:\n\n    $ npm install zotero\n\nAnd:\n\n    var zotero = require('zotero');\n\nNow you can use the `zotero.Client` and `zotero.Library` constructors;\nthe latter is also aliased to the `zotero` namespace. Let's access the\nLibrary of Zotero's public user:\n\n    var lib = zotero({ user: '475425' });\n\nWhen creating a Library you can pass-in a Client instance using the\n`client` property; if you don't, a default Client will be created for\nyou. You can access the client through the library:\n\n    \u003e // The default HTTP headers used by the client\n    \u003e lib.client.options.headers;\n    { 'Zotero-API-Version': '3', 'User-Agent': 'zotero-node/0.0.1' }\n\n    \u003e // Let's make the client re-use the TCP connection to the server\n    \u003e lib.client.persist = true;\n    \u003e lib.client.options.headers['Connection'];\n    'keep-alive'\n\nTo send requests to Zotero you can now use `Library#get(path, options, callback)`,\nor use the convenience methods baked into Zotero-Node:\n\n    \u003e lib.items();\n    // Will call /users/475425/items\n\n    \u003e lib.items.top({ limit: 3 })\n    // Will call /users/475425/items/top?limit=3\n\n    \u003e lib.items('KWENT2ZM', { format: 'csljson' });\n    // Will call /users/475425/items/KWENT2ZM?format=csljson\n\nAnd so on; all valid Zotero API paths can be created this way (but you can also\nuse the `#get` method with any path yourself). All of these path methods allow\nyou to pass options which will be added as URL parameters. The methods will return\na Message instance; at that moment, the Message will only contain the HTTP request\nwhich has not been sent yet, allowing you to make alterations, set event handlers\nand so on. You can also pass a callback function to the request methods, which will\nreceive the Message instance when the response has been received and parsed.\n\nIf you just want to quickly print information about a message, pass-in\n`zotero.print` as the callback. It will print out information like this:\n\n    \u003e lib.items('KWENT2ZM', { format: 'csljson' }, zotero.print);\n\n    zotero:node Path:     /users/475425/items/KWENT2ZM?format=csljson +0ms\n    zotero:node Status:   200 +2ms\n    zotero:node Type:     json +1ms\n    zotero:node Headers:  {\"date\":\"Thu, 26 Jun 2014 10:36:07 GMT\",\"server\":\"Apache/2.2.15 (CentOS)\",\"zotero-api-version\":\"2\",\"content-length\":\"148\",\"connection\":\"close\",\"content-type\":\"application/vnd.citationstyles.csl+json\"} +0ms\n    zotero:node Content:  {\"items\":[{\"id\":\"392648/KWENT2ZM\",\"type\":\"webpage\",\"title\":\"Zotero | Home\",\"URL\":\"http://staging.zotero.net/\",\"accessed\":{\"raw\":\"2011-06-28\"}}]} +0ms\n\nMessage Parsing\n---------------\nZotero-Node was written with the Zotero API v3 in mind and, by default, will parse\nJSON responses automatically. Contents are accessible in the `message.data` property\nonce the response has been received. Other content-types will be saved as strings\nusing the appropriate encoding. Having said that, it is very easy to add your own message\nparsers to Zotero-Node, by adding them to `zotero.Messages.parsers`. For instance,\nwe could add a parser for Atom responses like this:\n\n\n    var zotero = require('zotero');\n    var xml2js = require('xml2js').parseString;\n\n    zotero.Message.parsers.atom = function (data, callback) {\n      return xml2js(data.toString(this.encoding), callback);\n    };\n\nNow, if you make a call that returns an Atom feed, it will be parsed automatically:\n\n    lib.items.top({ format: 'atom', limit: 2 }, function (error, message) {\n      if (error) return console.log(error.message);\n      console.dir(message.data.feed);\n    });\n\nStream API\n----------\nZotero-Node supports the Zotero Stream API through `zotero.Stream`. To create\na single-key stream, simply pass your Zotero API key to the constructor:\n\n    var stream = new zotero.Stream({ apiKey: 'your-zotero-api-key' });\n\nYou can then register handlers for all events (e.g., `topicUpdated`,\n`topicRemoved`, `topicAdded`, `subscriptionsCreated`, etc.):\n\n    stream.on('topicUpdated', function (data) {\n      console.log(data.topic);\n      console.log(data.version);\n    });\n\nIf you create a stream without a key, it will default to a multi-key\nstream. Once the stream has been established, you can manage your\nsubscriptions using the `.subscribe` and `.unsubscribe` methods.\n\n    (new zotero.Stream())\n      .on('connected', function () {\n        this.subscribe([\n          { apiKey: 'abc123' },\n          { apiKey: 'efd456', topics: [ '/users/12345' ] }\n        ]);\n      });\n\nAlternatively, you can add your subscriptions even before the stream\nhas been connected: the respective `createSubscriptions` message will\nbe sent automatically once the connection has been established.\n\nYou can also create a multi-key stream for a given Zotero user/group\nlibrary, by using the `.stream` method on the library instance. This will\nautomatically create the stream and subscribe to the current library,\nusing the library's API key (if present):\n\n    zotero({ user: '475425' })\n      .stream(function (error, stream) {\n\n        // This will set up a stream and subscribe to\n        // the topic '/users/475425'. The callback will\n        // be called once the subscription has been\n        // accepted (or if there was an error).\n\n      });\n\nEach stream keeps track of its subscriptions locally; call\n`stream.subscriptions.all` to see your current subscriptions.\n\nYou can close a stream at any time by calling `stream.close()`; if the\nstream is closed unexpectedly, the stream will automatically wait for\nthe `retry` interval (sent by the Zotero API with the `connected` event)\nand then try to re-connect. Once the connection is established, the stream\nwill attempt to restore your previous subscriptions.\n\nRate-Limiting\n-------------\nZotero-Node observes rate-limit directives by default, so you should not have\nto worry about them. The headers of each response are parsed by the client; if\nthere are any `Retry-After` or `Backoff` headers, the client will switch into\nlimited mode; all messages you send in limited mode, will be held back, until\nthe limited period has expired.\n\nIf you want to check the client's state, you can do so by calling\n`client.state.limited` – this will return the time until the limited period\nwill be expired; if `limited` is zero, the client is in normal mode.\n\nIf you want to force the client to send messages in limited mode, you can do\nso by calling `client.flush(true)` with the force flag set to true.\n\nWhat about promises?\n--------------------\nZotero-Node uses standard Node.js style callbacks out of the box, but you can\neasily promisify the API. Simply call `zotero.promisify` passing in the Promise\nimplementation's promisify variant of your choice.\n\n    // For Bluebird:\n    zotero.promisify(Promise.promisify.bind(Promise));\n\n    // For Q:\n    zotero.promisify(Q.denodeify.bind(Q));\n\nThis will promisify the Client's request method; as a result `Client#get` and\nall Library getters will return a Promise instead of a Message object. If you\nwant to access the message object before it is sent, you can still do so: all\nmessages are stored in `client.messages` before they are sent; messages are\nadded at the start of the list, so your last message will always be at index\nzero in the queue.\n\n    // Using Bluebird promises, fetch the top 5 items of a library:\n    var promise = lib.items.top({ limit: 5 });\n\n    // If you need to modify the message before it is sent, you\n    // can access it at the start of the client's message queue.\n    lib.client.messages[0].req.getHeader('Zotero-API-Version');\n\n    // Handle the API response or errors when the promise is\n    // resolved or rejected:\n    promise\n      .then(function (message) {\n        // Handle the Zotero API response...\n      })\n      .catch(function (error) {\n        // Handle any errors...\n      });\n\nNote that the Stream API also uses promieses now:\n\n    lib\n      .stream()\n      .then(function (stream) {\n        // ...\n      });\n\nYou can undo the promisification at any time by calling:\n\n    zotero.promisify.restore();\n\n\n\nLicense\n-------\nCopyright 2014-2015 Zotero. All rights reserved.\n\nZotero-Node is licensed under the AGPL3 license. See LICENSE for details.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzotero%2Fzotero-api-node","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fzotero%2Fzotero-api-node","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzotero%2Fzotero-api-node/lists"}