GitHub Stars GitHub Forks License Build Status RubyGems Version

Purpose

The lutaml-hal gem provides a framework for interacting with HAL-compliant APIs using the power of LutaML Models.

Hypertext Application Language (HAL) (HAL Internet-Draft) is a simple format for representing resources and their relationships in a hypermedia-driven API.

It allows clients to navigate and interact with resources using links, making it easier to build flexible and extensible applications.

This library provides a set of classes and methods for modeling HAL resources, links, and collections, as well as a client for making HTTP requests to HAL APIs.

Features

  • Classes for modeling HAL resources and links

  • A client for making HTTP requests to HAL APIs

  • Tools for pagination and resource resolution

  • Integration with the lutaml-model serialization framework

  • Error handling and response validation for API interactions

  • Comprehensive embed support for reducing HTTP requests and improving performance

Installation

Add this line to your application’s Gemfile:

gem 'lutaml-hal'

And then execute:

$ bundle install

Or install it yourself as:

$ gem install lutaml-hal

Quick start

Here’s a minimal example to get you started:

require 'lutaml-hal'

# Define a HAL resource
class Product < Lutaml::Hal::Resource
  attribute :id, :string
  attribute :name, :string
  attribute :price, :float

  hal_link :self, key: 'self', realize_class: 'Product'
  hal_link :category, key: 'category', realize_class: 'Category'

  key_value do
    map 'id', to: :id
    map 'name', to: :name
    map 'price', to: :price
  end
end

# Set up API client and register
client = Lutaml::Hal::Client.new(api_url: 'https://api.example.com')
register = Lutaml::Hal::ModelRegister.new(name: :my_api, client: client)

# Register endpoints
register.add_endpoint(
  id: :product_resource,
  type: :resource,
  url: '/products/{id}',
  model: Product
)

# Fetch and use resources
product = register.fetch(:product_resource, id: '123')
puts product.name
puts product.price

# Navigate to related resources
category = product.links.category.realize(register)
puts category.name

Documentation

Comprehensive guides

For detailed documentation, see these comprehensive guides:

Architecture overview

The library is organized into these main components:

Lutaml::Hal::Client

HTTP client for making requests to HAL APIs. Supports GET requests with automatic response handling.

Lutaml::Hal::ModelRegister

Registry for managing HAL resource models and their API endpoints. Handles URL resolution and resource fetching.

Lutaml::Hal::GlobalRegister

Optional singleton for managing multiple ModelRegisters and enabling automatic link resolution.

Lutaml::Hal::Resource

Base class for defining HAL resource models with attributes, links, and serialization mappings.

Lutaml::Hal::Link

Represents HAL links with automatic realization capabilities for fetching target resources.

Lutaml::Hal::Page

Specialized resource class for handling pagination with navigation methods and helper functions.

Usage workflow

The lutaml-hal workflow follows a two-phase approach:

1. Data definition phase

  1. Define resource models: Create classes inheriting from Lutaml::Hal::Resource

  2. Set up client: Create a Client instance pointing to your API

  3. Create register: Set up a ModelRegister to manage your models

  4. Register endpoints: Map your models to specific API URLs

2. Runtime phase

  1. Fetch resources: Use register.fetch() to get data from the API

  2. Access attributes: Work with resource data as normal Ruby objects

  3. Navigate links: Use HAL links to move between related resources

  4. Realize links: Convert links to actual resource instances

Path matching specification

The library supports sophisticated URL pattern matching for endpoint registration. Patterns use curly braces {} for parameter interpolation:

# Simple patterns
'/products/{id}'
'/users/{user_id}/orders/{order_id}'

# With query parameters
register.add_endpoint(
  id: :search_products,
  type: :index,
  url: '/products',
  model: ProductIndex,
  parameters: [
    Lutaml::Hal::EndpointParameter.query('category',
      schema: { type: :string },
      description: 'Product category filter'
    ),
    Lutaml::Hal::EndpointParameter.query('page',
      schema: { type: :integer },
      description: 'Page number'
    ),
    Lutaml::Hal::EndpointParameter.query('limit',
      schema: { type: :integer },
      description: 'Results per page'
    )
  ]
)

For complex path pattern examples, see Complex Path Patterns.

Error handling

The library provides structured error handling:

begin
  product = register.fetch(:product_resource, id: '123')
rescue Lutaml::Hal::Errors::NotFoundError => e
  puts "Product not found: #{e.message}"
rescue Lutaml::Hal::Errors::ApiError => e
  puts "API Error: #{e.message}"
end

Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/lutaml/lutaml-hal.

This project is licensed under the BSD 2-clause License. See the LICENSE.md file for details.

Copyright Ribose.