Active Call - Zoho Sign
Zoho Sign exposes the Zoho Sign API endpoints through Active Call service objects.
- Installation
- Configuration
- Usage
- Using call
- Using call!
- When to use call or call!
- Using lists
- Service Objects
- Development
- Contributing
- License
Installation
Install the gem and add to the application's Gemfile by executing:
bundle add active_call-zoho_signIf bundler is not being used to manage dependencies, install the gem by executing:
gem install active_call-zoho_signConfiguration
Create a new Self Client client type from the Zoho Developer Console to retrieve your Client ID and Client Secret.
Choose what you need from the list of Zoho Scopes like ZohoSign.documents.ALL to generate your Grant Token.
Get your Refresh Token by calling ZohoSign::GrantToken::GetService.call(grant_token: '', client_id: '', client_secret: '').refresh_token
Configure your API credentials.
In a Rails application, the standard practice is to place this code in a file named zoho_sign.rb within the config/initializers directory.
require 'active_call-zoho_sign'
ZohoSign::BaseService.configure do |config|
config.client_id = ''
config.client_secret = ''
config.refresh_token = ''
# Optional configuration.
config.cache = Rails.cache # Default: ActiveSupport::Cache::MemoryStore.new
config.logger = Rails.logger # Default: Logger.new($stdout)
config.logger_level = :debug # Default: :info
config.log_headers = true # Default: false
config.log_bodies = true # Default: false
endWhile testing, you can set your temporary development OAuth access token in the ZOHO_SIGN_ACCESS_TOKEN environment variable. In your production environment,config.refresh_token will be used.
Usage
Each service object returned will undergo validation before the call method is invoked to access API endpoints.
After successful validation.
service.success? # => true
service.errors # => #<ActiveModel::Errors []>After failed validation.
service.success? # => false
service.errors # => #<ActiveModel::Errors [#<ActiveModel::Error attribute=name, type=blank, options={}>]>
service.errors.full_messages # => ["Name can't be blank"]After a successful call invocation, the response attribute will contain a Faraday::Response object.
service.success? # => true
service.response # => #<Faraday::Response ...>
service.response.success? # => true
service.response.status # => 200
service.response.body # => {"code"=>0, "message"=>"Document has been retrieved", "status"=>"success", "requests"=>{...}}At this point you will also have a facade object which will hold all the attributes for the specific resource.
service.facade # => #<ZohoSign::Document::Facade @request_status="inprogress" ...>
service.facade.request_status # => 'inprogress'For convenience, facade attributes can be accessed directly on the service object.
service.request_status # => 'inprogress'After a failed call invocation, the response attribute will still contain a Faraday::Response object.
service.success? # => false
service.errors # => #<ActiveModel::Errors [#<ActiveModel::Error attribute=base, type=Not found, options={}>]>
service.errors.full_messages # => ["No match found"]
service.response # => #<Faraday::Response ...>
service.response.success? # => false
service.response.status # => 400
service.response.body # => {"code"=>9004, "message"=>"No match found", "status"=>"failure"}Each service object returned will undergo validation before the call! method is invoked to access API endpoints.
After successful validation.
service.success? # => trueAfter failed validation, a ZohoSign::ValidationError exception will be raised with an errors attribute which
will contain an ActiveModel::Errors object.
rescue ZohoSign::ValidationError => exception
exception.message # => ''
exception.errors # => #<ActiveModel::Errors [#<ActiveModel::Error attribute=name, type=blank, options={}>]>
exception.errors.full_messages # => ["Name can't be blank"]After a successful call! invocation, the response attribute will contain a Faraday::Response object.
service.success? # => true
service.response # => #<Faraday::Response ...>
service.response.success? # => true
service.response.status # => 200
service.response.body # => {"code"=>0, "message"=>"Document has been retrieved", "status"=>"success", "requests"=>{...}}At this point you will also have a facade object which will hold all the attributes for the specific resource.
service.facade # => #<ZohoSign::Document::Facade @request_status="inprogress" ...>
service.facade.request_status # => 'inprogress'For convenience, facade attributes can be accessed directly on the service object.
service.request_status # => 'inprogress'After a failed call! invocation, a ZohoSign::RequestError will be raised with a response attribute which will contain a Faraday::Response object.
rescue ZohoSign::RequestError => exception
exception.message # => ''
exception.errors # => #<ActiveModel::Errors [#<ActiveModel::Error attribute=base, type=Not found, options={}>]>
exception.errors.full_messages # => ["No match found"]
exception.response # => #<Faraday::Response ...>
exception.response.status # => 400
exception.response.body # => {"code"=>9004, "message"=>"No match found", "status"=>"failure"}An example of where to use call would be in a controller doing an inline synchronous request.
class SomeController < ApplicationController
def update
@document = ZohoSign::Document::UpdateService.call(**params)
if @document.success?
redirect_to [@document], notice: 'Success', status: :see_other
else
flash.now[:alert] = @document.errors.full_messages.to_sentence
render :edit, status: :unprocessable_entity
end
end
endAn example of where to use call! would be in a job doing an asynchronous request.
You can use the exceptions to determine which retry strategy to use and which to discard.
class SomeJob < ApplicationJob
discard_on ZohoSign::NotFoundError
retry_on ZohoSign::RequestTimeoutError, wait: 5.minutes, attempts: :unlimited
retry_on ZohoSign::TooManyRequestsError, wait: :polynomially_longer, attempts: 10
def perform
ZohoSign::Document::UpdateService.call!(**params)
end
endUsing lists
If you don't provide the limit argument, multiple API requests will be made untill all records have been returned. You could be rate limited, so use wisely.
Note that the offset argument starts at 1 for the first item.
Service Objects
Documents
List documents
# https://www.zoho.com/sign/api/document-managment/get-document-list.html
ZohoSign::Document::ListService.call(offset: 1, limit: 10).each do |facade|
facade.description
endSort by column.
ZohoSign::Document::ListService.call(sort_column: 'recipient_email', sort_order: 'ASC').map { _1 }Filter by column.
ZohoSign::Document::ListService.call(search_columns: { recipient_email: 'eric.cartman@example.com' }).map { _1 }Columns to sort and filter by are request_name, folder_name, owner_full_name, recipient_email, form_name and created_time.
Get a document
# https://www.zoho.com/sign/api/document-managment/get-details-of-a-particular-document.html
service = ZohoSign::Document::GetService.call(id: '')
service.request_name
service.request_id
service.request_status
service.owner_email
service.owner_first_name
service.owner_last_name
service.attachments
service.sign_percentage
...Create a document
# https://www.zoho.com/sign/api/document-managment/create-document.html
ZohoSign::Document::CreateService.call(
file: '/path/to/file.pdf', # or File.open('/path/to/file.pdf')
file_name: 'file.pdf',
file_content_type: 'application/pdf',
data: {
requests: {
request_name: 'Name',
is_sequential: false,
actions: [{
action_type: 'SIGN',
recipient_email: 'eric.cartman@example.com',
recipient_name: 'Eric Cartman',
verify_recipient: true,
verification_type: 'EMAIL'
}]
}
}
)Update a document
# https://www.zoho.com/sign/api/document-managment/update-document.html
ZohoSign::Document::UpdateService.call(
id: '',
data: {
requests: {
request_name: 'Name Updated',
actions: [{
action_id: '',
action_type: 'SIGN',
recipient_email: 'stan.marsh@example.com',
recipient_name: 'Stan Marsh'
}]
}
}
)Delete a document
# https://www.zoho.com/sign/api/document-managment/delete-document.html
ZohoSign::Document::DeleteService.call(id: '')Sign a document
A unique signing URL will be generated, which will be valid for two minutes. If the signing page is not open by then, a new link needs to be generated and it is a one-time usable URL.
# https://www.zoho.com/sign/api/embedded-signing.html
service = ZohoSign::Document::Action::EmbedToken::GetService.call(request_id: '', action_id: '', host: '')
service.sign_urlFolders
TODO: ...
Field Types
TODO: ...
Request Types
TODO: ...
Templates
List templates
# https://www.zoho.com/sign/api/template-managment/get-template-list.html
ZohoSign::Template::ListService.call(offset: 1, limit: 10).each do |facade|
facade.description
endSort by column.
ZohoSign::Template::ListService.call(sort_column: 'template_name', sort_order: 'ASC').map { _1 }Filter by column.
ZohoSign::Template::ListService.call(search_columns: { template_name: 'Eric Template' }).map { _1 }Columns to sort and filter by are template_name, owner_first_name and modified_time.
Get a template
# https://www.zoho.com/sign/api/template-managment/get-template-details.html
service = ZohoSign::Template::GetService.call(id: '')
service.description
service.document_fields
service.email_reminders
service.expiration_days
service.folder_name
service.folder_id
service.owner_email
service.template_name
service.request_status
...Create a template
TODO: ...
Update a template
TODO: ...
Delete a template
TODO: ...
Create document from template
The auto filled fields specified in the field_data object should be marked as Prefill by you when creating the document template.
# https://www.zoho.com/sign/api/template-managment/send-documents-using-template.html
ZohoSign::Template::Document::CreateService.call!(
id: '',
is_quicksend: true,
data: {
templates: {
request_name: 'Request Document',
field_data: {
field_text_data: {
'Full name' => 'Eric Cartman',
'Email' => 'eric.cartman@example.com'
},
field_boolean_data: {
'Agreed to terms' => true
},
field_date_data: {
'Inception date' => '31/01/2025'
}
},
actions: [{
action_type: 'SIGN',
recipient_email: 'eric.cartman@example.com',
recipient_name: 'Eric Cartman',
verify_recipient: false,
delivery_mode: 'EMAIL',
action_id: '',
role: 'Client'
}]
}
}
)Development
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.
Contributing
Bug reports and pull requests are welcome on GitHub at https://github.com/kobusjoubert/zoho_sign.
License
The gem is available as open source under the terms of the MIT License.