Hungrytable
Ruby client for the OpenTable REST API. Supports restaurant search, availability lookup, reservations, and booking management.
Features
- Fetch restaurant details
- Search available reservation times
- Lock time slots before booking
- Create and cancel reservations
- Check reservation status
- Requires Ruby 3.0+
- No
method_missing- all methods explicitly defined - Error classes for different failure types
Installation
Add this line to your application's Gemfile:
gem 'hungrytable'
And then execute:
$ bundle install
Or install it yourself as:
$ gem install hungrytable
Configuration
Environment Variables
Set the following environment variables (recommended for production):
export OT_PARTNER_ID=<YOUR OPENTABLE PARTNER ID>
export OT_OAUTH_KEY=<YOUR OPENTABLE OAUTH KEY>
export OT_OAUTH_SECRET=<YOUR OPENTABLE OAUTH SECRET KEY>
Programmatic Configuration
Alternatively, configure programmatically in your code:
Hungrytable.configure do |config|
config.partner_id = 'your_partner_id'
config.oauth_key = 'your_oauth_key'
config.oauth_secret = 'your_oauth_secret'
end
Usage
1. Get Restaurant Details
restaurant = Hungrytable::Restaurant.new(82591)
if restaurant.valid?
puts restaurant.restaurant_name
puts restaurant.address
puts restaurant.phone
puts restaurant.primary_food_type
puts restaurant.price_range
else
puts "Error: #{restaurant.error_message}"
end
Available restaurant attributes:
restaurant_name,restaurant_IDaddress,city,state,postal_codephone,urllatitude,longitudeneighborhood_name,metro_nameprimary_food_type,price_rangerestaurant_descriptionparking,parking_detailsimage_link
2. Search for Availability
restaurant = Hungrytable::Restaurant.new(82591)
# Search for a table for 4 people, 5 days from now at 7pm
search_time = 5.days.from_now.change(hour: 19, min: 0)
search = Hungrytable::RestaurantSearch.new(
restaurant,
date_time: search_time,
party_size: 4
)
if search.valid?
puts "Exact time: #{search.exact_time}" if search.exact_time
puts "Early time: #{search.early_time}" if search.early_time
puts "Later time: #{search.later_time}" if search.later_time
puts "Best time: #{search.ideal_time}"
else
puts "No availability: #{search.error_message}"
end
3. Lock a Time Slot
slotlock = Hungrytable::RestaurantSlotlock.new(search)
if slotlock.successful?
puts "Slot locked! ID: #{slotlock.slotlock_id}"
else
puts "Failed to lock slot: #{slotlock.errors}"
end
4. Make a Reservation
reservation = Hungrytable::ReservationMake.new(
slotlock,
email_address: '[email protected]',
firstname: 'John',
lastname: 'Doe',
phone: '5551234567',
specialinstructions: 'Window seat please'
)
if reservation.successful?
puts "Reservation confirmed! Number: #{reservation.confirmation_number}"
else
puts "Reservation failed: #{reservation.error_message}"
end
5. Check Reservation Status
status = Hungrytable::ReservationStatus.new(
restaurant_id: 82591,
confirmation_number: 'ABC123XYZ'
)
if status.successful?
puts "Status: #{status.status}"
details = status.reservation_details
puts "Restaurant: #{details[:restaurant_name]}"
puts "Date/Time: #{details[:date_time]}"
puts "Party Size: #{details[:party_size]}"
end
6. Cancel a Reservation
cancel = Hungrytable::ReservationCancel.new(
email_address: '[email protected]',
confirmation_number: 'ABC123XYZ',
restaurant_id: 82591
)
if cancel.successful?
puts "Reservation cancelled successfully"
else
puts "Cancellation failed: #{cancel.error_message}"
end
Complete Example: Full Reservation Flow
require 'hungrytable'
# Configure
Hungrytable.configure do |config|
config.partner_id = ENV['OT_PARTNER_ID']
config.oauth_key = ENV['OT_OAUTH_KEY']
config.oauth_secret = ENV['OT_OAUTH_SECRET']
end
# 1. Get restaurant details
restaurant = Hungrytable::Restaurant.new(82591)
raise "Restaurant not found" unless restaurant.valid?
puts "Booking at: #{restaurant.restaurant_name}"
# 2. Search for availability
search_time = 3.days.from_now.change(hour: 19, min: 0)
search = Hungrytable::RestaurantSearch.new(
restaurant,
date_time: search_time,
party_size: 2
)
raise "No availability" unless search.valid?
puts "Found time slot: #{search.ideal_time}"
# 3. Lock the slot
slotlock = Hungrytable::RestaurantSlotlock.new(search)
raise "Could not lock slot: #{slotlock.errors}" unless slotlock.successful?
# 4. Make the reservation
reservation = Hungrytable::ReservationMake.new(
slotlock,
email_address: '[email protected]',
firstname: 'Jane',
lastname: 'Smith',
phone: '5551234567'
)
if reservation.successful?
puts "Success! Confirmation: #{reservation.confirmation_number}"
else
puts "Failed: #{reservation.error_message}"
end
Error Handling
Available error classes:
begin
restaurant = Hungrytable::Restaurant.new(invalid_id)
rescue Hungrytable::ConfigurationError => e
puts "Configuration error: #{e.message}"
rescue Hungrytable::HTTPError => e
puts "HTTP error: #{e.message}"
rescue Hungrytable::APIError => e
puts "API error #{e.error_code}: #{e.error_message}"
rescue Hungrytable::MissingRequiredFieldError => e
puts "Missing required field: #{e.message}"
end
Error hierarchy:
-
Hungrytable::Error(base class)ConfigurationError- Missing or invalid configuration-
HTTPError- HTTP-level errorsNotFoundError- 404 errorsUnauthorizedError- 401 authentication errorsServerError- 5xx server errors
APIError- OpenTable API errors-
ValidationError- Input validation errorsMissingRequiredFieldError- Missing required parameters
Development
After checking out the repo, run bundle install to install dependencies. Then, run rake test to run the tests.
Running Tests
bundle exec rake test
Running RuboCop
bundle exec rubocop
Auto-fixing RuboCop Issues
bundle exec rubocop -A
Requirements
- Ruby >= 3.0.0
- OpenTable Partner API credentials
Dependencies
Runtime:
activesupport(>= 6.0)http(~> 5.0)oauth(~> 1.1)
Development:
minitest(~> 5.20) - Testing frameworkwebmock(~> 3.20) - HTTP mocking for testsrubocop(~> 1.60) - Code quality and stylemocha(~> 2.1) - Mocking and stubbing
Contributing
- Fork it (https://github.com/dchapman1988/hungrytable/fork)
- Create your feature branch (
git checkout -b my-new-feature) - Commit your changes (
git commit -am 'Add some feature') - Push to the branch (
git push origin my-new-feature) - Create a new Pull Request
Please ensure:
- All tests pass (
bundle exec rake test) - RuboCop is clean (
bundle exec rubocop) - New features have tests
- Code follows existing style
License
The gem is available as open source under the terms of the MIT License.
Maintainers
Active:
- David Chapman (@dchapman1988)
Inactive:
- Nicholas Fine (@yrgoldteeth)
- Ryan T. Hosford (@rthbound)
Changelog
See RELEASE_NOTES.md for version history.