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',
)

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)

  • :user_agent (String)

    HTTP User-Agent (gini-api-ruby/VERSION (Faraday vFaraday::VERSION))


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
70
71
# File 'lib/gini-api/client.rb', line 36

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),
    user_agent: "gini-api-ruby/#{VERSION} (Faraday v#{Faraday::VERSION})"
  }.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


201
202
203
204
205
206
207
208
209
210
# File 'lib/gini-api/client.rb', line 201

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


218
219
220
# File 'lib/gini-api/client.rb', line 218

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

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

List all documents

Options Hash (options):

  • :limit (Integer)

    Maximum number of documents to return (defaults to 20)

  • :offset (Integer)

    Start offset. Defaults to 0


230
231
232
233
234
235
236
237
238
239
240
241
242
243
# File 'lib/gini-api/client.rb', line 230

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')

Options Hash (opts):

  • :auth_code (String)

    OAuth authorization code. Will be exchanged for a token

  • :username (String)

    API username

  • :password (String)

    API password


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

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

#logoutObject

Destroy OAuth2 token


107
108
109
# File 'lib/gini-api/client.rb', line 107

def logout
  @oauth.destroy
end

#register_parserObject

Register OAuth2 response parser


75
76
77
78
79
80
81
82
83
84
85
# File 'lib/gini-api/client.rb', line 75

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
  OAuth2::Response.register_parser(:gini_incubator, [version_header(:json, :incubator)[:accept]]) do |body|
    MultiJson.load(body, symbolize_keys: true) rescue body
  end
end

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

Request wrapper that sets URI and accept header

Options Hash (options):

  • :type (String)

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

  • :headers (Hash)

    Custom headers. Must include accept


130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
# File 'lib/gini-api/client.rb', line 130

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

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


255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
# File 'lib/gini-api/client.rb', line 255

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, options = {}, &block) ⇒ Gini::Api::Document

Upload a document

Examples:

Upload and wait for completion

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

Upload with doctype hint

doc = api.upload('/tmp/myfile.pdf', doctype_hint: 'Receipt')

Upload and monitor progress

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

Upload and monitor progress

doc = api.upload('This is a text message i would love to get extractions from', text: true)

Options Hash (options):

  • :doctype_hint (String)

    Document type hint to optimize results or get incubator results

  • :text (String)

    Use given file-string as text upload

  • :interval (Float)

    Interval to poll progress


168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
# File 'lib/gini-api/client.rb', line 168

def upload(file, options = {}, &block)
  opts = {
    doctype_hint: nil,
    text: false,
    interval: 0.5
  }.merge(options)

  duration = Hash.new(0)

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

  # 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, opts[: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, version = @api_version) ⇒ Hash

Version accept header based on @api_version


118
119
120
# File 'lib/gini-api/client.rb', line 118

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