Class: Zotero::Client

Inherits:
Object
  • Object
show all
Includes:
Fields, FileUpload, HTTPErrors, ItemTypes, NetworkErrors, Syncing
Defined in:
lib/zotero/client.rb

Overview

The main HTTP client for interacting with the Zotero Web API v3. Provides authentication, request handling, and access to library operations.

rubocop:disable Metrics/ClassLength

Examples:

Create a client with API key

client = Zotero::Client.new(api_key: 'your-api-key-here')
library = client.user_library(12345)

Constant Summary collapse

BASE_URI =
"https://api.zotero.org"

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(api_key:) ⇒ Client

Initialize a new Zotero API client.

Parameters:

Raises:

  • (ArgumentError)

    if api_key is nil or empty



39
40
41
# File 'lib/zotero/client.rb', line 39

def initialize(api_key:)
  @api_key = api_key
end

Instance Attribute Details

#api_keyObject (readonly, private)

Returns the value of attribute api_key.



135
136
137
# File 'lib/zotero/client.rb', line 135

def api_key
  @api_key
end

Instance Method Details

#auth_headersObject (protected)



100
101
102
# File 'lib/zotero/client.rb', line 100

def auth_headers
  { "Zotero-API-Key" => api_key }
end

#build_locale_params(locale) ⇒ Object (private) Originally defined in module Fields

#build_request(method, uri, headers, body, request_options) ⇒ Object (private)



159
160
161
162
163
164
# File 'lib/zotero/client.rb', line 159

def build_request(method, uri, headers, body, request_options)
  request = create_request(method, uri)
  set_headers(request, headers)
  set_request_body(request, method, body, headers, request_options) if body
  request
end

#build_request_options(options) ⇒ Object (private)



137
138
139
140
141
142
143
144
145
# File 'lib/zotero/client.rb', line 137

def build_request_options(options)
  {
    headers: options[:headers] || {},
    body: options[:body],
    params: options[:params] || {},
    multipart: options[:multipart],
    format: options[:format]
  }
end

#build_uri(path, params = {}) ⇒ Object (private)



147
148
149
150
151
152
153
154
155
156
157
# File 'lib/zotero/client.rb', line 147

def build_uri(path, params = {})
  base = path.start_with?("http") ? path : "#{BASE_URI}#{path}"
  uri = URI(base)

  unless params.empty?
    query_params = params.map { |k, v| "#{CGI.escape(k.to_s)}=#{CGI.escape(v.to_s)}" }.join("&")
    uri.query = uri.query ? "#{uri.query}&#{query_params}" : query_params
  end

  uri
end

#build_write_headers(version: nil, write_token: nil) ⇒ Object (protected)



108
109
110
111
112
113
114
# File 'lib/zotero/client.rb', line 108

def build_write_headers(version: nil, write_token: nil)
  headers = auth_headers.merge(default_headers)
  headers["Content-Type"] = "application/json"
  headers["If-Unmodified-Since-Version"] = version.to_s if version
  headers["Zotero-Write-Token"] = write_token if write_token
  headers
end

#create_request(method, uri) ⇒ Object (private)



166
167
168
169
170
171
172
173
174
175
176
177
# File 'lib/zotero/client.rb', line 166

def create_request(method, uri)
  request_class = case method
                  when :get then Net::HTTP::Get
                  when :post then Net::HTTP::Post
                  when :put then Net::HTTP::Put
                  when :patch then Net::HTTP::Patch
                  when :delete then Net::HTTP::Delete
                  else raise ArgumentError, "Unsupported HTTP method: #{method}"
                  end

  request_class.new(uri)
end

#creator_fields(locale: nil) ⇒ Array<Hash> Originally defined in module Fields

Get all available creator fields.

Parameters:

  • locale (String) (defaults to: nil)

    Optional locale for localized field names (e.g. 'en-US', 'fr-FR')

Returns:

  • (Array<Hash>)

    Array of creator field definitions with field names and localized labels

#default_headersObject (protected)



104
105
106
# File 'lib/zotero/client.rb', line 104

def default_headers
  { "Zotero-API-Version" => "3" }
end

#deleted_items(since: nil) ⇒ Hash Originally defined in module Syncing

Get items that have been deleted from this library.

Parameters:

  • since (Integer) (defaults to: nil)

    Optional version to get deletions since

Returns:

  • (Hash)

    Object with deleted collections and items arrays

#error_message_for(error) ⇒ Object (private) Originally defined in module NetworkErrors

#external_post(url, multipart_data:) ⇒ Object Originally defined in module FileUpload

#group_library(group_id) ⇒ Library

Get a Library instance for a specific group.

Parameters:

  • group_id (Integer, String)

    The Zotero group ID

Returns:

  • (Library)

    A Library instance for the specified group



55
56
57
# File 'lib/zotero/client.rb', line 55

def group_library(group_id)
  Library.new(client: self, type: :group, id: group_id)
end

#handle_network_errorsObject Originally defined in module NetworkErrors

#handle_response(response, format = nil) ⇒ Object (protected)



116
117
118
119
120
# File 'lib/zotero/client.rb', line 116

def handle_response(response, format = nil)
  return parse_response_body(response, format) if response.code.to_i.between?(200, 299)

  raise_error_for_status(response)
end

#handle_write_response(response) ⇒ Object (protected)



122
123
124
125
126
127
128
129
130
131
# File 'lib/zotero/client.rb', line 122

def handle_write_response(response)
  case response.code.to_i
  when 200
    parse_json_response(response)
  when 204
    true
  else
    raise_error_for_status(response)
  end
end

#http_request(method, path, **options) ⇒ Object (protected)



88
89
90
91
92
93
94
95
96
97
98
# File 'lib/zotero/client.rb', line 88

def http_request(method, path, **options)
  request_options = build_request_options(options)
  uri = build_uri(path, request_options[:params])

  handle_network_errors do
    connection = HTTPConnection.new(uri)
    request = build_request(method, uri, request_options[:headers], request_options[:body], request_options)

    connection.request(request)
  end
end

#item_fields(locale: nil) ⇒ Array<Hash> Originally defined in module Fields

Get all available item fields.

Parameters:

  • locale (String) (defaults to: nil)

    Optional locale for localized field names (e.g. 'en-US', 'fr-FR')

Returns:

  • (Array<Hash>)

    Array of field definitions with field names and localized labels

#item_type_creator_types(item_type) ⇒ Array<Hash> Originally defined in module ItemTypes

Get all creator types available for a specific item type.

Parameters:

  • item_type (String)

    The item type name (e.g. 'book', 'journalArticle')

Returns:

  • (Array<Hash>)

    Array of creator type definitions for the item type

#item_type_fields(item_type, locale: nil) ⇒ Array<Hash> Originally defined in module ItemTypes

Get all fields available for a specific item type.

Parameters:

  • item_type (String)

    The item type name (e.g. 'book', 'journalArticle')

  • locale (String) (defaults to: nil)

    Optional locale for localized field names

Returns:

  • (Array<Hash>)

    Array of field definitions for the item type

#item_types(locale: nil) ⇒ Array<Hash> Originally defined in module ItemTypes

Get all available item types.

Parameters:

  • locale (String) (defaults to: nil)

    Optional locale for localized type names (e.g. 'en-US', 'fr-FR')

Returns:

  • (Array<Hash>)

    Array of item type definitions

#make_get_request(path, params: {}) ⇒ Array, Hash

Make a GET request to the Zotero API. This is the main public interface for read operations.

Parameters:

  • path (String)

    The API endpoint path

  • params (Hash) (defaults to: {})

    Query parameters for the request

Returns:

  • (Array, Hash)

    The parsed response data



65
66
67
68
69
# File 'lib/zotero/client.rb', line 65

def make_get_request(path, params: {})
  headers = auth_headers.merge(default_headers)
  response = http_request(:get, path, headers: headers, params: params)
  handle_response(response, params[:format])
end

#make_write_request(method, path, data: nil, options: {}, params: {}) ⇒ Hash, Boolean

Make a write request (POST, PATCH, PUT, DELETE) to the Zotero API. This is the main public interface for write operations.

Parameters:

  • method (Symbol)

    The HTTP method (:post, :patch, :put, :delete)

  • path (String)

    The API endpoint path

  • data (Hash, Array) (defaults to: nil)

    Optional request body data

  • options (Hash) (defaults to: {})

    Write options (version: Integer, write_token: String)

  • params (Hash) (defaults to: {})

    Query parameters for the request

Returns:

  • (Hash, Boolean)

    The parsed response data or success status



80
81
82
83
84
# File 'lib/zotero/client.rb', line 80

def make_write_request(method, path, data: nil, options: {}, params: {})
  headers = build_write_headers(version: options[:version], write_token: options[:write_token])
  response = http_request(method, path, headers: headers, body: data, params: params)
  handle_write_response(response)
end

#network_error_classesObject (private) Originally defined in module NetworkErrors

#new_item_template(item_type) ⇒ Hash Originally defined in module ItemTypes

Get a new item template for a specific item type.

Parameters:

  • item_type (String)

    The item type name (e.g. 'book', 'journalArticle')

Returns:

  • (Hash)

    Template object with empty fields for the item type

#parse_json_response(response) ⇒ Object (private)



205
206
207
208
209
210
211
# File 'lib/zotero/client.rb', line 205

def parse_json_response(response)
  return nil if response.body.nil? || response.body.empty?

  JSON.parse(response.body)
rescue JSON::ParserError
  response.body
end

#parse_response_body(response, format) ⇒ Object (private)



196
197
198
199
200
201
202
203
# File 'lib/zotero/client.rb', line 196

def parse_response_body(response, format)
  case format&.to_s
  when "json", nil
    parse_json_response(response)
  else
    response.body
  end
end

#post_form(path, form_data:, if_match: nil, if_none_match: nil, params: {}) ⇒ Object Originally defined in module FileUpload

#raise_client_error(response) ⇒ Object Originally defined in module HTTPErrors

#raise_error_for_status(response) ⇒ Object Originally defined in module HTTPErrors

#raise_rate_limit_error(response) ⇒ Object Originally defined in module HTTPErrors

Raises:

#raise_server_or_unknown_error(response) ⇒ Object Originally defined in module HTTPErrors

#register_upload(path, upload_key:) ⇒ Object Originally defined in module FileUpload

#request_upload_authorization(path, filename:, md5: nil, mtime: nil, existing_file: false) ⇒ Object Originally defined in module FileUpload

#set_headers(request, headers) ⇒ Object (private)



179
180
181
# File 'lib/zotero/client.rb', line 179

def set_headers(request, headers)
  headers.each { |key, value| request[key] = value }
end

#set_request_body(request, method, body, headers, request_options) ⇒ Object (private)



183
184
185
186
187
188
189
190
191
192
193
194
# File 'lib/zotero/client.rb', line 183

def set_request_body(request, method, body, headers, request_options)
  return unless %i[post put patch].include?(method)

  if request_options[:multipart]
    request.set_form(body, "multipart/form-data")
  elsif headers["Content-Type"] == "application/x-www-form-urlencoded"
    request.set_form_data(body)
  else
    request.body = body.is_a?(String) ? body : JSON.generate(body)
    request["Content-Type"] = "application/json" unless headers["Content-Type"]
  end
end

#translate_network_error(error) ⇒ Object (private) Originally defined in module NetworkErrors

#user_groups(user_id, format: "versions") ⇒ Hash, Array Originally defined in module Syncing

Get groups for a specific user.

Parameters:

  • user_id (Integer, String)

    The user ID to get groups for

  • format (String) (defaults to: "versions")

    Response format ('versions' or 'json')

Returns:

  • (Hash, Array)

    Groups data in the requested format

#user_library(user_id) ⇒ Library

Get a Library instance for a specific user.

Parameters:

  • user_id (Integer, String)

    The Zotero user ID

Returns:

  • (Library)

    A Library instance for the specified user



47
48
49
# File 'lib/zotero/client.rb', line 47

def user_library(user_id)
  Library.new(client: self, type: :user, id: user_id)
end

#verify_api_keyHash Originally defined in module Syncing

Verify that the current API key is valid.

Returns:

  • (Hash)

    API key information including userID and username