Wrest
A fluent, easy-to-use, object oriented Ruby HTTP/REST client library with support RFC2616 HTTP caching and async calls that runs on CRuby and JRuby.
Install / Use
/learn @gojek/WrestREADME
Wrest 4.0.0
<p align="center"><img src="docs/wrest-logo-320x320.png" width="320"></p> <p align="center"> <a href="https://badge.fury.io/rb/wrest"> <img src="https://badge.fury.io/rb/wrest.svg" alt="Gem Version" height="18"> </a> <a href="https://github.com/kaiwren/wrest/actions/workflows/ruby.yml"> <img src="https://github.com/kaiwren/wrest/actions/workflows/ruby.yml/badge.svg" alt="Ruby" style="max-width: 100%;"> </a> <a href="https://github.com/kaiwren/wrest/actions/workflows/jruby.yml"> <img src="https://github.com/kaiwren/wrest/actions/workflows/jruby.yml/badge.svg" alt="JRuby" style="max-width: 100%;"> </a> <a href="https://codeclimate.com/github/kaiwren/wrest/maintainability"> <img src="https://api.codeclimate.com/v1/badges/dc0366a60000561951ab/maintainability" /> </a> </p>Wrest is a ruby REST/HTTP client library. It is currently in use at 10x🦄 scale across all Ruby/JRuby systems at Gojek.
$ gem install wrest
$ wrest # interactive shell
Ruby 3.1.2, 2022-04-12, arm64-darwin21
Loading Wrest 4.0.0
>> 'https://api2.binance.com/api/v3/ticker/24hr'.to_uri.get.deserialize
In your project Gemfile:
gem 'wrest', '~> 4.0.0'
- Quick tool to wrangle APIs to powerful library to build complex production grade systems, Wrest does it all
- Clean, object-oriented API with URLs as first class entities
- Supports RFC 2616 based caching
- Async http calls using Threads (truly useful only on JRuby due to GIL limitations on CRuby) or EventMachine
- Is spec driven, strongly favours immutable objects and avoids class methods and setters making it better suited for use as a library, especially in multi-threaded environments
- Provides convenient HTTP wrappers, redirect handling, serialisation, deserialisation and xpath based lookup
Examples
For Facebook, Twitter, Delicious, GitHub and other API examples, see http://github.com/kaiwren/wrest/tree/master/examples
Basic Http Calls
GET
-
Basic API calls
# Works with json and xml out of the box to give you a hash # See lib/wrest/components/translators to add other formats 'https://api.github.com/repos/rails/rails/issues'.to_uri.get.deserialize -
Timeout support
'https://api.github.com/repos/c42/wrest/issues'.to_uri(timeout: 5).get.body -
Redirect support
'http://google.com'.to_uri(follow_redirects: false).get 'http://google.com'.to_uri(follow_redirects_limit: 1).get:follow_redirects_limit defaults to 5 if not specified.
-
Deserialise with XPath filtering
'http://twitter.com/statuses/public_timeline.xml'.to_uri.get.deserialise( xpath: '//user/name/text()' ) -
More complex request with parameters and a custom deserialiser
'api.openweathermap.org/data/2.5/weather'.to_uri.get( lat: 35, lon: 139 ).deserialise_using( Wrest::Components::Translators::Xml ) -
Basic HTTP auth and URI extensions using Wrest::Uri#[]
base_uri = 'https://api.del.icio.us/v1'.to_uri(username: 'kaiwren', password: 'fupupp1es') bookmarks = base_uri['/posts/get'].get.deserialise -
Detailed debugging and logging (NOT FOR USE IN PRODUCTION! SEE API DOCS!)
'https://api.github.com/repos/c42/wrest/issues'.to_uri(detailed_http_logging: $stdout).get.deserialize
POST
-
Regular, vanilla Post with a body and headers
'http://my.api.com'.to_uri.post('YAML encoded body', 'Content-Type' => 'text/x-yaml') -
Form encoded post
'https://api.del.icio.us/v1/posts/add'.to_uri( username: 'kaiwren', password: 'fupupp1es' ).post_form( url: 'http://blog.sidu.in/search/label/ruby', description: 'The Ruby related posts on my blog!', extended: "All posts tagged with 'ruby'", tags: 'ruby hacking' ) -
Multipart posts
'http://imgur.com/api/upload.xml'.to_uri.post_multipart( image: UploadIO.new(File.open(file_path), "image/png", file_path), key: imgur_key ).deserialise
Note: To enable Multipart support, you'll have to explicitly require 'wrest/multipart', which depends on the multipart-post gem.
DELETE
To delete a resource:
'https://api.del.icio.us/v1/posts/delete'.to_uri(
username: 'kaiwren',
password: 'fupupp1es'
).delete(
url: 'http://c2.com'
)
Caching
Wrest supports caching with the following pluggable back-ends:
- Hash
- Memcached
- Redis
Hash
Use the following method to enable caching for all requests, and set Hash as the default cache store. Note: Hash should NEVER be used in a production environment. It is unbounded and will keep increasing in size.
Wrest::Caching.default_to_hash!
c42 = 'http://c42.in'.to_uri.get
To use Hash as a cache store in an explicit request (without setting hash as default), use the following API:
r1 = "http://c42.in".to_uri.using_hash.get
Memcached
A Memcached based caching back-end is available in Wrest. You can get instructions on how to install Memcached on your system here. The Dalli gem is used by Wrest to interface with Memcached. Install dalli using 'gem install dalli'.
Use the following method to enable caching for all requests, and set Memcached as the default back-end.
Wrest::Caching.default_to_memcached!
To use Memcached as a cache store in an explicit request (without setting memcached as default), use the following API:
Wrest::Caching.enable_memcached
r2 = "http://c42.in".to_uri.using_memcached.get
Redis
Wrest also supports a Redis based caching back-end. Follow the guide here to install Redis in your system.
It uses redis-rd to interface with Redis. Install redis-rb using gem install redis.
Use the following method to enable caching for all requests, and set Redis as the default back-end.
Wrest::Caching.default_to_redis!
To use Redis as a cache store in an explicit request (without setting redis as default), use the following API:
Wrest::Caching.enable_redis
r3 = "http://c42.in".to_uri.using_redis.get
A detailed writeup regarding caching as defined by RFC 2616, and how Wrest implements caching is at Wrest Caching Doc
You can create your own back-ends for Wrest caching by implementing the interface implemented in https://github.com/c42/wrest/blob/master/lib/wrest/caching/redis.rb
To explicitly disable caching for specific requests:
"http://c42.in".to_uri.disable_cache.get
Callbacks
Uri level callbacks
You can define a set of callbacks that are invoked based on the http codes of the responses to any requests on a given uri.
"http://google.com".to_uri(callback: {
200 => lambda {|response| Wrest.logger.info "Ok." },
400..499 => lambda {|response| Wrest.logger.error "Invalid. #{response.body}"},
300..302 => lambda {|response| Wrest.logger.debug "Redirected. #{response.message}" }
}).get
Per request callbacks
You can also define callbacks that are invoked based on the http code of the response to a particular request.
"http://google.com".to_uri.get do |callback|
callback.on_ok do |response|
Wrest.logger.info "Ok."
end
callback.on(202) do |response|
Wrest.logger.info "Accepted."
end
callback.on(200..206) do |response|
Wrest.logger.info "Successful."
end
end
Please note that Wrest is a synchronous library. All requests are blocking, and will not return till the request is completed and appropriate callbacks executed.
Asynchronous requests
Asynchronous requests are non-blocking. They do not return a response and the request is executed on a separate thread. The only way to access the response while using asynchronous request is through callbacks.
Asynchronous requests support pluggable backends. The default backend used for asynchronous requests is ruby threads, which is only reliable when using JRuby.
"http://c42.in".to_uri.get_async do |callback|
callback.on_ok do |response|
Wrest.logger.info "Ok."
end
end
# Wait until the background threads finish execution before letting the program end.
Wrest::AsyncRequest.wait_for_thread_pool!
You can change the default to eventmachine or to threads.
Wrest::AsyncRequest.default_to_em!
or
Wrest::AsyncRequest.default_to_threads!
You can also override the default on Uri objects.
"http://c42.in".to_uri.using_em.get_async do |callback|
callback.on_ok do |response|
Wrest.logger.info "Ok."
end
end
You can decide which AsyncBackend to use at runtime through to to_uri's options hash.
"http://c42.in".to_uri(asynchronous_backend: ThreadBackend.new(number_of_threads)).get_async do |callback|
callback.on_ok do |response|
Wrest.logger.info "Ok."
end
end
Other useful stuff
Hash container with ActiveResource-like semantics
Allows any class to hold an attributes hash, somewhat like ActiveResource. It also supports several extensions to this base fuctionality such as support f
Related Skills
openhue
347.2kControl Philips Hue lights and scenes via the OpenHue CLI.
sag
347.2kElevenLabs text-to-speech with mac-style say UX.
weather
347.2kGet current weather and forecasts via wttr.in or Open-Meteo
Better-Prompt
Publishable Prompt Engineering skill package that compiles a user request into a ready-to-use high-quality Prompt, with support for diagnosis, module injection, debugging, and evaluation.
