class ALD::API

Public: Access the ALD API programatically.

Constants

DEFAULT_HEADERS

Internal: The default headers to be used in request.

Attributes

auth[R]

Public: Get current authentication information Hash (see auth=)

Public Class Methods

new(root_url) click to toggle source

Public: Create a new instance to access an ALD server.

root_url - a String pointing to the root URL of the server’s API.

Example

api = ALD::API.new('http://api.my_ald_server.com/v1/')
# File lib/ALD/api.rb, line 22
def initialize(root_url)
  @root_url = URI(root_url)
  @item_store, @user_store = {}, {}
end

Public Instance Methods

auth=(auth) click to toggle source

Public: Set authentication information for future requests.

auth - a Hash containing the authentication information:

:name     - the user name to use
:password - the plaintext password to use

Returns the hash that was passed.

Raises ArgumentError if the passed hash does not have the specified keys.

# File lib/ALD/api.rb, line 39
def auth=(auth)
  raise ArgumentError unless valid_auth?(auth)
  @auth = auth
end
item(*args) click to toggle source

Public: Get an individual item. This method is roughly equivalent to calling ItemCollection#[] on API#items. Calling this method might trigger a HTTP request.

Examples

api.item('185d265f24654545aad3f88e8a383339')
api.item('MyApp', '0.9.5')

# unlike ItemCollection#[], this also supports passing a Hash (and a Boolean):
api.item({'id' => '185d265f24654545aad3f88e8a383339',
         'name' => 'MyApp',
         'version' => '4.5.6'})
# However, this last form is only meant to be used internally and should
# never be called by library consumers.

Returns the ALD::API::Item instance representing the item, or nil if not found.

Raises ArgumentError if the arguments are not of one of the supported forms.

Signature

item(id)
item(name, version)

id - the GUID String of the item to return name - a String containing the item’s name version - a String containing the item’s semver version

# File lib/ALD/api.rb, line 114
def item(*args)
  if args.first.is_a? Hash # used internally to avoid multiple Item instances
    args.first['id'] = normalize_id(args.first['id'])
    @item_store[args.first['id']] ||= Item.new(self, *args)
  elsif args.length == 1 && args.first.is_a?(String) # GUID
    @item_store[normalize_id(args.first)] || items[args.first]
  elsif args.length == 2 # name and version
    items[*args]
  else
    raise ArgumentError
  end
end
items(conditions = nil) click to toggle source

Public: Get a collection of items from this server. This calls ItemCollection#where on the collection of all items. This method might trigger a HTTP request.

conditions - a Hash of conditions the items should meet.

Valid conditions are documented at ItemCollection#where.

Example

api.items.each { |i| puts i.name }
api.items(name: 'MyApp') # equivalent to api.items.where(name: 'MyApp')

Returns an ALD::API::ItemCollection containing the items.

Raises ArgumentError if the specified conditions are invalid.

# File lib/ALD/api.rb, line 59
def items(conditions = nil)
  @all_items ||= ItemCollection.new(self)
  @all_items.where(conditions)
end
normalize_id(id) click to toggle source

Internal: Given a GUID string, bring it into a standardized form. This is used internally to make comparing GUIDs easier.

id - the GUID String to normalize

Returns the normalized GUID String.

# File lib/ALD/api.rb, line 168
def normalize_id(id)
  id.upcase.gsub(/[^0-9A-F]/, '')
end
request(url, method = :get, headers = {}, body = nil) click to toggle source

Internal: Make a raw request to the ALD server. This is used internally, and library consumers should only call it if they are familiar with the ALD API.

url - the URL String, relative to the root URL, to request against. method - a Symbol indicating the HTTP method to use. Supported: :get, :post headers - a Hash containing additional headers (for the defaults see

::DEFAULT_HEADERS).

body - If method is :post, a request body to use.

Returns The response body; as Hash / Array if the ‘Content-type’ header indicates a JSON response; as raw String otherwise.

Raises ArgumentError is method is not supported.

Raises API::RequestError if the response code is not in (200…300).

# File lib/ALD/api.rb, line 193
def request(url, method = :get, headers = {}, body = nil)
  Net::HTTP.start(@root_url.host, @root_url.port) do |http|
    url = @root_url + url

    request = create_request(method, url)
    DEFAULT_HEADERS.merge(headers).each do |k, v|
      request[k] = v
    end

    response = http.request(request)
    response = request_with_auth(http, request, url, response) if response.code.to_i == 401

    raise RequestError unless (200...300).include?(response.code.to_i)
    if response['Content-type'].include?('application/json')
      JSON.parse(response.body)
    else
      response.body
    end
  end
end
user(*args) click to toggle source

Public: Get an individual user. This method is roughly equivalent to calling UserCollection#[] on API#users. Calling this method might trigger a HTTP request.

Examples

api.user('6a309ac8a4304f5cb1e6a2982f680ca5')
api.user('Bob')

# As #item, this method also supports being passed a Hash (and a Boolean),
# which should only be used internally.

Returns the ALD::API::User instance representing the user, or nil if not found.

Raises ArgumentError if the arguments are not of one of the supported forms.

Signature

user(id)
user(name)

id - a 32-character GUID string containing the user’s ID name - a String containing the user’s name

# File lib/ALD/api.rb, line 151
def user(*args)
  if args.first.is_a? Hash # used internally to avoid multiple User instances
    args.first['id'] = normalize_id(args.first['id'])
    @user_store[args.first['id']] ||= User.new(self, *args)
  elsif args.length == 1 && args.first.is_a?(String)
    @user_store[normalize_id(args.first)] || users[args.first]
  else
    raise ArgumentError
  end
end
users(conditions = nil) click to toggle source

Public: Get a collection of users on this server. This calls UserCollection#where on the collection of all users. This method might trigger a HTTP request.

conditions - a Hash of conditions the users should meet.

Valid conditions are documented at UserCollection#where.

Returns an ALD::API::UserCollection containing the users.

# File lib/ALD/api.rb, line 72
def users(conditions = nil)
  @all_users ||= UserCollection.new(self)
  @all_users.where(conditions)
end
version() click to toggle source

Public: Get the API version supported by the server. This method triggers a HTTP request.

Returns the semver version string of the API.

# File lib/ALD/api.rb, line 81
def version
  @version ||= request('/version')['version']
end

Private Instance Methods

auth_method(response) click to toggle source

Internal: Get the authentication method used by a server

response - the Net::HTTPResponse to examine

Returns the used method as Symbol, e.g. :digest or :basic

# File lib/ALD/api.rb, line 272
def auth_method(response)
  response['WWW-Authenticate'].strip.split(' ')[0].downcase.to_sym
end
create_request(method, url) click to toggle source

Internal: Create a new Net::HTTPRequest for the given method.

method - a Symbol indicating the HTTP verb (lowercase url - the URI to request

Returns a Net::HTTPRequest for the given method.

Raises ArgumentError if the verb is not supported.

# File lib/ALD/api.rb, line 224
def create_request(method, url)
  case method
    when :get
      Net::HTTP::Get.new url.request_uri
    when :post
      Net::HTTP::Post.new url.request_uri
    else
      raise ArgumentError
  end
end
request_with_auth(http, request, url, failed_response) click to toggle source

Internal: Retry a request with authentication

http - a Net::HTTP object to use for the request request - the Net::HTTPRequest to use url - the URI that is requested failed_response - the response that was given when requesting without auth

Returns a successful Net::HTTPResponse for the request.

Raises NoAuthError if @auth is not set.

Raises UnsupportedAuthMethodError if the server uses a not supported auth method.

Raises InvalidAuthError if the authenticated request yields a 401 response.

# File lib/ALD/api.rb, line 250
def request_with_auth(http, request, url, failed_response)
  raise NoAuthError if @auth.nil?
  case auth_method(failed_response)
    when :basic
      request.basic_auth(@auth[:name], @auth[:password])
    when :digest
      url.user, url.password = @auth[:name], @auth[:password]
      request.add_field 'Authorization', Net::HTTP::DigestAuth.new.auth_header(url, failed_response['WWW-Authenticate'], request.method)
    else
      raise UnsupportedAuthMethodError
  end

  response = http.request(request)
  raise InvalidAuthError if response.code.to_i == 401
  response
end
valid_auth?(auth) click to toggle source

Internal: Check if a Hash contains valid auth data

auth - the Hash to check

Returns true, if the Hash contains the necessary keys, false otherwise.

# File lib/ALD/api.rb, line 281
def valid_auth?(auth)
  auth.is_a?(Hash) && %w[name password].all? { |k| auth.key?(k.to_sym) }
end