Project

alma_api

0.0
A long-lived project that still receives updates
A Ruby client library for the Ex Libris Alma REST APIs
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
 Dependencies

Runtime

~> 2.7
~> 5.0
~> 1.11
~> 3.11
 Project Readme

Alma REST API Ruby library

Tests Test Coverage Maintainability Gem Version MIT License

This is a simple Ruby library that acts as a wrapper for the Ex Libris Alma REST APIs.

The main purpose of this library is to abstract authentication, error handling, and response parsing.

It uses faraday as the underlying http client, nokogiri for XML parsing, and oj and hashie for JSON processing.

Note: This is NOT an official Alma API client. It is developed at the University Library of Paderborn as an open source project and used in production as part of the library's discovery portal.

Installation

Add this to your Gemfile:

gem "alma_api"

and run the bundle install command in your terminal.

Usage

You need an API key for your Alma Instance in order to use this client. Please consult the Ex Libris developer documentation on how to use the Alma REST APIs for more information how to get and setup your API keys.

Note: There a some changes when upgrading from 1.x to 2.x. Please read the section on upgrading below.

Quick example

Here is a minimal example to get started. Read the sections below for more information on how to use this library.

# Create a client
client = AlmaApi::Client.configure do |config|
  config.api_key = "YOUR API KEY"
end

# Use the client to get some users
users = client.get("users", params: {limit: 2})

Creating a configuration

To use this library you need an AlmaApi::Client instance. To create a client you first need an AlmaApi::Configuration.

# Normal method
configuration = AlmaApi::Configuration.new(api_key: "YOUR API KEY")
# ... or
configuration = AlmaApi::Configuration.new
configuration.api_key = "YOUR API KEY"

# Block-style
configuration = AlmaApi::Configuration.new do |config|
  config.api_key = "YOUR API KEY"
end

The api_key is the only required option to get a functional configuration. There are sensible default values for all other options.

The following options are available:

  1. api_key Set your Alma API key. This is the only option that can be passed to the constructor as a shortcut. All other options must be set using setters.

  2. base_url Set the base URL to be used for each request. Ex Libris provides different API gateways for different geographical locations. See the documentation here for more information. This parameter is optional and defaults to the Alma API Gateway for Europe.

    This expects a String with a valid URL. However, you can use a Symbol as a shortcut to set the base_url for one of the preconfigured gateways :na (North America), :eu (Europe), :ap (Asia-Pacific), :ca (Canada), :cn (China).

    For example, to set the base_url for the canadian gateway, use

      configuration = AlmaApi::Configuration.new do |config|
        config.api_key  = "YOUR API KEY"
        config.base_url = :ca
      )
  3. default_format The default format to use for each request. The client supports "json" and "xml". The default is "json".

  4. language The language used by Alma for error messages and textual information. The default is English ("en"). To change this, set this parameter to any 2-letter language code that is supported and enabled in Alma (see the mapping table "Institution Languages" in Alma).

  5. timeout The max number of seconds (Integer, Float) to wait for a request to complete. The default is nil which uses the default of the underlying Faraday adapter (Net::HTTP).

Creating a client

With the configuration ready, you can create the client.

client = AlmaApi::Client.new(configuration)

As a shortcut, you can call AlmaApi::Client.configure with a block to get the client instance. Note that each call to AlmaApi::Client.configure returns a new AlmaApi::Client instance.

client = AlmaApi::Client.configure do |config|
  config.api_key = "..."
  ...
end

Using the client

Calling Alma

The client provides the following methods: #get, #post, #put and #delete to call the Alma APIs with the corresponding HTTP methods GET, POST, PUT and DELETE.

Each method expects a URL path to the resource relative to the configured base_url as it's first parameter. Parameters that the Alma API expects as part of the URL path must be included here.

To set query string parameters, set the params: option and provide a Ruby Hash. To override the default_format for an individual request, you can set the format: option to "json" or "xml", depending on your needs. Setting the format to "xml" is preferable for Alma APIs that work with MARCXML data.

To set the body of a #post or #put request, you can set the body: option. If the request format is "json", the body: option should contain a valid json string. Otherwise, if the request format is "xml", the option should be a valid XML string.

In the case of a JSON request, the result of the call is a Ruby Hash. For a XML request, the result is a Nokogiri::XML::Document instance, as this library uses nokogiri under the hood for XML processing.

Get remaining API calls

Alma reports the number of remaining API calls as part of the response. You can call #remaining_api_calls on the client to get this number. In case of an error this simply returns -1.

Examples

GET requests

Retrieve users

# Retrieve users (JSON)
users = client.get("users", params: {limit: 2})

# Retrieve users (XML)
users = client.get("users", params: {limit: 2}, format: :xml)

POST and PUT requests

Creating a user

# Prepare the data for a new user in Alma
user_data = {
  record_type: {value: "PUBLIC"},
  account_type: {value: "INTERNAL"},
  preferred_language: {value: "de"},
  status: {value: "ACTIVE"},
  first_name: "FIRSTNAME",
  last_name: "LASTNAME",
  birth_date: "1978-07-07",
  [...]
  password: "SECRET PASSWORD",
  force_password_change: true
}

# Create the user in Alma
user = client.post(
  "users",
  params: {
    source_user_id: "xxx"
  },
  body: user_data.to_json
)

Updating a user

# First, get the user
user_id = "..." # a unique identifier for the user
user = client.get("users/#{user_id}") # user_id is a URL parameter

# Change the last name of the user
user["last_name"] = "..."

# Update the user in Alma
user = client.put("users/#{user_id}", body: user.to_json)

DELETE requests

Deleting a user

user_id = "..." # a unique identifier for the user
client.delete("users/#{user_id}") # user_id is a URL parameter

Error handling

There are four types of errors that can occur when calling the Alma APIs with this library.

1. AlmaApi::Error

This is the base error class for this library. All errors raised within this library during a request will result in an AlmaApi::Error or in one of the more specific sub classes listed below.

This error is also raised if something goes wrong when opening the connection, on SSL errors, network timeouts, etc.

The original error is wrapped and is available via the #cause method.

Each error exposes #message and #code methods for further inspection. Messages that are generated by Alma are returned in the language set in the configuration (default is English).

The code is generated by Alma. For gateway errors, the code is a string token (e.g. REQUEST_TOO_LARGE). For logical errors, the code is usually a number (e.g. 401850). See the "Possible Error Codes" section for each resource in the documentation for details. For some errors, code may be nil.

2. AlmaApi::GatewayError

If the Alma API responds with a 4xx OR 5xx HTTP status AND one of the following error codes, an AlmaApi::GatewayError is raised.

GENERAL_ERROR, UNAUTHORIZED, INVALID_REQUEST, PER_SECOND_THRESHOLD, DAILY_THRESHOLD, REQUEST_TOO_LARGE, FORBIDDEN, ROUTING_ERROR

Check the the documentation here for more information about gateway errors.

3. AlmaApi::ServerError

Any 5xx HTTP status that does not result in an AlmaApi::GatewayError will be raised as an AlmaApi::ServerError.

4. AlmaApi::LogicalError

Any 4xx HTTP status that does not result in an AlmaApi::GatewayError will be raised as an AlmaApi::LogicalError.

This is the most common error you will encounter and can be used to manage the control flow in your application.

For example, if you're loading a user's details, you usually don't want your application to blow up if a user with the specified user ID doesn't exist. Instead, you can handle the error like this:

def load_user(user_id)
  client.get("users/#{user_id}")
rescue AlmaApi::LogicalError => e
  # log the error
  puts "Error #{e.code}: #{e.message}"

  # ... the error code could be inspected and we could perform
  # different things based on the error code but in this case
  # we just return nil to indicate that the user does not exists.
  nil
end

if (user = load_user("ALMA_USER_ID"))
  puts "Hello #{user["first_name"]} #{user["last_name"]}"
else
  puts "Too bad. No such user."
end

Tweaking a request

As stated before this library uses faraday as the underlying http client. It manages the Faraday connection, sets up the necessary headers and params and performs the requests against Alma.

Therefore there should be no need to tweak a request before sending it to Alma. This should be considered as a bug and we are happy to receive feature requests.

However, there is still a way to tweak a request. For #get, #post, #put and #delete, you can open a block that gives you access to the Faraday::Request instance, which you can use to manipulate the request before it is sent to Alma.

client.get("some/path") do |req|
  req.headers["foo"] = "bar"
end

Upgrading

From 1.x to 2.x

  • AlmaApi.configure is deprecated. Use AlmaApi::Client.configure instead.
  • All errors that get raised during a request result in an AlmaApi::Error. Use #cause to get the causing error.
  • AlmaApi::Client#remaining_api_calls performs a request to read the value from Alma.
  • AlmaApi::Configuration can be used to set a request timeout.