Class: Orchestrate::Client

Inherits:
Object
  • Object
show all
Defined in:
lib/orchestrate/client.rb

Overview

The "method client": A single entry point to an Orchestrate Application, with methods for accessing each API endpoint.

Instance Attribute Summary collapse

Collections collapse

Key/Value collapse

Events collapse

Graphs / Relations collapse

Instance Method Summary collapse

Constructor Details

#initialize(api_key, host = "https://api.orchestrate.io") {|The| ... } ⇒ Object

TODO:

api_key -> app_url, parse api_key from auth section of url

Instantiate a new Client for an Orchestrate application.

Yield Parameters:

  • The (Faraday::Connection)

    setup for the faraday connection.


28
29
30
31
32
33
34
35
36
37
38
39
40
# File 'lib/orchestrate/client.rb', line 28

def initialize(api_key, host="https://api.orchestrate.io", &block)
  @api_key = api_key
  @host = host
  @faraday_configuration = block
  @http = Faraday.new(@host) do |faraday|
    block = lambda{|f| f.adapter :net_http_persistent } unless block
    block.call faraday

    # faraday seems to want you do specify these twice.
    faraday.request :basic_auth, api_key, ''
    faraday.basic_auth api_key, ''
  end
end

Instance Attribute Details

#api_keyString (readonly)


11
12
13
# File 'lib/orchestrate/client.rb', line 11

def api_key
  @api_key
end

#faraday_configurationProc (readonly)


20
21
22
# File 'lib/orchestrate/client.rb', line 20

def faraday_configuration
  @faraday_configuration
end

#hostString (readonly)


14
15
16
# File 'lib/orchestrate/client.rb', line 14

def host
  @host
end

#httpFaraday::Connection (readonly)


17
18
19
# File 'lib/orchestrate/client.rb', line 17

def http
  @http
end

Instance Method Details

#delete(collection, key, ref = nil) ⇒ Object

Note:

previous versions of the values at this key are still available via #list_refs and #get.

Sets the current value of a key to a null object.

Raises:

  • Orchestrate::API::VersionMismatch if the provided ref is not the ref for the current value.


217
218
219
220
221
# File 'lib/orchestrate/client.rb', line 217

def delete(collection, key, ref=nil)
  headers = {}
  headers['If-Match'] = API::Helpers.format_ref(ref) if ref
  send_request :delete, [collection, key], { headers: headers }
end

#delete_collection(collection) ⇒ Object

Note:

The Orchestrate API will return succesfully regardless of if the collection exists or not.

Deletes an entire collection


84
85
86
# File 'lib/orchestrate/client.rb', line 84

def delete_collection(collection)
  send_request :delete, [collection], { query: {force:true} }
end

#delete_relation(collection, key, kind, to_collection, to_key) ⇒ Object


397
398
399
400
# File 'lib/orchestrate/client.rb', line 397

def delete_relation(collection, key, kind, to_collection, to_key)
  path = [collection, key, 'relation', kind, to_collection, to_key]
  send_request :delete, path, { query: {purge: true} }
end

#get(collection, key, ref = nil) ⇒ Object

Raises:

  • Orchestrate::API::NotFound If the key or ref doesn't exist.

  • Orchestrate::API::MalformedRef If the ref provided is not a valid ref.


100
101
102
103
104
# File 'lib/orchestrate/client.rb', line 100

def get(collection, key, ref=nil)
  path = [collection, key]
  path.concat(['refs', ref]) if ref
  send_request :get, path, { response: API::ItemResponse }
end

#get_event(collection, key, event_type, timestamp, ordinal) ⇒ Object

Raises:

  • Orchestrate::API::NotFound If the requested event doesn't exist.


267
268
269
270
271
# File 'lib/orchestrate/client.rb', line 267

def get_event(collection, key, event_type, timestamp, ordinal)
  timestamp = API::Helpers.timestamp(timestamp)
  path = [collection, key, 'events', event_type, timestamp, ordinal]
  send_request :get, path, { response: API::ItemResponse }
end

#get_relations(collection, key, *kinds) ⇒ Object

Examples:

Retrieves the friend's of John's family

client.get_relations(:users, 'john', :family, :friends)

If the relation facets exist in an array, use:

relations = [:family, :friends]
client.get_relations(:users, 'john', *relations)

Raises:

  • Orchestrate::API::NotFound If the given collection/key doesn't exist.


372
373
374
375
# File 'lib/orchestrate/client.rb', line 372

def get_relations(collection, key, *kinds)
  path = [collection, key, 'relations'].concat(kinds)
  send_request :get, path, {response: API::CollectionResponse}
end

#in_parallel {|accumulator| ... } ⇒ Object

Note:

This method is not Thread-safe. Requests generated from the same client in different threads while #in_parallel is running will behave unpredictably. Use #dup to create per-thread clients.

Performs requests in parallel. Requires using a Faraday adapter that supports parallel requests.

Examples:

Performing three requests at once

responses = client.in_parallel do |r|
  r[:some_items] = client.list(:site_globals)
  r[:user] = client.get(:users, current_user_key)
  r[:user_feed] = client.list_events(:users, current_user_key, :notices)
end

Yield Parameters:

  • accumulator (Hash)

    A place to store the results of the parallel responses.

See Also:

  • See the Readme for more examples.

416
417
418
419
420
421
422
# File 'lib/orchestrate/client.rb', line 416

def in_parallel(&block)
  accumulator = {}
  http.in_parallel do
    block.call(accumulator)
  end
  accumulator
end

#list(collection, options = {}) ⇒ Object

Note:

The Orchestrate API may return an error if you include both the :start/:after or :before/:end keys. The client will not stop you from doing this.

Note:

To include all keys in a collection, do not include any :start/:after/:before/:end parameters.

List the KeyValue items in a collection. Results are sorted results lexicographically by key name and paginated.

Options Hash (options):

  • :limit (Integer) — default: 10

    The number of results to return. Maximum 100.

  • :start (String)

    The inclusive start key of the query range.

  • :after (String)

    The exclusive start key of the query range.

  • :before (String)

    The exclusive end key of the query range.

  • :end (String)

    The inclusive end key of the query range.

Raises:

  • Orchestrate::API::InvalidSearchParam The :limit value is not valid.


249
250
251
252
# File 'lib/orchestrate/client.rb', line 249

def list(collection, options={})
  API::Helpers.range_keys!('key', options)
  send_request :get, [collection], { query: options, response: API::CollectionResponse }
end

#list_events(collection, key, event_type, options = {}) ⇒ Object

Lists events associated with a key. Results are time-ordered in reverse-chronological order, and paginated.

Options Hash (options):

  • :limit (Integer) — default: 10

    The number of results to return. Default 100.

  • :start (Date, Time, String, Integer)

    The inclusive start of the range.

  • :after (Date, Time, String, Integer)

    The exclusive start of the range.

  • :before (Date, Time, String, Integer)

    The exclusive end of the range.

  • :end (Date, Time, String, Integer)

    The inclusive end of the range.

Raises:

  • Orchestrate::API::NotFound If the provided collection/key doesn't exist.


349
350
351
352
353
354
355
356
# File 'lib/orchestrate/client.rb', line 349

def list_events(collection, key, event_type, options={})
  (options.keys & [:start, :after, :before, :end]).each do |param|
    options[param] = API::Helpers.timestamp(options[param])
  end
  API::Helpers.range_keys!('event', options)
  path = [collection, key, 'events', event_type]
  send_request :get, path, { query: options, response: API::CollectionResponse }
end

#list_refs(collection, key, options = {}) ⇒ Object

List historical refs for values of a key. Results are time-ordered newest-to-oldest and paginated.

Options Hash (options):

  • :limit (Integer) — default: 10

    The number of results to return. Maximum 100.

  • :offset (Integer) — default: 0

    The starting position of the results.

  • :values (true, false) — default: false

    Whether to return the value for each ref. Refs with no content (for example, deleted with #delete) will not have a value, but marked with a 'tombstone' => true key.

Raises:

  • Orchestrate::API::NotFound If there are no values for the provided key/collection.

  • Orchestrate::API::InvalidSearchParam The :limit/:offset values are not valid.

  • Orchestrate::API::MalformedRef If the ref provided is not a valid ref.


120
121
122
# File 'lib/orchestrate/client.rb', line 120

def list_refs(collection, key, options={})
  send_request :get, [collection, key, :refs], { query: options, response: API::CollectionResponse }
end

#patch(collection, key, body, condition = nil) ⇒ Object

Manipulate values associated with a key, without retrieving the key object. Array of operations passed as body, will execute operations on the key sequentially. Patch.

Raises:

  • Orchestrate::API::BadRequest the body is not valid JSON.

  • Orchestrate::API::AlreadyPresent the false condition was given, but a value already exists for this collection/key combo.


181
182
183
184
185
186
187
# File 'lib/orchestrate/client.rb', line 181

def patch(collection, key, body, condition=nil)
  headers = {'Content-Type' => 'application/json-patch+json'}
  if condition.is_a?(String)
    headers['If-Match'] = API::Helpers.format_ref(condition)
  end
  send_request :patch, [collection, key], { body: body, headers: headers, response: API::ItemResponse }
end

#patch_merge(collection, key, body, condition = nil) ⇒ Object

Merge field/value pairs into existing key, without retrieving the key object. Patch. If a given field's value is nil, will remove field from existing key on merge.

Raises:

  • Orchestrate::API::BadRequest the body is not valid JSON.

  • Orchestrate::API::AlreadyPresent the false condition was given, but a value already exists for this collection/key combo.


201
202
203
204
205
206
207
# File 'lib/orchestrate/client.rb', line 201

def patch_merge(collection, key, body, condition=nil)
  headers = {'Content-Type' => 'application/merge-patch+json'}
  if condition.is_a?(String)
    headers['If-Match'] = API::Helpers.format_ref(condition)
  end
  send_request :patch, [collection, key], { body: body, headers: headers, response: API::ItemResponse }
end

#pingObject

Tests authentication with Orchestrate.

Raises:

  • Orchestrate::API::Unauthorized if the client could not authenticate.


56
57
58
# File 'lib/orchestrate/client.rb', line 56

def ping
  send_request :head, []
end

#post(collection, body) ⇒ Object


129
130
131
# File 'lib/orchestrate/client.rb', line 129

def post(collection, body)
  send_request :post, [collection], { body: body, response: API::ItemResponse }
end

#post_event(collection, key, event_type, body, timestamp = nil) ⇒ Object

Raises:

  • Orchestrate::API::BadRequest If the body is not valid JSON.


283
284
285
286
287
# File 'lib/orchestrate/client.rb', line 283

def post_event(collection, key, event_type, body, timestamp=nil)
  timestamp = API::Helpers.timestamp(timestamp)
  path = [collection, key, 'events', event_type, timestamp].compact
  send_request :post, path, { body: body, response: API::ItemResponse }
end

#purge(collection, key, ref = nil) ⇒ Object


229
230
231
232
233
# File 'lib/orchestrate/client.rb', line 229

def purge(collection, key, ref=nil)
  headers = {}
  headers['If-Match'] = API::Helpers.format_ref(ref) if ref
  send_request :delete, [collection, key], { query: { purge: true }, headers: headers }
end

#purge_event(collection, key, event_type, timestamp, ordinal, ref = nil) ⇒ Object

Raises:

  • Orchestrate::API::VersionMismatch The event's current value has a ref that does not match the provided ref.

  • Orchestrate::API::MalformedRef If the ref provided is not a valid ref.


328
329
330
331
332
333
334
# File 'lib/orchestrate/client.rb', line 328

def purge_event(collection, key, event_type, timestamp, ordinal, ref=nil)
  timestamp = API::Helpers.timestamp(timestamp)
  path = [collection, key, 'events', event_type, timestamp, ordinal]
  headers = {}
  headers['If-Match'] = API::Helpers.format_ref(ref) if ref
  send_request :delete, path, { query: { purge: true }, headers: headers }
end

#put(collection, key, body, condition = nil) ⇒ Object Also known as: put_if_unmodified

Updates the value associated with a key. If the key does not currently have a value, will create the value.

Raises:

  • Orchestrate::API::BadRequest the body is not valid JSON.

  • Orchestrate::API::IndexingConflict One of the value's keys contains a value of a different type than the schema that exists for the collection.

  • Orchestrate::API::VersionMismatch A ref was provided, but it does not match the ref for the current value.

  • Orchestrate::API::AlreadyPresent the false condition was given, but a value already exists for this collection/key combo.

See Also:


151
152
153
154
155
156
157
158
159
# File 'lib/orchestrate/client.rb', line 151

def put(collection, key, body, condition=nil)
  headers={}
  if condition.is_a?(String)
    headers['If-Match'] = API::Helpers.format_ref(condition)
  elsif condition == false
    headers['If-None-Match'] = '"*"'
  end
  send_request :put, [collection, key], { body: body, headers: headers, response: API::ItemResponse }
end

#put_event(collection, key, event_type, timestamp, ordinal, body, ref = nil) ⇒ Object

Raises:

  • Orchestrate::API::NotFound The specified event doesn't exist.

  • Orchestrate::API::BadRequest If the body is not valid JSON.

  • Orchestrate::API::VersionMismatch The event's current value has a ref that does not match the provided ref.

  • Orchestrate::API::MalformedRef If the ref provided is not a valid ref.


306
307
308
309
310
311
312
# File 'lib/orchestrate/client.rb', line 306

def put_event(collection, key, event_type, timestamp, ordinal, body, ref=nil)
  timestamp = API::Helpers.timestamp(timestamp)
  path = [collection, key, 'events', event_type, timestamp, ordinal]
  headers = {}
  headers['If-Match'] = API::Helpers.format_ref(ref) if ref
  send_request :put, path, { body: body, headers: headers, response: API::ItemResponse }
end

#put_if_absent(collection, key, body) ⇒ Object

See Also:


165
166
167
# File 'lib/orchestrate/client.rb', line 165

def put_if_absent(collection, key, body)
  put collection, key, body, false
end

#put_relation(collection, key, kind, to_collection, to_key) ⇒ Object

Creates a relationship between two Key/Value objects. Relations can span collections.

Raises:

  • Orchestrate::API::NotFound If either end of the relation doesn't exist.


386
387
388
# File 'lib/orchestrate/client.rb', line 386

def put_relation(collection, key, kind, to_collection, to_key)
  send_request :put, [collection, key, 'relation', kind, to_collection, to_key], { body: {} }
end

#search(collection, query, options = {}) ⇒ Object

Search the items in a collection using a Lucene Query Syntax.

Options Hash (options):

  • :limit (Integer) — default: 10

    The number of results to return. Maximum 100.

  • :offset (Integer) — default: 0

    The starting position of the results.

  • :sort (String)

    The field and direction to sort by. Ex: value.name:asc

Raises:

  • Orchestrate::API::InvalidSearchParam The :limit/:offset values are not valid.

  • Orchestrate::API::SearchQueryMalformed if query isn't a valid Lucene query.


75
76
77
78
# File 'lib/orchestrate/client.rb', line 75

def search(collection, query, options={})
  send_request :get, [collection], { query: options.merge({query: query}),
                                     response: API::CollectionResponse }
end

#send_request(method, path, options = {}) ⇒ Object

Performs an HTTP request against the Orchestrate API

Options Hash (options):

  • :query (Hash) — default: {}

    Query String parameters.

  • :body (#to_json) — default: ''

    The request body.

  • :headers (Hash) — default: {}

    Extra request headers.

  • :response (Class) — default: Orchestrate::API::Response

    A subclass of Orchestrate::API::Response to instantiate and return

Raises:


434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
# File 'lib/orchestrate/client.rb', line 434

def send_request(method, path, options={})
  path = ['/v0'].concat(path.map{|s| URI.escape(s.to_s).gsub('/','%2F') }).join('/')
  query_string = options.fetch(:query, {})
  body = options.fetch(:body, '')
  headers = options.fetch(:headers, {})
  headers['User-Agent'] = "ruby/orchestrate/#{Orchestrate::VERSION}"
  headers['Accept'] = 'application/json' if method == :get
  headers['Connection'] = 'close' if method == :head

  http_response = http.send(method) do |request|
    request.url path, query_string
    if [:put, :post].include?(method)
      headers['Content-Type'] = 'application/json'
      request.body = body.to_json
    elsif [:patch].include?(method)
      request.body = body.to_json
    end
    headers.each {|header, value| request[header] = value }
  end

  response_class = options.fetch(:response, API::Response)
  response_class.new(http_response, self)
end