Class: Gini::Api::Client

Inherits:
Object
  • Object
show all
Defined in:
lib/gini-api/client.rb

Overview

Main class to operate on the Gini API

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(options = {}) ⇒ Client

Instantiate a new Gini::Api::Client object with OAuth capabilities

Examples:

api = Gini::Api::Client.new(
  client_id: 'my_client_id',
  client_secret: 'my_client_secret',
)

Parameters:

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

    Hash of available config settings

Options Hash (options):

  • :client_id (String)

    OAuth client_id

  • :client_secret (String)

    OAuth client_secret

  • :oauth_site (String)

    OAuth site to connect to (user.gini.net)

  • :oauth_redirect (String)

    Redirect URI

  • :upload_timeout (Integer)

    Upload timeout in seconds

  • :processing_timeout (Integer)

    API operational timeout in seconds

  • :api_uri (String)

    API URI (api.gini.net)

  • :api_version (String)

    API version to use (v1)

  • :log (Logger)

    logger object to use (initialized with STDOUT otherwise)



35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
# File 'lib/gini-api/client.rb', line 35

def initialize(options = {})
  opts = {
    oauth_site: 'https://user.gini.net/',
    oauth_redirect: 'http://localhost',
    api_uri: 'https://api.gini.net',
    api_version: 'v1',
    api_type: 'json',
    upload_timeout: 90,
    processing_timeout: 180,
    log: Logger.new(STDOUT),
  }.merge(options)

  # Ensure mandatory keys are set
  [:client_id, :client_secret].each do |k|
    raise Gini::Api::Error.new("Mandatory option key is missing: #{k}") unless opts.key?(k)
  end

  # Populate instance variables from merged opts
  opts.each do |k, v|
    instance_variable_set("@#{k}", v)
    self.class.send(:attr_reader, k)
  end

  # Ensure STDOUT is flushed
  STDOUT.sync = true

  # Sanitize api_uri
  @api_uri.sub!(/(\/)+$/, '')

  # Register parser (json+xml) based on API version
  register_parser

  @log.info('Gini API client initialized')
  @log.info("Target: #{@api_uri}")
end

Instance Attribute Details

#logObject (readonly)

Returns the value of attribute log.



14
15
16
# File 'lib/gini-api/client.rb', line 14

def log
  @log
end

#tokenObject (readonly)

Returns the value of attribute token.



14
15
16
# File 'lib/gini-api/client.rb', line 14

def token
  @token
end

Instance Method Details

#delete(id) ⇒ Object

Delete document

Parameters:

  • id (String)

    document ID



182
183
184
185
186
187
188
189
190
191
# File 'lib/gini-api/client.rb', line 182

def delete(id)
  response = request(:delete, "/documents/#{id}")
  unless response.status == 204
    raise Gini::Api::DocumentError.new(
      "Deletion of docId #{id} failed (code=#{response.status})",
      response
    )
  end
  @log.info("Deleted document #{id}")
end

#get(id) ⇒ Gini::Api::Document

Get document by Id

Parameters:

  • id (String)

    document ID

Returns:



199
200
201
# File 'lib/gini-api/client.rb', line 199

def get(id)
  Gini::Api::Document.new(self, "/documents/#{id}")
end

#list(options = {}) ⇒ Gini::Api::DocumentSet

List all documents

Parameters:

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

    List options (offset and limit)

Options Hash (options):

  • :limit (Integer)

    Maximum number of documents to return (defaults to 20)

  • :offset (Integer)

    Start offset. Defaults to 0

Returns:



211
212
213
214
215
216
217
218
219
220
221
222
223
224
# File 'lib/gini-api/client.rb', line 211

def list(options = {})
  opts   = { limit: 20, offset: 0 }.merge(options)
  limit  = Integer(opts[:limit])
  offset = Integer(opts[:offset])

  response = request(:get, "/documents?limit=#{limit}&next=#{offset}")
  unless response.status == 200
    raise Gini::Api::DocumentError.new(
      "Failed to get list of documents (code=#{response.status})",
      response
    )
  end
  Gini::Api::DocumentSet.new(self, response.parsed)
end

#login(opts) ⇒ Object

Acquire OAuth2 token and popolate @oauth (instance of Gini::Api::OAuth.new) and @token (OAuth2::AccessToken). Supports 2 strategies: username/password and authorization code

Examples:

api.(auth_code: '1234567890')
api.(username: '[email protected]', password: 'secret')

Parameters:

  • opts (Hash)

    Your authorization credentials

Options Hash (opts):

  • :auth_code (String)

    OAuth authorization code. Will be exchanged for a token

  • :username (String)

    API username

  • :password (String)

    API password



95
96
97
98
# File 'lib/gini-api/client.rb', line 95

def (opts)
  @oauth = Gini::Api::OAuth.new(self, opts)
  @token = @oauth.token
end

#logoutObject

Destroy OAuth2 token



102
103
104
# File 'lib/gini-api/client.rb', line 102

def logout
  @oauth.destroy
end

#register_parserObject

Register OAuth2 response parser



73
74
75
76
77
78
79
80
# File 'lib/gini-api/client.rb', line 73

def register_parser
  OAuth2::Response.register_parser(:gini_json, [version_header(:json)[:accept]]) do |body|
    MultiJson.load(body, symbolize_keys: true) rescue body
  end
  OAuth2::Response.register_parser(:gini_xml, [version_header(:xml)[:accept]]) do |body|
    MultiXml.parse(body) rescue body
  end
end

#request(verb, resource, options = {}) ⇒ Object

Request wrapper that sets URI and accept header

Parameters:

  • verb (Symbol)

    HTTP request verb (:get, :post, :put, :delete)

  • resource (String)

    API resource like /documents

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

    Optional type and custom headers

Options Hash (options):

  • :type (String)

    Type to pass to version_header (:xml, :json)

  • :headers (Hash)

    Custom headers. Must include accept



124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
# File 'lib/gini-api/client.rb', line 124

def request(verb, resource, options = {})
  opts = {
    headers: version_header(options.delete(:type) || @api_type)
  }.merge(options)

  timeout(@processing_timeout) do
    @token.send(verb.to_sym, resource_to_location(resource).to_s , opts)
  end
rescue OAuth2::Error => e
  raise Gini::Api::RequestError.new(
    "API request failed: #{verb} #{resource} (code=#{e.response.status})",
    e.response
  )
rescue Timeout::Error => e
  raise Gini::Api::ProcessingError.new(
    "API request timed out: #{verb} #{resource} (#{e.message})"
  )
end

#search(query, options = {}) ⇒ Gini::Api::DocumentSet

Fulltext search for documents

Parameters:

  • query (String, Array)

    The search term(s), separated by space. Multiple terms as array

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

    Search options

Options Hash (options):

  • :type (String)

    Only include documents with the given doctype

  • :limit (Integer)

    Number of results per page. Must be between 1 and 250. Defaults to 20

  • Integer (])

    nteger] :offset Start offset. Defaults to 0

Returns:



236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
# File 'lib/gini-api/client.rb', line 236

def search(query, options = {})
  opts   = { type: '', limit: 20, offset: 0 }.merge(options)
  query  = URI.escape(query)
  type   = URI.escape(opts[:type])
  limit  = Integer(opts[:limit])
  offset = Integer(opts[:offset])

  response = request(:get, "/search?q=#{query}&type=#{type}&limit=#{limit}&next=#{offset}")
  unless response.status == 200
    raise Gini::Api::SearchError.new(
      "Search query failed with code #{response.status}",
      response
    )
  end
  Gini::Api::DocumentSet.new(self, response.parsed)
end

#upload(file, interval = 0.5, &block) ⇒ Gini::Api::Document

Upload a document

Examples:

Upload and wait for completion

doc = api.upload('/tmp/myfile.pdf')

Upload and monitor progress

doc = api.upload('/tmp/myfile.pdf') { |d| puts "Progress: #{d.progress}" }

Parameters:

  • file (String)

    path of the document to upload

  • interval (Float) (defaults to: 0.5)

    Interval to poll progress

Returns:



155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
# File 'lib/gini-api/client.rb', line 155

def upload(file, interval = 0.5, &block)
  duration = Hash.new(0)

  # Document upload
  duration[:upload], response = upload_document(file)

  # Start polling (0.5s) when document has been uploaded successfully
  if response.status == 201
    doc = Gini::Api::Document.new(self, response.headers['location'])
    duration[:processing] = poll_document(doc, interval, &block)

    duration[:total] = duration.values.inject(:+)
    doc.duration = duration

    doc
  else
    fail Gini::Api::UploadError.new(
      "Document upload failed with HTTP code #{response.status}",
      response
    )
  end
end

#version_header(type = @api_type) ⇒ Hash

Version accept header based on @api_version

Parameters:

  • type (Symbol, String) (defaults to: @api_type)

    Expected response type (:xml, :json)

Returns:

  • (Hash)

    Return accept header or empty hash



112
113
114
# File 'lib/gini-api/client.rb', line 112

def version_header(type = @api_type)
  { accept: "application/vnd.gini.#{@api_version}+#{type}" }
end