Permalink
Browse files

Fix URL of JS client

  • Loading branch information...
1 parent ee0c4c2 commit 0c9c2dc8fe3a272cf8fdf72713359213053fdc9e @arjunsanyal arjunsanyal committed May 10, 2013
@@ -128,9 +128,9 @@
<li><p>Restart Tomcat: <code>sudo service tomcat7 restart</code></p></li>
<li><p>Run the <code>./smart_manager.py -s</code> script to update the server settings
(substitute &quot;localhost&quot; with the DNS of the machine that you want).</p></li>
-<li><p>Take a look at the apache virtual servers' configurations in
+<li><p>Take a look at the apache virtual servers&#39; configurations in
&quot;/etc/apache2/sites-enabled&quot; and change any occurence of &quot;smart-vm&quot;
-with your server's DNS.</p></li>
+with your server&#39;s DNS.</p></li>
<li><p>Restart Apache: <code>sudo service apache2 restart</code></p></li>
<li><p>Reset the SMART servers and reload the sample patients: <code>./smart_manager.py -rl</code></p></li>
<li><p>If you need the SMART REST sample apps as well, then edit the manifest
@@ -121,12 +121,12 @@
<p>Importantly, a background app is not necessarily a web app, since it may not
have a user-facing web interface. In this example, we will demonstrate just
that: a simple Python program that acts as a SMART background app, but does not
-respond to any web requests. So, if you've figured out how to build a SMART REST
+respond to any web requests. So, if you&#39;ve figured out how to build a SMART REST
app, all you need to know now is how to obtain the credentials needed to cycle
-through all the SMART Container's medical records.</p>
+through all the SMART Container&#39;s medical records.</p>
<p>The first thing you need is, of course, a SmartClient instance to make REST API
-calls against the SMART container. If you don't have that library running yet,
+calls against the SMART container. If you don&#39;t have that library running yet,
check out the SMART Python Client. </p>
<p>Make sure you understand the warning about setting a strong <code>consumer_secret</code>
@@ -142,26 +142,24 @@
<span class="s">&#39;consumer_secret&#39;</span> <span class="p">:</span> <span class="s">&#39;smartapp-secret&#39;</span>
<span class="p">},</span>
<span class="bp">None</span><span class="p">)</span>
-</code></pre>
-</div>
+</code></pre></div>
<p>The important difference between this SmartClient and the one you created for
use in SMART REST API calls is that this one has no resource-specific
-credentials. That's because, at first, you're not going to make API calls
+credentials. That&#39;s because, at first, you&#39;re not going to make API calls
specific to any single medical record. In OAuth parlance, this is called a
-&quot;2-legged call.&quot; Now, it's time to iterate through all records available at that
+&quot;2-legged call.&quot; Now, it&#39;s time to iterate through all records available at that
SMART Container. The specific API calls to do this can be found in our REST API,
but the SMART Python client library makes it easy for you:</p>
<div class="highlight"><pre><code class="python"> <span class="k">for</span> <span class="n">record_id</span> <span class="ow">in</span> <span class="n">smart_client</span><span class="o">.</span><span class="n">loop_over_records</span><span class="p">():</span>
<span class="c"># do stuff with each record</span>
-</code></pre>
-</div>
+</code></pre></div>
-<p>Note that, in each iteration, the smart_client is modified to automatically use
+<p>Note that, in each iteration, the smart<em>client is modified to automatically use
the credentials needed to access this specific record. If you were to call the
API manually, you would have to extract the tokens you get from the container,
-and insert them into the smart_client object.</p>
+and insert them into the smart</em>client object.</p>
<p>So, using a simple query to read drug names:</p>
@@ -176,18 +174,16 @@
<span class="s"> ?drugname_code dcterms:title ?drugname .</span>
<span class="s"> }</span>
<span class="s"> &quot;&quot;&quot;</span>
-</code></pre>
-</div>
+</code></pre></div>
-<p>We can simply iterate through the records, retrieve each record's medications,
+<p>We can simply iterate through the records, retrieve each record&#39;s medications,
and print them to the screen:</p>
<div class="highlight"><pre><code class="python"> <span class="k">for</span> <span class="n">record_id</span> <span class="ow">in</span> <span class="n">smart_client</span><span class="o">.</span><span class="n">loop_over_records</span><span class="p">():</span>
<span class="n">medications</span> <span class="o">=</span> <span class="n">smart_client</span><span class="o">.</span><span class="n">get_medications</span><span class="p">(</span><span class="n">record_id</span> <span class="o">=</span> <span class="n">record_id</span><span class="p">)</span>
<span class="n">med_names</span> <span class="o">=</span> <span class="n">medications</span><span class="o">.</span><span class="n">graph</span><span class="o">.</span><span class="n">query</span><span class="p">(</span><span class="n">QUERY</span><span class="p">)</span>
<span class="k">print</span> <span class="s">&quot;</span><span class="si">%s</span><span class="s">: </span><span class="si">%s</span><span class="s">&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="n">record_id</span><span class="p">,</span> <span class="s">&quot;, &quot;</span><span class="o">.</span><span class="n">join</span><span class="p">([</span><span class="nb">str</span><span class="p">(</span><span class="n">m</span><span class="p">)</span> <span class="k">for</span> <span class="n">m</span> <span class="ow">in</span> <span class="n">med_names</span><span class="p">]))</span>
-</code></pre>
-</div>
+</code></pre></div>
<h2>Helper Apps</h2>
@@ -126,12 +126,12 @@
were entirely transparent to you, the app builder, because the SMART Container
was able to take care of it all: the JavaScript API call simply notified the
outer frame of the data request, and the outer-frame knows who the logged-in
-user is and what medical record they're currently considering.</p>
+user is and what medical record they&#39;re currently considering.</p>
<p>Now, we consider the case where you want the backend of your app to obtain data
directly from the SMART Container, e.g. the SMART Reference EMR, using the REST
-API. In that case, the SMART Container doesn't know a-priori who is making the
-call and whether they're authorized to do so. We need to authenticate the call
+API. In that case, the SMART Container doesn&#39;t know a-priori who is making the
+call and whether they&#39;re authorized to do so. We need to authenticate the call
somehow, and you, the app builder, need to know how to ensure that your calls
are properly authenticated.</p>
@@ -151,17 +151,17 @@
</ol>
<p>SMART employs (1), but implements a much simpler approach to (2), providing your
-app with the requisite token and secret. We'll describe this simpler approach
+app with the requisite token and secret. We&#39;ll describe this simpler approach
here. At a high-level, your app can simply look for a URL parameter called
<code>oauth_header</code> set by the SMART JavaScript client library. In this value, you
will find the OAuth token and secret you need.</p>
-<h2>Change Your App's OAuth Consumer Secret in Production (Important!)</h2>
+<h2>Change Your App&#39;s OAuth Consumer Secret in Production (Important!)</h2>
<p>Each SMART container your app runs against must first &quot;install&quot; your app
-by inserting your app's manifest into it's database. This data includes
-your app's OAuth <code>consumer-secret</code> which is the shared secret between
-your app and the container that <strong>ALL SECURITY</strong> of your app's
+by inserting your app&#39;s manifest into it&#39;s database. This data includes
+your app&#39;s OAuth <code>consumer-secret</code> which is the shared secret between
+your app and the container that <strong>ALL SECURITY</strong> of your app&#39;s
communication with the server relies on and is a basic requirement of
OAuth-signed REST API calls.</p>
@@ -176,60 +176,53 @@
<p>This secret is provisioned when your app is loaded into the smart
container with the following command:</p>
-
-<pre><code>manage.py load_app &lt;manifest-location&gt; &lt;secret&gt;
-</code></pre>
-
+<div class="highlight"><pre><code class="text">manage.py load_app &lt;manifest-location&gt; &lt;secret&gt;
+</code></pre></div>
<h2>Passing Tokens via URL Parameter</h2>
<p>The SMART container will pass all necessary fields to your app via the
<code>oauth_header</code> URL parameter. Specifically, the actual request sent to your
-app's backend server for index.html looks like this:</p>
+app&#39;s backend server for index.html looks like this:</p>
<div class="highlight"><pre><code class="javascript"> <span class="nx">GET</span> <span class="o">/</span><span class="nx">index</span><span class="p">.</span><span class="nx">html</span><span class="o">?</span><span class="nx">oauth_header</span><span class="o">=</span><span class="p">{</span><span class="nx">Header</span> <span class="nx">value</span> <span class="nx">here</span><span class="p">...}</span>
-</code></pre>
-</div>
+</code></pre></div>
<p>You need to first extract that header from the GET parameter:</p>
<div class="highlight"><pre><code class="javascript"> <span class="nx">oauth_header</span> <span class="o">=</span> <span class="nx">web</span><span class="p">.</span><span class="nx">input</span><span class="p">().</span><span class="nx">oauth_header</span>
-</code></pre>
-</div>
+</code></pre></div>
-<p>You'll also to need to URL-decode it:</p>
+<p>You&#39;ll also to need to URL-decode it:</p>
<div class="highlight"><pre><code class="javascript"> <span class="nx">oauth_header</span> <span class="o">=</span> <span class="nx">urllib</span><span class="p">.</span><span class="nx">unquote</span><span class="p">(</span><span class="nx">oauth_header</span><span class="p">)</span>
-</code></pre>
-</div>
+</code></pre></div>
<p>The field contains a complete OAuth Authorization header that includes a few
-extra fields, including notably smart_record_id, smart_oauth_token and
-smart_oauth_token_secret. smart_record_id indicates the medical record ID
+extra fields, including notably smart<em>record</em>id, smart<em>oauth</em>token and
+smart<em>oauth</em>token<em>secret. smart</em>record_id indicates the medical record ID
of the current context, while the OAuth token and secret are the credentials
your app needs to make REST API calls back into the SMART EMR. Why, then, are
they themselves delivered in OAuth authorization header format? So you can
verify that these tokens are authentic before you actually use them!</p>
<p>In other words, the SMART container is sending you credentials you can use to
sign your API request. Those credentials are, themselves, signed, so you know
-they're okay to use.</p>
+they&#39;re okay to use.</p>
-<p>Thankfully, you don't need to worry too much about the details, because we
+<p>Thankfully, you don&#39;t need to worry too much about the details, because we
provide you with the utilities you need to extract the fields you need quickly
and efficiently:</p>
<div class="highlight"><pre><code class="javascript"> <span class="err">#</span> <span class="nx">parse</span> <span class="nx">it</span> <span class="nx">into</span> <span class="nx">a</span> <span class="nx">python</span> <span class="nx">dictionary</span>
<span class="nx">oauth_params</span> <span class="o">=</span> <span class="nx">oauth</span><span class="p">.</span><span class="nx">parse_header</span><span class="p">(</span><span class="nx">oauth_header</span><span class="p">)</span>
-</code></pre>
-</div>
+</code></pre></div>
<p>Then get the specific parameters you need to sign your own API calls:</p>
<div class="highlight"><pre><code class="javascript"> <span class="nx">record_id</span> <span class="o">=</span> <span class="nx">oauth_params</span><span class="p">[</span><span class="s1">&#39;smart_record_id&#39;</span><span class="p">]</span>
<span class="nx">resource_credentials</span> <span class="o">=</span> <span class="p">{</span><span class="s1">&#39;oauth_token&#39;</span><span class="o">:</span> <span class="nx">oauth_params</span><span class="p">[</span><span class="s1">&#39;smart_oauth_token&#39;</span><span class="p">],</span>
<span class="s1">&#39;oauth_token_secret&#39;</span><span class="o">:</span> <span class="nx">oauth_params</span><span class="p">[</span><span class="s1">&#39;smart_oauth_token_secret&#39;</span><span class="p">]}</span>
-</code></pre>
-</div>
+</code></pre></div>
<p>The SMART Connect OAuth Header contains a few more parameters that will prove
useful:</p>
@@ -245,7 +238,7 @@
<p>In the simple case, yes, but in more advanced cases, your backend server might
support multiple simultaneous apps made available to multiple SMART Containers.
Thus, in a given setting, your app needs to know definitely which SMART
-Container it's connecting to and, if you're using one server to host multiple
+Container it&#39;s connecting to and, if you&#39;re using one server to host multiple
apps, which of your apps is being invoked in the first place.</p>
<h2>Using SMART Client Libraries</h2>
@@ -260,21 +253,19 @@
<span class="p">{</span><span class="s1">&#39;consumer_key&#39;</span> <span class="o">:</span> <span class="s1">&#39;my-app@apps.smartplatforms.org&#39;</span><span class="p">,</span>
<span class="s1">&#39;consumer_secret&#39;</span> <span class="o">:</span> <span class="s1">&#39;smartapp-secret&#39;</span><span class="p">},</span>
<span class="nx">resource_credentials</span><span class="p">)</span>
-</code></pre>
-</div>
+</code></pre></div>
-<p>Since we're working against the SMART Reference EMR Sandbox, the APP_ID and
+<p>Since we&#39;re working against the SMART Reference EMR Sandbox, the APP_ID and
consumer-level credentials are all fixed. Of course when connecting against a
different SMART Container (e.g. your own), those will probably change.</p>
<h1>Obtaining SMART Health Data</h1>
<p>With our smart_client instance ready to go, loaded with the right credentials,
-we can start making API calls. Let's get the medication list:</p>
+we can start making API calls. Let&#39;s get the medication list:</p>
<div class="highlight"><pre><code class="javascript"> <span class="nx">medications</span> <span class="o">=</span> <span class="nx">smart_client</span><span class="p">.</span><span class="nx">get_medications</span><span class="p">(</span><span class="nx">record_id</span> <span class="o">=</span> <span class="nx">record_id</span><span class="p">)</span>
-</code></pre>
-</div>
+</code></pre></div>
<p>Just like in the first SMART App we built, the result is an SMARTResponse object
containing an RDF graph of data, which we can query for just the fields we want:</p>
@@ -295,36 +286,34 @@
<span class="nx">med_names_and_cuis</span> <span class="o">=</span> <span class="nx">medications</span><span class="p">.</span><span class="nx">graph</span><span class="p">.</span><span class="nx">query</span><span class="p">(</span><span class="nx">query</span><span class="p">)</span>
<span class="nx">meds</span> <span class="o">=</span> <span class="p">[{</span><span class="s1">&#39;name&#39;</span><span class="o">:</span> <span class="nx">med</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="s1">&#39;rxcui&#39;</span><span class="o">:</span> <span class="nx">med</span><span class="p">[</span><span class="mi">1</span><span class="p">]}</span> <span class="k">for</span> <span class="nx">med</span> <span class="k">in</span> <span class="nx">med_names_and_cuis</span><span class="p">]</span>
-</code></pre>
-</div>
+</code></pre></div>
+
-<p>So far, we're not doing anything novel compared to our SMART Connect App. Let's
+<p>So far, we&#39;re not doing anything novel compared to our SMART Connect App. Let&#39;s
make use of this fully capable backend we have, and integrate this data with
-other information. We'll use <a href="http://rxnav.nlm.nih.gov/">RxNav</a>, the National
-Library of Medicine's resource for RxNorm. In particular, we'll pull out the
+other information. We&#39;ll use <a href="http://rxnav.nlm.nih.gov/">RxNav</a>, the National
+Library of Medicine&#39;s resource for RxNorm. In particular, we&#39;ll pull out the
ingredients for each medication:</p>
<div class="highlight"><pre><code class="javascript"> <span class="k">for</span> <span class="nx">med</span> <span class="k">in</span> <span class="nx">meds</span><span class="o">:</span>
<span class="nx">rxnav_info_xml</span> <span class="o">=</span> <span class="nx">urllib</span><span class="p">.</span><span class="nx">urlopen</span><span class="p">(</span><span class="s2">&quot;http://rxnav.nlm.nih.gov/REST/rxcui/%s/related?rela=has_ingredient&quot;</span> <span class="o">%</span> <span class="nx">med</span><span class="p">[</span><span class="s1">&#39;rxcui&#39;</span><span class="p">]).</span><span class="nx">read</span><span class="p">()</span>
<span class="nx">info</span> <span class="o">=</span> <span class="nx">ElementTree</span><span class="p">.</span><span class="nx">fromstring</span><span class="p">(</span><span class="nx">rxnav_info_xml</span><span class="p">)</span>
<span class="nx">med</span><span class="p">[</span><span class="s1">&#39;ingredients&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="p">[</span><span class="nx">ing</span><span class="p">.</span><span class="nx">text</span> <span class="k">for</span> <span class="nx">ing</span> <span class="k">in</span> <span class="nx">info</span><span class="p">.</span><span class="nx">findall</span><span class="p">(</span><span class="s1">&#39;relatedGroup/conceptGroup/conceptProperties/name&#39;</span><span class="p">)]</span>
-</code></pre>
-</div>
+</code></pre></div>
<p>Most of that code above is to quickly parse the XML we get back from RxNav and
obtain the ingredient names.</p>
-<p>Now that we've combined the SMART record data with a third-party data source, we
+<p>Now that we&#39;ve combined the SMART record data with a third-party data source, we
can just render our HTML:</p>
<div class="highlight"><pre><code class="javascript"> <span class="nx">meds_html</span> <span class="o">=</span> <span class="s2">&quot;\n&quot;</span><span class="p">.</span><span class="nx">join</span><span class="p">([</span><span class="s2">&quot;&lt;li&gt;%s&lt;br /&gt;&lt;small&gt;ingredients: %s&lt;/small&gt;&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="nx">str</span><span class="p">(</span><span class="nx">med</span><span class="p">[</span><span class="s1">&#39;name&#39;</span><span class="p">]),</span> <span class="s2">&quot;, &quot;</span><span class="p">.</span><span class="nx">join</span><span class="p">(</span><span class="nx">med</span><span class="p">[</span><span class="s1">&#39;ingredients&#39;</span><span class="p">]))</span> <span class="k">for</span> <span class="nx">med</span> <span class="k">in</span> <span class="nx">meds</span><span class="p">])</span>
-</code></pre>
-</div>
+</code></pre></div>
-<p>and we're done.</p>
+<p>and we&#39;re done.</p>
-<p>(Note that we're using clunky string concatenation to produce our HTML. Of
-course we recommend using a templating system, but we didn't want to burden the
+<p>(Note that we&#39;re using clunky string concatenation to produce our HTML. Of
+course we recommend using a templating system, but we didn&#39;t want to burden the
explanation with a templating language at this point.)</p>
<h2>What Next?</h2>
Oops, something went wrong.

0 comments on commit 0c9c2dc

Please sign in to comment.