Ruby client to Gliffy's API
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Failed to load latest commit information.


This is the Ruby client library for interacting with Gliffy. It's main function is for you to integrate Gliffy documents into the workflow of another application.

Getting Started

sudo gem install gliffy


The main entry point to Gliffy is Gliffy::Handle, which provides high-level access to most features available from the API. You should instantiate one of these objects per user session. To create it, you will need to create and populate an instance of the Credentials class. This class is constructed almost entirely from static data about your Gliffy account, so you will probably configure an instance of this globally.

This is then used (along with the API root to Gliffy) to create an instance of Gliffy::Handle. Objects of this class provide access to the features you will need to integrate Gliffy into your app's workflow.


Suppose you have created a group blog application using Rails and wish to give Blog authors the ability to use Gliffy diagrams. In config/initializers/gliffy.rb you might configure values for the Credential object

$gliffy_api_key = 'your-consumer-key-here'
$gliffy_secret = 'your-secret-here'
$gliffy_app_description = 'My Awesome Group Blog',
$gliffy_account_id = 655321
$gliffy_root = ''
$gliffy_edit_root = ''

Then, in your sessions_controller.rb:

require 'gliffy'

def create
  self.current_user = User.authenticate(params[:email],params[:password])
  if logged_in?
    # Whatever you do when they log in successfully
    # Then create the credentials object
    cred =\
    session[:gliffy] =$gliffy_root,$gliffy_edit_root,cred)

Now you can use the gliffy handle in a controller or a view. Perhaps you'd make an action to create a new document and send the user to edit it:

def create
  new_doc = session[:gliffy].document_create(params[:name])
              {:returnURL => url_for(:controller => 'return_from_gliffy'),
               :returnButtonText => 'Back to My Awesome Blog'})) 

It is recommended that you do not expose the Gliffy URLs directly in your views; since each URL can be called one time only and they must be called in the order generated, if you were to have, for example, a page with links to images of your Gliffy diagrams, the browser may not request those links in the order that you need.

Instead, create a route like so:

map.resources :diagrams, :only => [:index,:new,:destroy,:edit,:show]

And implement all Gliffy access in your controller methods

# diagrams_controller.rb
class DiagramsController < ApplicationController

  Mime::Type.register 'image/jpeg', :jpg, [], ["jpeg"] 
  Mime::Type.register 'image/png', :png, [], ["png"] 
  Mime::Type.register 'image/svg+xml', :svg, [], ["svg"] 

  def index
    @diagrams = self.gliffy_handle.folder_documents(APP_CONFIG['gliffy_folder']).sort{|a,b| <=>}

  def show
    size = params[:size] || :L
    respond_to do |format|
      format.jpg { send_data session[:gliffy].document_get(params[:id],:jpeg,size), :type => "image/jpeg", :disposition => 'inline' }
      format.png { send_data session[:gliffy].document_get(params[:id],:png,size), :type => "image/png", :disposition => 'inline' }
      format.svg { send_data session[:gliffy].document_get(params[:id],:svg,size), :type => "image/svg+xml", :filename => params[:id] + ".svg" }
      format.xml { send_data session[:gliffy].document_get(params[:id],:xml,size), :type => "text/xml", :filename => params[:id] + ".xml" }

# index.html.erb
  <% @diagrams.each do |diagram| %>
    <li><img src="<%= diagram_path(diagram.document_id) %>" /></li>
  <% end %>

This way, your application has links to your controller and the requests to Gliffy are constructed as the browser makes requests to your application.

Digging Deeper

If you wish to bypass the high-level API, you can interact with Gliffy directly via the Gliffy::Request class, which allows you to make arbitrary requests against the Gliffy API, but takes care of signing your URLs and all OAuth things that need to be done:

# Create a Credentials object as normal
request ='',credentials)
# The method name maps directly to Gliffy's "action" parameters
response = request.delete('accounts/$account_id/documents/12345')

You can manipulate the response directly, or attempt to parse it using the Gliffy::Response object:

model = Response.from_http_response(response)

Command Line Client

This also comes with a command line client that can serve as an example of using the API. The command-line client is quite usable in its own right:

gliffy help

This will list all the commands you can give to the gliffy command. You can't do everything with the command line that you can with the full API, but you can do quite a bit

# set up your account
> gliffy config

# List all documents in your account
> gliffy ls

# Create a new document
> gliffy new "My New Document"
Created document 123456 - My New Document

# Edit it
> gliffy edit 123456

# Make a new folder
> gliffy mkdir awesome

# Move our new document there
> gliffy mv 123456 awesome

# Get it as a PNG
> gliffy get -t png 123456
Wrote 123456_L.png

# Get help on a command
> bin/gliffy help get
view [options] 
    View a diagram as an image, or download it

    -p, --publicurl                                - Get the Public URL only (if
    -s, --size=L, M, S, T                          - Size (default: L)
    -t, --type=jpeg, png, svg, xml                 - File Type (default: jpeg)
    -u, --url                                      - Get the URL only
    -v, --version=version number (omit for latest) - Version



Domain Objects

Instead of creating explicit objects for each domain object in Gliffy, we always return a Response object, that uses method_missing to implement accessors for data returned from Gliffy. These implicit accessors should return typed values and are named accordingly:

  • If the name in the XSD has dashes, underscores are used here

  • If the item is a boolean, its boolean value is available with a “?” at the end

  • The id field is available as type_id, e.g. document_id

  • Date fields are converted to Time objects

  • Any field in the response that was not known about in this code will be available as a String, based on the above rules

So, if you requested document meta data, you would have the following accessors available:

  • document.document_id

  • document.is_private?

  • document.is_public?

  • document.num_versions

  • document.mod_date # returns a Time

  • document.create_date # returns a Time

  • document.published_date # returns a Time

  • document.owner # Returns a Response that responds to user accessors

  • document.versions # Returns an array of Response objects that act like versions

HTTP Layer

Request implements the HTTP layer, and is based on HTTParty. Since all Gliffy URLs have an “action” HTTP param in them, this action is the method name, followed by the URL on which to perform that action (this is not a REST action, but specific to Gliffy). You can optionally include other HTTP params, however those needed for authentication and signing are taken care of. Request will examine the Credential object used to create the Request object, sign the request, make the request and return the result. It will look at the result only enough to determine if it's an error, or a failure. See the RubyDoc for more on how this works.



You will need:

* sdoc 0.2.16 or better
* httparty 0.4.2 or better
* ruby-hmac 0.3.2 or better
* gli 0.1.6 or better

All of these save for hanna are installed if you installed the gem.

Unit Tests

rake test

This will run unit tests and also create junit_output.xml as a side-effect (via some monkeypatching of Ruby's unit test code); this should be a standard JUnit test result file you could use for integration into your CI server.

Sometimes the test that two nonces shouldn't be the same fails. This occurs because they are generated in pretty much the same instant AND when the random number generator generates the same number twice in a row. Usually if you run tests again, things pass. This will be very unlikely to happen in a production environment.

Integration Tests

rake inttest

This code is capable of running integration tests against Gliffy's integration test servers. If you would like to run these tests, you must contact Gliffy for the information needed. You could technically run integration tests against your own Gliffy account on their production server, but this may delete or change your account's data and is not recommended. Once you have the information from Gliffy, create the file `test/it_cred.rb` as follows:

$account_id = # integration tests account id
$username = # integration tests admin user name
$oauth_consumer_key = # integration test account consumer key
$oauth_consumer_secret = # integration test account consumer secret
$api_root = # integration test server API endpoint
$http_auth_username = # integration test server HTTP Auth username
$http_auth_password = # integration test server HTTP Auth password

Functional Tests

rake functest

The functional tests perform actual workflows against a Gliffy server and, as such, are more fragile. If something is wrong in your environment (or with Gliffy), you could leave the test account in a weird state. As such, you should create a new account using a test-only API call. This can be done via

rake setup_account

This requires that it_cred.rb is set up and will then run test/setup_account.rb. This will create the file functest_cred.rb with the necessary information to access the newly created account. The accounts seem to get reset every day, so you will not be able to reliably automate this. That being said, the only way to get 100% coverage is to run these tests.

Each functional test assumes the following:

  • The account name is 'Ruby Client Test Account'

  • The account id is 1000001

  • The only user is

  • There are no documents/diagrams

  • The only folder is ROOT

Each test will put data into Gliffy, query it, and remove it, thus leaving the account in the same state.

To fully test the edit launch link, run

rake TEST_LINK=true functest

This will print out the launch link and pause the testing. Copy/Paste this into your browser to make sure it works and then come back to the console and hit return. Do not do this for automated builds.