Using the Bootic API in a Ruby on Rails application
This article shows how to access Bootic API data from a Ruby on Rails Application. The reader is expected to have a working knowledge of the Rails framework.
At the end of this article you will be able to use Bootic’s login system to log Bootic users into your application, and access Bootic’s API on their behalf to display a list of recent orders.
Create an OAuth2 application
We’ll use Bootic’s OAuth2 provider service to implement Single Sign-on (SSO) for you app’s users. This means that users will be able to login to this app using their Bootic user credentials.
This process involves the app redirecting to Bootic’s OAuth provider with an OAuth2 application credentials, the user authorizing the application to access their Bootic data on their behalf, and Bootic’s OAuth2 provider issuing an API access token back to the Rails app.
As a developer, you must first create an OAuth2 application and obtain its
client_secret credentials. You only need to do this once.
Make sure that the OAuth2 Application’s “Redirect URI” matches you app’s host plus the path
/auth/bootic/callback (more on that shortly). For example, if your local development app runs on
http://localhost:3000, you’ll enter
Omniauth is a Ruby framework for plugin different authentication strategies into Rails apps, allowing your users to signup into your app using 3rd party identity providers such as Twitter, Facebook, Google or, in this case, Bootic.
Omniauth-Botic is an Omniauth strategy that will do most of the work to let you seamlessly add Bootic Single Sign-on to your Ruby apps.
First, add Omniauth-Bootic to you app’s Gemfile.
Now install it.
Now we’ll create a file in
config/initializers/omniauth.rb to configure it with your OAuth2 credentials.
# config/initializers/omniauth.rb Rails.application.config.middleware.use OmniAuth::Builder do provider :bootic, ENV['BOOTIC_CLIENT_ID'], ENV['BOOTIC_CLIENT_SECRET'], scope: 'admin' end
We will now implement the user login flow.
Add a “login” link.
In one of your public views, add …
<a href="/auth/bootic" class="btn-login">Login with Bootic!<a>
Omniauth adds these special
auth/:provider logins routes automatically from your configuration above.
When the user clicks this link, they will be redirected to
auth.bootic.net where they will be asked to login using their own Bootic credentials and, the first time, authorize your application to access their Bootic data on their behalf.
After the user authorizes your application,
auth.bootic.net redirects to you app’s
redirect_uri, where Omniauth-Bootic finished the process.
Add required routes.
Omniauth expects your app to define a few routes. These routes encompass the complete user flow of logging in, registering and logging out of your app.
You can point these routes to whatever controller and action you want, but we’ll use a
SessionsController to encapsulate everything to do with user sessions and login.
# This route is hit by Omniauth when it's done with the # user authorization flow, and will receive user data # that you can use to complete the registration in your system match '/auth/:provider/callback', to: 'sessions#create', via: [:get, :post] # Use this to logout or destroy the user session get '/auth/logout', to: 'sessions#destroy', as: :logout # This is a normal Rails action that will be login-protected get 'dashboard', to: 'dashboard#index'
Create controller actions
class SessionsController < ApplicationController # This action is invoked at the end of the authorize/login flow # Omniauth puts the user data sent by Bootic in the 'omniauth.auth' request variable. def create # We'll need the Bootic access token later # so let's store it in the session # (you could store it in your database, too) session[:access_token] = request.env['omniauth.auth']['credentials']['token'] # Omniauth-Bootic returns some aditional user information. # Lets store it too session[:user_name] = request.env['omniauth.auth']['info']['name'] # That's it! The user is now logged in our Rails app. # Redirect to some protected page flash[:notice] = "Welcome!" redirect_to dashboard_url end # Destroy the session and logout. def destroy session.delete :access_token session.delete :user_name redirect_to root_url end end
Note that we’re only storing user data in the Rails session (cookie-based by default), but if you have your own database of users you could make sure to create a local user if one doesn’t exist already.
def create bootic_email = request.env['omniauth.auth']['info']['email'] bootic_name = request.env['omniauth.auth']['info']['name'] user = User.where(email: bootic_email, name: bootic_name).first_or_create session[:user_id] = user.id # .. etc end
Finally, we’ll add the newly logged in user’s name in
app/views/dashboard/index.html.erb to welcome them into the application.
<h1>Welcome, <%= session[:user_name] %></h1>
Bootic API client
What we’ve seen so far is enough if you just want to use Bootic’s OAuth2 provider as a Single Sign-on mechanism, but if you want to use the provided access token to access the Bootic API in a Ruby app, we recommend you use our official BooticClient gem.
Add it to your Gemfile.
And install it
Configuring the client
… Now we’ll configure it with your OAuth2 application credentials, just like you did with Omniauth-Bootic.
# config/initializers/bootic_client.rb BooticClient.configure do |c| c.client_id = ENV['BOOTIC_CLIENT_ID'] c.client_secret = ENV['BOOTIC_CLIENT_SECRET'] c.logger = Rails.logger c.logging = Rails.env.development? c.cache_store = Rails.cache end
Now we need to instantiate the Bootic API client in our controllers so we can use it everywhere in our app. We need to pass it the
access_token we just got from Omniauth.
# app/controllers/application_controller.rb def bootic_client @bootic_client ||= BooticClient.client(:authorized, access_token: session[:access_token]) do |new_token| Rails.logger.info "Renewed access token" session[:access_token] = new_token end end
We’ll now use the
bootic_client instance available in every controller to fetch a list of recent orders for your Bootic shop.
Bootic’s API is designed after Hypermedia principles, meaning that its JSON responses include links to other resources in the system. This is similar to how you normally navigate the Web by following links from one page to the other. The Bootic Ruby Client fully supports this.
def index # The API root resource root = bootic_client.root # Your main shop shop = root.shops.first # Do you have permissions to access the shop's orders? @orders = if shop.has?(:orders) shop.orders(sort: 'updated_at.desc') else  end end
Note that we check that the
shop sub-resource has a link called “orders”. If the link isn’t there, it means that your
access_token doesn’t have the right scope of “admin”.
You can simplify this controller action a bit by creating a helper method to access common API resources like
root and its embedded
# app/controllers/application_controller.rb protected def bootic_root @bootic_root ||= bootic_client.root end def current_shop @current_shop ||= bootic_root.shops.first end
So now your
DashboardController and any other controllers look much simpler.
# app/controllers/dashboard_controller.rb def index @orders = if current_shop.has?(:orders) current_shop.orders(sort: 'updated_on.desc') else  end end
We’re almost there! Now we just need to list the
@orders in the
<h2>Your recent orders</h2> <ul class="orders_list"> <% @orders.each do |order| %> <li class="order status_<%= order.status %>"> <h3><%= order.code %></h3> <span class="total"><%= number_to_currrency order.net_total %></span> <span class="units"><%= order.units %> units</span> <span class="products">products: <%= order.line_items.map(&:product_title).join(', ') %></span> <li> <% end %> </ul>
This wasn’t too hard, and it works; but talking to external API’s will always be slower and less reliable than connecting to a local database.
Fortunately, the Bootic API can help you optimize client-server communication by adding HTTP caching headers to its responses. In turn, the Bootic Ruby client knows how to parse these headers and store repeat responses in a local cache. This means that subsequent requests to a cached resource will be much faster.
In our configuration above we already ask the Bootic client to use the
Rails.cache interface to store responses.
# config/initializers/bootic_client.rb BooticClient.configure do |c| # ... c.cache_store = Rails.cache end
In development mode Rails uses an in-memory cache store, but in production it is recommended that you use a distributed store such as Memcache
So the good news is that you just have to configure
Rails.cache to use Memcache to get a noticeable speed boost when using the Bootic API client in a Rails app.
Read more on Rails caching here.
And that’s the basics of working with the Bootic API in a Rails application. If you have any questions or problems please contact us on our contact form.
You should be able to deploy this app like any other Rails application, including hosted services like Heroku.
Keep in mind that you need to create a separate OAuth2 application with a redirect URI matching your live server.
For example, if your production app is deployed to
https://my.greatapp.com, for Omniauth to work with Bootic’s OAuth2 server you need to enter a redirect URI of
Remember to configure your
BOOTIC_CLIENT_SECRET accordingly to use the live app credentials in the “production” environment.