Application Proxies: The New Hotness

David Underwood

I’m pleased to announce a brand new feature that we recently added to the Shopify API: Application Proxies. These will allow you do develop all kinds of crazy things that weren’t possible before, and we’re really excited about it. Let me explain.

What’s an App Proxy?

An App Proxy is simply a page within a Shopify shop that loads its content from another location of your choosing. Applications can tell certain shop pages that they should fetch and display data from another location outside of Shopify.

The really cool thing about the implementation we’ve put together is that if you return data with the application/liquid content-type we’ll run it through Shopify’s template rendering engine before pushing it out to the user. This allows you to create dynamic native pages without having to do anything crazy with iframes. I’ll explain this in more detail later.

How Do I Set This Up?

We have a great App Proxy tutorial over on our API docs that takes you through the steps, but I’ll summarize them here too.

The first thing you need to do is set up the path that should be proxied and where it should be proxied to. This is done from your app’s configuration screen on the Partners dashboard.

Once you’ve done that, you’ll need to work out what data you’re going to return when the specified URL is hit. You can return anything you want but for now we’re going to show some very simple stats to get the ball rolling.

All my examples assume that you’re using the shopify_app gem as a starting point, but the topics I cover translate directly to all languages.

Before we do anything else we need a controller to handle the calls. I generated a ProxyController class and mapped /proxy to hit its index method. I also created a template to render the response.

Here’s the controller:

class ProxyController < ApplicationController
  def index
  end
end

And here’s the template:

<h1>Hello App Proxy World</h1>

Really easy so far. Now we can start our rails app and visit the proxied page in a browser. It should look something like this:

Not much to see here just yet. In fact, it looks nothing like our shop. Let’s do something about that.

What we want is for shopify to render the page just like it were any other native data using the Liquid engine. We tell Shopify to do this by setting the content-type header on our response to application/liquid. At the same time we’re going to tell rails not to use its own layouts when rendering the page.

Add this line to the index method in ProxyController

render :layout => false, :content_type => 'application/liquid'

Now save and reload the page. Tada! Here’s what you’ll see:


Good, eh?

Next Steps

Static text is all well and good, but its not very interesting. What we really want here are some stats. I’ve chosen to display the shop’s takings as well as a link to the most popular product for the last week.

Now that we’re trying to access shop data we need to figure out which shop is sending us the request in the first place. Fortunately the url of the shop is one of the GET parameters on the request, so we can grab that and use it to configure our environment to make API calls. Details on how to do this are documented here, so go set that up and then come back when you’re done. I’ll wait.

Back? Excellent. Let’s put some info into our response. here’s what your ProxyController should look like now:

class ProxyController < ApplicationController

  def index
    ShopifyAPI::Base.site = Shop.find_by_name(params[:shop]).api_url

    @orders = ShopifyAPI::Order.find(:all, :params => {:created_at_min => 1.week.ago})
    @total = 0

    @product_sale_counts =Hash.new()

    @orders.each do |order|
      order.line_items.each do |line_item|
        if @product_sale_counts[line_item.product_id]
          @product_sale_counts[line_item.product_id] = @product_sale_counts[line_item.product_id] + line_item.quantity
        else
          @product_sale_counts[line_item.product_id] = line_item.quantity
        end
      end 
      @total += order.total_price.to_i
    end

    top_seller_stats = @product_sale_counts.max_by{|k,v| v}
    @product = ShopifyAPI::Product.find(top_seller_stats.first)

    @top_seller_count = top_seller_stats.last

    render :layout => false, :content_type => 'application/liquid'
  end
end

And here’s the template:

<h1>This Week's Earnings</h1>
<p><%= number_to_currency(@total)%> from <%= @orders.count%> orders</p>
<h1>Top Seller: <%= link_to(@product.title, url_for_product(@product)) %></h1>
<p>This product sold <%= @top_seller_count %> units</p>

Here's the finished product. The CSS could use some work, but all our info is there and matches the theme perfectly:

A Word On Security

So far so good, but right now there’s no security on our proxy. Anyone sending a request to that url with a ‘shop’ parameter will get data back. Oops! Let’s fix that.

Just like our webhooks, we sign all our proxy requests. There are details in the API docs on exactly how this is done, but for simplicity’s sake just add this private function to your ProxyController and add it as a before_filter:

def verify_request_source
  url_parameters = {
    "shop" => params[:shop],
    "path_prefix" => params[:path_prefix],
    "timestamp" => params[:timestamp]
  }

  sorted_params = url_parameters.collect{ |k, v| "#{k}=#{Array(v).join(',')}" }.sort.join

  calculated_signature = OpenSSL::HMAC.hexdigest(OpenSSL::Digest::Digest.new('sha256'),
  ShopifyAppProxyExample::Application.config.shopify.secret, sorted_params)

  raise 'Invalid signature' if params[:signature] != calculated_signature
end

Great! Now you can be sure that Shopify is the one sending you this data and not some dirty impostor.

There you have it. Application Proxies are a great way to introduce dynamic third-party content into a native shop page. There's a lot more that you can do with them, far too much to cover in a single blog post.

If you're interested I encourage you to set up a quick app and give them a try. You can also discuss potential ideas with other developers on our dev mailing list.