This gem provides all mechanisms needed to interact with the Dropbox HelloSign API.
Add this line to your application's Gemfile:
gem 'hello_sign-client'
And then execute:
$ bundle install
Or install it yourself as:
$ gem install hello_sign-client
All routes will be defined in the data/routes.json
file. These are then available via the FileStore within the client.
>> routes = HelloSign::Client.routes
=> #<RestlessRouter::Routes:0x00007fa23c176048 @routes=[#<RestlessRouter::Route:0x00007fa23c175da0 @name="signature-requests", @path="{version}/signature_request/list", @options={:templated=>true}>, #<RestlessRouter::Route:0x00007fa23c175b70 @name="signature-request", @path="{version}/signature_request/{id}", @options={:templated=>true}>]>
>> route = routes.route_for('signature-request')
=> #<RestlessRouter::Route:0x00007fa23c175b70 @name="signature-request", @path="{version}/signature_request/{id}", @options={:templated=>true}>
>> route.url_for(version: 'v3', id: '122323')
=> "v3/signature_request/122323"
All routes can then be inspected with bundle exec rake routes
You can configure the client for your own needs:
HelloSign::Client.configure do |c|
c.api_key = '1234'
c.logger = HelloSign::Logger.new(File.expand_path('../log/rake.log', __FILE__))
c.request_logger = HelloSign::Logger.new(File.expand_path('../log/requests.log', __FILE__))
end
Once you've configured the client you can establish a connection.
>> connection = HelloSign::Client.connection
=> #<Faraday::Connection:0x00007fa23c1f48f8>
>> connection.get('/')
I, [2022-08-23T13:55:46.463490 #79881] INFO -- request: GET https://api.hellosign.com/
I, [2022-08-23T13:55:46.463536 #79881] INFO -- request: Authorization: "Basic {redacted}"
User-Agent: "HelloSign Ruby Gem 0.1.0"
Accept: "application/json"
Content-Type: "application/json"
I, [2022-08-23T13:55:46.645627 #79881] INFO -- response: Status 302
I, [2022-08-23T13:55:46.645696 #79881] INFO -- response: date: "Tue, 23 Aug 2022 17:55:46 GMT"
content-type: "text/html; charset=utf-8"
content-length: "100"
connection: "keep-alive"
set-cookie: "AWSALB=8HKIIef1KaSXpLejqP57+izK5jD6x1l2jt0+FZT3ccZECSF29ai7xhAJhOGNWY6QyAmZdLL5M4cmGYWW7pKuJO33tOBxOs0cflZvZi4L9VZ/l5TSlcEGJY9LOBU8; Expires=Tue, 30 Aug 2022 17:55:46 GMT; Path=/, AWSALBCORS=8HKIIef1KaSXpLejqP57+izK5jD6x1l2jt0+FZT3ccZECSF29ai7xhAJhOGNWY6QyAmZdLL5M4cmGYWW7pKuJO33tOBxOs0cflZvZi4L9VZ/l5TSlcEGJY9LOBU8; Expires=Tue, 30 Aug 2022 17:55:46 GMT; Path=/; SameSite=None; Secure"
server: "Apache"
strict-transport-security: "max-age=31536000"
vary: "Origin"
location: "https://app.hellosign.com/api"
p3p: "CP=\"NOP3PPOLICY\""
access-control-allow-origin: "*"
access-control-allow-headers: "Authorization, Origin, X-Requested-With, Content-Type, Accept, Request-URL, Referrer-Policy, Referer, Sec-CH-UA, Sec-CH-UA-Mobile, Sec-CH-UA-Platform, Sec-Fetch-Site, User-Agent, X-User-Agent"
access-control-allow-methods: "GET, POST, OPTIONS, PUT, DELETE"
=> #<Faraday::Response:0x00007fa23c2b6110>
Note: Response cut for brevity
Once you've established a connection, then you can begin making requests:
>> request = HelloSign::Requests::SignatureRequests.list
I, [2022-08-23T14:09:51.678102 #79881] INFO -- request: GET https://api.hellosign.com/v3/signature_request/list
I, [2022-08-23T14:09:51.678155 #79881] INFO -- request: Authorization: "Basic {redacted}"
User-Agent: "HelloSign Ruby Gem 0.1.0"
Accept: "application/json"
Content-Type: "application/json"
I, [2022-08-23T14:09:52.472150 #79881] INFO -- response: Status 200
I, [2022-08-23T14:09:52.472227 #79881] INFO -- response: date: "Tue, 23 Aug 2022 18:09:52 GMT"
content-type: "application/json"
content-length: "1466"
connection: "keep-alive"
set-cookie: "AWSALB=a3Xjq7HIpdpDcunX82a8a206v6od7cseDAGHeDY084+EPY8NkAC8svjn/1QJxtY6WuFEa2UC9dV4M54LmmTjCJ4PHwJpq/9ivM1f7zXkKD37rks8gLbhg6G9ZhgW; Expires=Tue, 30 Aug 2022 18:09:52 GMT; Path=/, AWSALBCORS=a3Xjq7HIpdpDcunX82a8a206v6od7cseDAGHeDY084+EPY8NkAC8svjn/1QJxtY6WuFEa2UC9dV4M54LmmTjCJ4PHwJpq/9ivM1f7zXkKD37rks8gLbhg6G9ZhgW; Expires=Tue, 30 Aug 2022 18:09:52 GMT; Path=/; SameSite=None; Secure"
server: "Apache"
strict-transport-security: "max-age=31536000"
vary: "Origin,Accept-Encoding"
x-ratelimit-limit: "100"
x-ratelimit-limit-remaining: "99"
x-ratelimit-reset: "1661278192"
access-control-allow-origin: "*"
access-control-allow-headers: "Authorization, Origin, X-Requested-With, Content-Type, Accept, Request-URL, Referrer-Policy, Referer, Sec-CH-UA, Sec-CH-UA-Mobile, Sec-CH-UA-Platform, Sec-Fetch-Site, User-Agent, X-User-Agent"
access-control-allow-methods: "GET, POST, OPTIONS, PUT, DELETE"
user-agent: "HelloSign API"
p3p: "CP=\"NOP3PPOLICY\""
=> #<Faraday::Response:0x00007fa23a82c830>
>>
Note: Response cut for brevity
The requests will all return a delegated response object (Faraday
as
the default adapter)
>> response = HelloSign::Requests::SignatureRequests.retrieve('26d7fd1303666b4697a9b1a67a948aa8a81a7686')
=> #<Faraday::Response:0x00007fa23c0ed2e8
>> response.status
=> 200
>> response.headers
=> {"date"=>"Tue, 23 Aug 2022 18:18:47 GMT", "content-type"=>"application/json", "content-length"=>"705", "connection"=>"keep-alive", "set-cookie"=>"AWSALB=jTko1+Ygl3RjEWOnpy08NExWkQIq66sUDJtuOznTpqswZNDAnP1tfWBFzKFON4iw0fVeVitCe0vOTBTY+kwzJ3sNOMAnPtDuBCAt+6s8QiWf5qPaldRcxo0E4Svq; Expires=Tue, 30 Aug 2022 18:18:47 GMT; Path=/, AWSALBCORS=jTko1+Ygl3RjEWOnpy08NExWkQIq66sUDJtuOznTpqswZNDAnP1tfWBFzKFON4iw0fVeVitCe0vOTBTY+kwzJ3sNOMAnPtDuBCAt+6s8QiWf5qPaldRcxo0E4Svq; Expires=Tue, 30 Aug 2022 18:18:47 GMT; Path=/; SameSite=None; Secure", "server"=>"Apache", "strict-transport-security"=>"max-age=31536000", "vary"=>"Origin,Accept-Encoding", "x-ratelimit-limit"=>"100", "x-ratelimit-limit-remaining"=>"99", "x-ratelimit-reset"=>"1661278727", "access-control-allow-origin"=>"*", "access-control-allow-headers"=>"Authorization, Origin, X-Requested-With, Content-Type, Accept, Request-URL, Referrer-Policy, Referer, Sec-CH-UA, Sec-CH-UA-Mobile, Sec-CH-UA-Platform, Sec-Fetch-Site, User-Agent, X-User-Agent", "access-control-allow-methods"=>"GET, POST, OPTIONS, PUT, DELETE", "user-agent"=>"HelloSign API", "p3p"=>"CP=\"NOP3PPOLICY\""}
>> response.body
=> {"signature_request"=>{"signature_request_id"=>"26d7fd1303666b4697a9b1a67a948aa8a81a7686", "test_mode"=>true, "title"=>"NDA with Acme Co.", "original_title"=>"The NDA we talked about", "subject"=>"The NDA we talked about", "message"=>"Please sign this NDA and then we can discuss more. Let me know if you\nhave any questions.", "metadata"=>{"custom_id"=>1234, "custom_text"=>"NDA #9"}, "created_at"=>1661256889, "is_complete"=>false, "is_declined"=>false, "has_error"=>false, "custom_fields"=>[], "response_data"=>[], "signing_url"=>"https://app.hellosign.com/sign/26d7fd1303666b4697a9b1a67a948aa8a81a7686", "signing_redirect_url"=>nil, "final_copy_uri"=>"/v3/signature_request/final_copy/26d7fd1303666b4697a9b1a67a948aa8a81a7686", "files_url"=>"https://api.hellosign.com/v3/signature_request/files/26d7fd1303666b4697a9b1a67a948aa8a81a7686", "details_url"=>"https://app.hellosign.com/home/manage?guid=26d7fd1303666b4697a9b1a67a948aa8a81a7686", "requester_email_address"=>"[email protected]", "signatures"=>[{"signature_id"=>"df23f5a693ec300d2c235952c54d05e9", "has_pin"=>false, "has_sms_auth"=>false, "has_sms_delivery"=>false, "sms_phone_number"=>nil, "signer_email_address"=>"[email protected]", "signer_name"=>"Jack", "signer_role"=>nil, "order"=>0, "status_code"=>"awaiting_signature", "signed_at"=>nil, "last_viewed_at"=>nil, "last_reminded_at"=>nil, "error"=>nil}, {"signature_id"=>"8aef47c83e6d167763706f46f1e92817", "has_pin"=>false, "has_sms_auth"=>false, "has_sms_delivery"=>false, "sms_phone_number"=>nil, "signer_email_address"=>"[email protected]", "signer_name"=>"Jill", "signer_role"=>nil, "order"=>1, "status_code"=>"awaiting_signature", "signed_at"=>nil, "last_viewed_at"=>nil, "last_reminded_at"=>nil, "error"=>nil}], "cc_email_addresses"=>["[email protected]", "[email protected]"], "template_ids"=>nil}}
The response object will have helper methods for you to typecast the
body. For now it will handle application/json
.
The response object will also provide you methods to handle various responses however you would like to target:
>> response.on(:success) { puts "OK!" }
OK!
=> nil
>> response.on(200) { puts "OK!" }
OK!
=> nil
>> response.on(201) { puts "OK!" }
=> nil
>> response.on(200, 201) { puts "OK!" }
OK!
=> nil
These can be targed by HTTP status codes or keywords that encompass the full ranges.
:success
(200-299):redirect
(300-399):error
(400-499):server_error
(500-599)
Once you've made requests, then you can begin composing and using the domain models.
>> records = HelloSign::Models::SignatureRequests.list
=> #<HelloSign::Models::SignatureRequests:0x00007fa23b00cf78>
>> records.count
=> 5
>> records.first
=> #<HelloSign::Models::SignatureRequest:0x00007fa25d8e55b0>
>> record = HelloSign::Models::SignatureRequest.retrieve('26d7fd1303666b4697a9b1a67a948aa8a81a7686')
=> #<HelloSign::Models::SignatureRequest:0x00007fa25d91d9b0
>> record.id
=> "26d7fd1303666b4697a9b1a67a948aa8a81a7686"
>> record.title
=> "NDA with Acme Co."
>> record.subject
=> "The NDA we talked about"
>> record.message
=> "Please sign this NDA and then we can discuss more. Let me know if you\nhave any questions."
>> record.complete?
=> false
>> record.declined?
=> false
>> record.error?
=> false
The library has a delegated logger that you can use as you see fit. The client itself will use logging for:
- Request (Raw HTTP requests and responses)
- Application
- Cache
>> logger = HelloSign::Logger.new(File.expand_path('../log/my_log.log', __FILE__))
=> #<Logger:0x00007fa25a97ece0>
From there you can use all standard library logging.
The library has several errors and Exceptions that may be encountered throughout.
The library should always trap underlying exceptions and bubble them up with our named errors and full stack trace.
For instance, we can create bang!
methods that will raise exceptions
when trying to retrieve records:
>> raise HelloSign::Errors::RecordNotFoundError.new('Record Not Found')
Traceback (most recent call last):
2: from bin/console:15:in `<main>'
1: from (irb):21
HelloSign::Errors::RecordNotFoundError (Record Not Found)
This way the consumer of this library will only ever deal with the subset of exceptions defined in this library.
After checking out the repo, run bin/setup
to install dependencies. Then, run rake spec
to run the tests. You can also run bin/console
for an interactive prompt that will allow you to experiment.
To install this gem onto your local machine, run bundle exec rake install
. To release a new version, update the version number in version.rb
, and then run bundle exec rake release
, which will create a git tag for the version, push git commits and the created tag, and push the .gem
file to rubygems.org.
There are a handful of other methods to assist in development:
bin/rake routes
will show all available route definitionsbin/rake signature_requests
will list out a subset of signature requests
All code is document with Yard. You can use this with:
yard
: This will generate the documentationyard server
: This will start the yard server and enable documentation in the browser
Bug reports and pull requests are welcome on GitHub at https://github.com/ElectronicDataPaymentSystems/hello_sign-client.
The gem is available as open source under the terms of the MIT License.