A Grape API that uses Roar to serve HAL hypermedia, including CRUD operations, pagination, templated links, and Swagger documentation.
Use Ruby 3.3 or newer. This branch uses an ActiveModel Spline generated on demand, with no database or persistent writes.
bundle install
RACK_ENV=development bundle exec puma -p 9292Open localhost:9292/api to explore the API's HAL links, or localhost:9292/api/swagger_doc for Swagger documentation.
Create a spline by posting a JSON object nested under spline:
curl --include http://localhost:9292/api/splines \
--header 'Content-Type: application/json' \
--data '{"spline":{"reticulated":true}}'The response is 201 Created with the spline's uuid, reticulated value, and HAL links. Send a PUT to an individual spline URL to update it:
curl --include --request PUT http://localhost:9292/api/splines/123 \
--header 'Content-Type: application/json' \
--data '{"spline":{"reticulated":false}}'The response is 200 OK with uuid: "123" and reticulated: false. Both endpoints also accept Content-Type: application/hal+json. The default branch's dummy model accepts any UUID and does not persist writes; 123 is an example identifier, not the UUID generated by POST.
Hyperclient can create, list, update, and delete splines through the API. See splines_endpoint_with_hyperclient_spec.rb for the corresponding request coverage.
With the server running, open a second terminal:
bundle exec irbReuse one client for this sequence. Hyperclient's default middleware encodes Ruby Hash request bodies as HAL JSON, and the returned self links handle each branch's identifier format. The final call deletes only the spline created by this example, not the collection:
require 'hyperclient'
client = Hyperclient.new('http://localhost:9292/api')
spline = client.splines._post(spline: { reticulated: true })
puts spline._links.self._url
puts spline.reticulated
spline = spline._put(spline: { reticulated: false })
puts spline.reticulated
client.splines(size: 2).each do |item|
puts "#{item._links.self._url}: #{item.reticulated}"
end
spline._deletePassing size: 2 expands a fresh collection link after POST instead of reusing its cached response. Hyperclient follows pagination links automatically.
On master, writes are nonpersistent: the collection lists generated samples, not the spline created by POST. Update and delete demonstrate the API contract without changing later collections. The same sequence on the database-backed branches persists changes and deletes the created record.
bundle exec rake spec
bundle exec rubocop
# Run both:
bundle exec rakeTests generate HTML coverage in coverage/index.html and LCOV coverage in coverage/lcov.info. CI tests Ruby 3.3, 3.4, and 4.0 across Grape 2, 3, and 4, including Rack 2 and 3 compatibility, and uploads combined coverage to Coveralls.
The committed lockfile provides the default development bundle. CI resolves each compatibility combination independently using GRAPE_VERSION and RACK_VERSION. To try another combination locally, save the lockfile first, remove it, and run bundle install with those environment variables; restore the default lockfile afterward.
Each active example branch runs its own branch-specific test and lint workflows. This branch requires no database service.
The three active branches share the HAL API, with different model and persistence examples:
| Branch | Model | Database |
|---|---|---|
| master | ActiveModel | None; generated splines, nonpersistent writes |
| with-mongoid | Mongoid | MongoDB |
| with-activerecord | ActiveRecord | PostgreSQL |
Copyright (c) 2014-2025 Daniel Doubrovkine
MIT License, see LICENSE for details.