<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Microservices on Damian Galarza | Software Engineering &amp; AI Consulting</title><link>https://www.damiangalarza.com/tags/microservices/</link><description>Recent posts from Damian Galarza | Software Engineering &amp; AI Consulting</description><generator>Hugo</generator><language>en-us</language><managingEditor>Damian Galarza</managingEditor><atom:link href="https://www.damiangalarza.com/tags/microservices/feed.xml" rel="self" type="application/rss+xml"/><item><title>Simple Sinatra Service Proxy</title><link>https://www.damiangalarza.com/posts/2012-04-02-simple-sinatra-service-proxy/</link><pubDate>Mon, 02 Apr 2012 00:00:00 +0000</pubDate><author>Damian Galarza</author><guid>https://www.damiangalarza.com/posts/2012-04-02-simple-sinatra-service-proxy/</guid><content:encoded><![CDATA[<p>Recently I came across the situation where I would need to communicate with a third party API on the front
end via JavaScript and some AJAX requests. Unfortunately JavaScript does not allow ajax requests across different
domains which caused an issue for us since the service does not support a JSONP service to get around this.</p>
<p>Instead, I set out to build a back end service which would consume our third party API and we could interact
with on the front end. However, I did not want to spend a great deal of time on building this midpoint between
the services.</p>
<h3 id="ruby-and-sinatra-to-the-rescue">Ruby and Sinatra to the Rescue</h3>
<p>Armed with the task at hand I set out to build the simplest approach possible to begin consuming our third party
API as quickly as possible. I started out with Rails and a look into ActiveResource but quickly found that there was
to much overhead and complexity for what I needed. With this in mind I decided to move onto a simple Sinatra application which
would aim to mimic the third party services in API methods and forward requests for us.</p>
<p>For our test case, let&rsquo;s look at the Twitter API. Note, Twitter does in fact support a JSONP service so this isn&rsquo;t really necessary.
We are simply using it as a test case for the post.</p>
<h4 id="fetching-a-users-timeline">Fetching a user&rsquo;s timeline</h4>
<div class="highlight"><pre tabindex="0" style="color:#cdd6f4;background-color:#1e1e2e;-moz-tab-size:2;-o-tab-size:2;tab-size:2;"><code class="language-ruby" data-lang="ruby"><span style="display:flex;"><span><span style="color:#89dceb">require</span> <span style="color:#a6e3a1">&#39;sintra&#39;</span>
</span></span><span style="display:flex;"><span><span style="color:#89dceb">require</span> <span style="color:#a6e3a1">&#39;net/http&#39;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>get <span style="color:#a6e3a1">&#34;/1/statuses/user_timeline&#34;</span> <span style="color:#cba6f7">do</span>
</span></span><span style="display:flex;"><span>    uri <span style="color:#89dceb;font-weight:bold">=</span> <span style="color:#f9e2af">URI</span><span style="color:#89dceb;font-weight:bold">::</span><span style="color:#f9e2af">HTTP</span><span style="color:#89dceb;font-weight:bold">.</span>build(
</span></span><span style="display:flex;"><span>        <span style="color:#a6e3a1">:host</span> <span style="color:#89dceb;font-weight:bold">=&gt;</span> api<span style="color:#89dceb;font-weight:bold">.</span>twitter<span style="color:#89dceb;font-weight:bold">.</span>com,
</span></span><span style="display:flex;"><span>        <span style="color:#a6e3a1">:path</span> <span style="color:#89dceb;font-weight:bold">=&gt;</span> request<span style="color:#89dceb;font-weight:bold">.</span>path_info,
</span></span><span style="display:flex;"><span>        <span style="color:#a6e3a1">:query</span> <span style="color:#89dceb;font-weight:bold">=&gt;</span> request<span style="color:#89dceb;font-weight:bold">.</span>query_string
</span></span><span style="display:flex;"><span>    )
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    content_type <span style="color:#a6e3a1">&#39;application/json&#39;</span>, <span style="color:#a6e3a1">:charset</span> <span style="color:#89dceb;font-weight:bold">=&gt;</span> <span style="color:#a6e3a1">&#39;utf-8&#39;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#f9e2af">Net</span><span style="color:#89dceb;font-weight:bold">::</span><span style="color:#f9e2af">HTTP</span><span style="color:#89dceb;font-weight:bold">.</span>get(uri)
</span></span><span style="display:flex;"><span><span style="color:#cba6f7">end</span>
</span></span></code></pre></div><p>In order to fetch a user&rsquo;s timeline we will need to make a request to the following API path: <code>/1/statuses/user_timeline</code>. Along with this path
the API documentation by twitter specifies that we can send various parameters along in the query string. What we have done here is we created a path which matches
twitter&rsquo;s and from there we access the request information provided by Sinatra. We build a URI using the API URL, <code>request.path</code>, and <code>request.query</code>. This will allow us
to quickly forward the request to Twitter&rsquo;s API through a NET::HTTP.get request.</p>
<p>Now that we&rsquo;ve done that we can either mount our Sinatra app somewhere in the same domain or proxy requests to it on another domain.  In my case, I&rsquo;ve set up a simple
proxy through Apache at /services.</p>
<pre tabindex="0"><code>&lt;IfModule mod_proxy.c&gt;
    ProxyRequests Off
    ProxyVia On

    &lt;Proxy *&gt;
        AddDefaultCharset off
        Order deny, allow
        Allow from all
    &lt;/Proxy&gt;

    ProxyPass /services http://127.0.0.1:9393
    ProxyPassReverse /services http://127.0.0.1:9393
&lt;/IfModule&gt;
</code></pre><p>So assuming I have my Sinatra application up and running on port 9393. I now have a proxy which will forward all requests to /services in my web application
to the Sinatra application. This will then forward all requests to the Twitter API and return the results. Visit the <a href="http://httpd.apache.org/docs/2.0/mod/mod_proxy.html">mod_proxy</a> documentation
for more information about HTTP proxies with Apache.</p>
<h4 id="drying-up-our-application">Drying up our application</h4>
<p>In our case right now we have a single method that we are forwarding, but what if we wanted to support more API methods provided by twitter.  Well we could go ahead and write out
each method and its block, or we could take advantage of the flexibility we have available to us.</p>
<div class="highlight"><pre tabindex="0" style="color:#cdd6f4;background-color:#1e1e2e;-moz-tab-size:2;-o-tab-size:2;tab-size:2;"><code class="language-ruby" data-lang="ruby"><span style="display:flex;"><span><span style="color:#89dceb">require</span> <span style="color:#a6e3a1">&#39;sinatra&#39;</span>
</span></span><span style="display:flex;"><span><span style="color:#89dceb">require</span> <span style="color:#a6e3a1">&#39;net/http&#39;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#cba6f7">def</span> <span style="color:#89b4fa">api_request</span>(path, query_string)
</span></span><span style="display:flex;"><span>    uri <span style="color:#89dceb;font-weight:bold">=</span> <span style="color:#f9e2af">URI</span><span style="color:#89dceb;font-weight:bold">::</span><span style="color:#f9e2af">HTTP</span><span style="color:#89dceb;font-weight:bold">.</span>build(
</span></span><span style="display:flex;"><span>        <span style="color:#a6e3a1">:host</span> <span style="color:#89dceb;font-weight:bold">=&gt;</span> api<span style="color:#89dceb;font-weight:bold">.</span>twitter<span style="color:#89dceb;font-weight:bold">.</span>com,
</span></span><span style="display:flex;"><span>        <span style="color:#a6e3a1">:path</span> <span style="color:#89dceb;font-weight:bold">=&gt;</span> path,
</span></span><span style="display:flex;"><span>        <span style="color:#a6e3a1">:query</span> <span style="color:#89dceb;font-weight:bold">=&gt;</span> query_string
</span></span><span style="display:flex;"><span>    )
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#f9e2af">Net</span><span style="color:#89dceb;font-weight:bold">::</span><span style="color:#f9e2af">HTTP</span><span style="color:#89dceb;font-weight:bold">.</span>get uri
</span></span><span style="display:flex;"><span><span style="color:#cba6f7">end</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>request_handler <span style="color:#89dceb;font-weight:bold">=</span> <span style="color:#89dceb;font-weight:bold">-&gt;</span> <span style="color:#cba6f7">do</span>
</span></span><span style="display:flex;"><span>    content_type <span style="color:#89dceb;font-weight:bold">=</span> <span style="color:#a6e3a1">&#39;application/json&#39;</span>, <span style="color:#a6e3a1">:charset</span> <span style="color:#89dceb;font-weight:bold">=&gt;</span> <span style="color:#a6e3a1">&#39;utf-8&#39;</span>
</span></span><span style="display:flex;"><span>    api_request request<span style="color:#89dceb;font-weight:bold">.</span>path_info, request<span style="color:#89dceb;font-weight:bold">.</span>query_string
</span></span><span style="display:flex;"><span><span style="color:#cba6f7">end</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#a6e3a1">%w{
</span></span></span><span style="display:flex;"><span><span style="color:#a6e3a1">    /1/statues/user_timeline
</span></span></span><span style="display:flex;"><span><span style="color:#a6e3a1">    /1/statuses/mentions
</span></span></span><span style="display:flex;"><span><span style="color:#a6e3a1">    /1/statuses/retweeted_by_me
</span></span></span><span style="display:flex;"><span><span style="color:#a6e3a1">}</span><span style="color:#89dceb;font-weight:bold">.</span>each { <span style="color:#89dceb;font-weight:bold">|</span>route<span style="color:#89dceb;font-weight:bold">|</span> get route, <span style="color:#89dceb;font-weight:bold">&amp;</span>request_handler }
</span></span></code></pre></div>]]></content:encoded></item></channel></rss>