<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss xmlns:atom="http://www.w3.org/2005/Atom" xmlns:posterous="http://posterous.com/help/rss/1.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:media="http://search.yahoo.com/mrss/" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0">
  <channel>
    <title>Compojure on GAE</title>
    <link>http://compojureongae.posterous.com</link>
    <description>Deploying a Clojure web app to Google App Engine</description>
    <generator>posterous.com</generator>
    <link xmlns="http://www.w3.org/2005/Atom" href="http://posterous.com/api/sup_update#b2a70eaf6" type="application/json" rel="http://api.friendfeed.com/2008/03#sup" />
    
    
    <atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/CompojureOnGAE" /><feedburner:info uri="compojureongae" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://posterous.superfeedr.com/" /><item>
      <pubDate>Wed, 09 Jun 2010 09:30:07 -0700</pubDate>
      <title>Using the App Engine Users API from Clojure</title>
      <link>http://feedproxy.google.com/~r/CompojureOnGAE/~3/HupkuzWmQs0/using-the-app-engine-users-api-from-clojure</link>
      <guid isPermaLink="false">http://compojureongae.posterous.com/using-the-app-engine-users-api-from-clojure</guid>
      <description>&lt;p&gt;
	&lt;p&gt;In my previous post about &lt;a href="http://compojureongae.posterous.com/accessing-the-app-engine-datastore"&gt;Accessing the
Datastore&lt;/a&gt;
I set up basic security using a &lt;code&gt;security-constraint&lt;/code&gt; element in the
deployment descriptor (&lt;code&gt;web.xml&lt;/code&gt;). This was simple, as the app didn&amp;rsquo;t
have to be aware of security concerns at all. The downside is that the
app doesn&amp;rsquo;t know if the user is logged in and can&amp;rsquo;t react to that. For
example, the &amp;ldquo;Create new post&amp;rdquo; link is shown to all users, only after
clicking it (and logging in) they get an ugly error message about
missing privileges. This is bad usability, so let&amp;rsquo;s use the App Engine
Users API and move the authentication and authorization into the app.&lt;/p&gt;

&lt;h2&gt;Setting up the routes&lt;/h2&gt;

&lt;p&gt;To make things easier, I changed my route definitions, separating the
public routes from those that need admin privileges. All admin route
URLs now start with /admin:&lt;/p&gt;

&lt;p&gt;&lt;div class="data type-clojure"&gt;
    
      &lt;table class="lines" cellspacing="0" cellpadding="0"&gt;
        &lt;tr&gt;
          &lt;td&gt;
            &lt;pre class="line_numbers"&gt;&lt;span rel="#L1" id="L1"&gt;1&lt;/span&gt;
&lt;span rel="#L2" id="L2"&gt;2&lt;/span&gt;
&lt;span rel="#L3" id="L3"&gt;3&lt;/span&gt;
&lt;span rel="#L4" id="L4"&gt;4&lt;/span&gt;
&lt;span rel="#L5" id="L5"&gt;5&lt;/span&gt;
&lt;span rel="#L6" id="L6"&gt;6&lt;/span&gt;
&lt;/pre&gt;
          &lt;/td&gt;
          &lt;td width="100%"&gt;
            
              
                &lt;div class="highlight"&gt;&lt;pre /&gt;&lt;div class="line" id="LC1"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;defroutes&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;public-routes&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC2"&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;GET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;/&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;main-page&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC3"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="line" id="LC4"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;defroutes&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;admin-routes&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC5"&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;GET&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;/admin/new&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;render-page&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;New Post&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;new-form&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC6"&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;POST&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;/admin/post&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;title&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;body&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;create-post&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;title&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;body&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;/pre&gt;&lt;/div&gt;
              
            
          &lt;/td&gt;
        &lt;/tr&gt;
      &lt;/table&gt;
    
  &lt;/div&gt;&lt;/p&gt;

&lt;p&gt;The admin-routes are only allowed to be accessed by logged-in users
with admin privileges.&lt;a href="http://github.com/r0man/appengine-clj"&gt;appengine-clj&lt;/a&gt;
already comes with two middleware functions that help with this:
&lt;code&gt;wrap-with-user-info&lt;/code&gt; adds references to the UserService and (if a
user is logged in) User objects from the App Engine API to each
request. &lt;code&gt;wrap-requiring-login&lt;/code&gt; checks that the user is logged in
before passing the request on to the wrapped handler &amp;ndash; if not, the
user is redirected to the login page.&lt;/p&gt;

&lt;p&gt;There&amp;rsquo;s no &lt;code&gt;wrap-requiring-admin&lt;/code&gt; (yet), so I quickly wrote it myself:&lt;/p&gt;

&lt;p&gt;&lt;div class="data type-clojure"&gt;
    
      &lt;table class="lines" cellspacing="0" cellpadding="0"&gt;
        &lt;tr&gt;
          &lt;td&gt;
            &lt;pre class="line_numbers"&gt;&lt;span rel="#L1" id="L1"&gt;1&lt;/span&gt;
&lt;span rel="#L2" id="L2"&gt;2&lt;/span&gt;
&lt;span rel="#L3" id="L3"&gt;3&lt;/span&gt;
&lt;span rel="#L4" id="L4"&gt;4&lt;/span&gt;
&lt;span rel="#L5" id="L5"&gt;5&lt;/span&gt;
&lt;span rel="#L6" id="L6"&gt;6&lt;/span&gt;
&lt;/pre&gt;
          &lt;/td&gt;
          &lt;td width="100%"&gt;
            
              
                &lt;div class="highlight"&gt;&lt;pre /&gt;&lt;div class="line" id="LC1"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;defn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;wrap-requiring-admin&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;application&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC2"&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;fn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;request&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC3"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;let&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="no"&gt;:keys&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;user-service&lt;/span&gt;&lt;span class="p"&gt;]}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;users/user-info&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;request&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC4"&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;.isUserAdmin&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;user-service&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC5"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;application&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC6"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;:status&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;403&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;:body&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Access denied. You must be logged in as admin user!&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;}))))&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;/pre&gt;&lt;/div&gt;
              
            
          &lt;/td&gt;
        &lt;/tr&gt;
      &lt;/table&gt;
    
  &lt;/div&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;wrap-requiring-admin&lt;/code&gt; depends on &lt;code&gt;wrap-requiring-login&lt;/code&gt;, which in
turn depends on &lt;code&gt;wrap-with-user-info&lt;/code&gt;, so I have to decorate my
&lt;code&gt;admin-routes&lt;/code&gt; handler with all three:&lt;/p&gt;

&lt;p&gt;&lt;div class="data type-clojure"&gt;
    
      &lt;table class="lines" cellspacing="0" cellpadding="0"&gt;
        &lt;tr&gt;
          &lt;td&gt;
            &lt;pre class="line_numbers"&gt;&lt;span rel="#L1" id="L1"&gt;1&lt;/span&gt;
&lt;span rel="#L2" id="L2"&gt;2&lt;/span&gt;
&lt;span rel="#L3" id="L3"&gt;3&lt;/span&gt;
&lt;span rel="#L4" id="L4"&gt;4&lt;/span&gt;
&lt;/pre&gt;
          &lt;/td&gt;
          &lt;td width="100%"&gt;
            
              
                &lt;div class="highlight"&gt;&lt;pre /&gt;&lt;div class="line" id="LC1"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;wrap!&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;admin-routes&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC2"&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;wrap-requiring-admin&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC3"&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;users/wrap-requiring-login&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC4"&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nv"&gt;users/wrap-with-user-info&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;/pre&gt;&lt;/div&gt;
              
            
          &lt;/td&gt;
        &lt;/tr&gt;
      &lt;/table&gt;
    
  &lt;/div&gt;&lt;/p&gt;

&lt;p&gt;Finally, the routes are combined into my main handler:&lt;/p&gt;

&lt;p&gt;&lt;div class="data type-clojure"&gt;
    
      &lt;table class="lines" cellspacing="0" cellpadding="0"&gt;
        &lt;tr&gt;
          &lt;td&gt;
            &lt;pre class="line_numbers"&gt;&lt;span rel="#L1" id="L1"&gt;1&lt;/span&gt;
&lt;span rel="#L2" id="L2"&gt;2&lt;/span&gt;
&lt;span rel="#L3" id="L3"&gt;3&lt;/span&gt;
&lt;span rel="#L4" id="L4"&gt;4&lt;/span&gt;
&lt;/pre&gt;
          &lt;/td&gt;
          &lt;td width="100%"&gt;
            
              
                &lt;div class="highlight"&gt;&lt;pre /&gt;&lt;div class="line" id="LC1"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;defroutes&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;example&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC2"&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nv"&gt;public-routes&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC3"&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;ANY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;/admin/*&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;admin-routes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC4"&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;route/not-found&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Page not found&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;/pre&gt;&lt;/div&gt;
              
            
          &lt;/td&gt;
        &lt;/tr&gt;
      &lt;/table&gt;
    
  &lt;/div&gt;&lt;/p&gt;

&lt;p&gt;Why can&amp;rsquo;t I just put &lt;code&gt;admin-routes&lt;/code&gt; in there, just like
&lt;code&gt;public-routes&lt;/code&gt;? The problem is, that the middleware I wrapped around
&lt;code&gt;admin-routes&lt;/code&gt; jumps in before the route-matching. So even if
&lt;code&gt;admin-routes&lt;/code&gt; can&amp;rsquo;t match the request URL and passes on control to
the next handler, it first makes sure that the user is logged in as an
admin. In this case, the &lt;code&gt;not-found&lt;/code&gt; handler (which always has to be
last) could only be reached by admins, all other users would have to
login and then get a 403 error when they enter a non-existing URL.
Therefor, I have to make sure that the &lt;code&gt;admin-routes&lt;/code&gt; handler is only
called for URLs starting with /admin.&lt;/p&gt;

&lt;h2&gt;Checking the users login status&lt;/h2&gt;

&lt;p&gt;So far, the new code does the same thing the old configuration did, I
haven&amp;rsquo;t won anything. So let&amp;rsquo;s make the site a little more dynamic and
change the output depending on the users login status. I changed the
sidebar to display information about the current user and login/logout
links. Also, the &amp;ldquo;Create new post&amp;rdquo; link is only shown for logged-in
admin users:&lt;/p&gt;

&lt;p&gt;&lt;div class="data type-clojure"&gt;
    
      &lt;table class="lines" cellspacing="0" cellpadding="0"&gt;
        &lt;tr&gt;
          &lt;td&gt;
            &lt;pre class="line_numbers"&gt;&lt;span rel="#L1" id="L1"&gt;1&lt;/span&gt;
&lt;span rel="#L2" id="L2"&gt;2&lt;/span&gt;
&lt;span rel="#L3" id="L3"&gt;3&lt;/span&gt;
&lt;span rel="#L4" id="L4"&gt;4&lt;/span&gt;
&lt;span rel="#L5" id="L5"&gt;5&lt;/span&gt;
&lt;span rel="#L6" id="L6"&gt;6&lt;/span&gt;
&lt;span rel="#L7" id="L7"&gt;7&lt;/span&gt;
&lt;span rel="#L8" id="L8"&gt;8&lt;/span&gt;
&lt;span rel="#L9" id="L9"&gt;9&lt;/span&gt;
&lt;span rel="#L10" id="L10"&gt;10&lt;/span&gt;
&lt;span rel="#L11" id="L11"&gt;11&lt;/span&gt;
&lt;span rel="#L12" id="L12"&gt;12&lt;/span&gt;
&lt;span rel="#L13" id="L13"&gt;13&lt;/span&gt;
&lt;span rel="#L14" id="L14"&gt;14&lt;/span&gt;
&lt;span rel="#L15" id="L15"&gt;15&lt;/span&gt;
&lt;span rel="#L16" id="L16"&gt;16&lt;/span&gt;
&lt;span rel="#L17" id="L17"&gt;17&lt;/span&gt;
&lt;span rel="#L18" id="L18"&gt;18&lt;/span&gt;
&lt;span rel="#L19" id="L19"&gt;19&lt;/span&gt;
&lt;span rel="#L20" id="L20"&gt;20&lt;/span&gt;
&lt;span rel="#L21" id="L21"&gt;21&lt;/span&gt;
&lt;/pre&gt;
          &lt;/td&gt;
          &lt;td width="100%"&gt;
            
              
                &lt;div class="highlight"&gt;&lt;pre /&gt;&lt;div class="line" id="LC1"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;defn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;side-bar&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC2"&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;let&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;ui&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;users/user-info&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC3"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="no"&gt;:div&lt;/span&gt;&lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="nv"&gt;sidebar&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC4"&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="no"&gt;:h3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Current User&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC5"&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;if-let&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;user&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;:user&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;ui&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC6"&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="no"&gt;:ul&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC7"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="no"&gt;:li&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Logged in as &amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;.getEmail&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC8"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="no"&gt;:li&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;link-to&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;.createLogoutURL&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;:user-service&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;ui&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;/&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Logout&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)]]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC9"&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="no"&gt;:ul&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC10"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="no"&gt;:li&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Not logged in&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC11"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="no"&gt;:li&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;link-to&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;.createLoginURL&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;:user-service&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;ui&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;/&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Login&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)]]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC12"&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC13"&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="no"&gt;:h3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Navigation&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC14"&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="no"&gt;:ul&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC15"&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="no"&gt;:li&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;link-to&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;/&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Main page&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC16"&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;and&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;:user&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;ui&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;.isUserAdmin&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;:user-service&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;ui&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC17"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="no"&gt;:li&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;link-to&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;/admin/new&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Create new post (Admin only)&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)])]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC18"&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="no"&gt;:h3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;External Links&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC19"&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="no"&gt;:ul&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC20"&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="no"&gt;:li&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;link-to&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;http://compojureongae.posterous.com/&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Blog&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC21"&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="no"&gt;:li&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;link-to&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;http://github.com/christianberg/compojureongae&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Source Code&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)]]]))&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;/pre&gt;&lt;/div&gt;
              
            
          &lt;/td&gt;
        &lt;/tr&gt;
      &lt;/table&gt;
    
  &lt;/div&gt;&lt;/p&gt;

&lt;p&gt;(Note that &lt;code&gt;side-bar&lt;/code&gt; now is a function, since the content is dynamic.)&lt;/p&gt;

&lt;p&gt;I&amp;rsquo;ve achieved my goals: I can login and logout and I only see the
links I&amp;rsquo;m allowed to click. I can run this code using the local
dev_server and I can deploy it to the Google servers (see my &lt;a href="http://compojureongae.posterous.com/deploying-to-app-engine"&gt;previous
post&lt;/a&gt; on
how to do this).&lt;/p&gt;

&lt;p&gt;But in the interactive development environment I set up in my &lt;a href="http://compojureongae.posterous.com/getting-interactive-development-to-work-again"&gt;last
post&lt;/a&gt;,
nothing works! I&amp;rsquo;m always logged out and the login link is broken.
Let&amp;rsquo;s fix that.&lt;/p&gt;

&lt;h2&gt;Making logins work in interactive development&lt;/h2&gt;

&lt;p&gt;The local implementation of the App Engine Users API calls an instance
of &lt;code&gt;ApiProxy$Environment&lt;/code&gt;, which I have to provide, to figure out if a
user is logged in. In my last post, I set up a very minimal proxy,
that always answers this question with &amp;ldquo;no&amp;rdquo;. Here&amp;rsquo;s the relevant
snippet:&lt;/p&gt;

&lt;p&gt;&lt;div class="data type-clojure"&gt;
      &lt;table class="lines" cellspacing="0" cellpadding="0"&gt;
        &lt;tr&gt;
          &lt;td&gt;
            &lt;pre class="line_numbers"&gt;&lt;span rel="#L1" id="L1"&gt;1&lt;/span&gt;
&lt;span rel="#L2" id="L2"&gt;2&lt;/span&gt;
&lt;span rel="#L3" id="L3"&gt;3&lt;/span&gt;
&lt;span rel="#L4" id="L4"&gt;4&lt;/span&gt;
&lt;span rel="#L5" id="L5"&gt;5&lt;/span&gt;
&lt;span rel="#L6" id="L6"&gt;6&lt;/span&gt;
&lt;/pre&gt;
          &lt;/td&gt;
          &lt;td width="100%"&gt;
                &lt;div class="highlight"&gt;&lt;pre /&gt;&lt;div class="line" id="LC1"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nv"&gt;env-proxy&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;proxy&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;ApiProxy$Environment&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC2"&gt;&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;isLoggedIn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC3"&gt;&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;getRequestNamespace&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC4"&gt;&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;getDefaultNamespace&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC5"&gt;&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;getAttributes&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;att&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC6"&gt;&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;getAppId&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;_local_&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;/pre&gt;&lt;/div&gt;
          &lt;/td&gt;
        &lt;/tr&gt;
      &lt;/table&gt;
  &lt;/div&gt;&lt;/p&gt;

&lt;p&gt;This needs to be smarter. I decided to store information about the
current user globally in an atom. Of course, this implies that the
server can only be used by one user at a time &amp;ndash; for a production
system this would be an incredibly stupid implementation, for local
development I think it&amp;rsquo;s ok. Other options would be to store the login
information in session variables or directly in a cookie. Storing it
globally has the advantage, though,  that I can easily view and modify
the current login state from the REPL, which eases debugging (plus
it&amp;rsquo;s simple to implement!).&lt;/p&gt;

&lt;p&gt;Here&amp;rsquo;s the definition of the atom holding the login information,
prefilled with some reasonable default values:&lt;/p&gt;

&lt;p&gt;&lt;div class="data type-clojure"&gt;
    
      &lt;table class="lines" cellspacing="0" cellpadding="0"&gt;
        &lt;tr&gt;
          &lt;td&gt;
            &lt;pre class="line_numbers"&gt;&lt;span rel="#L1" id="L1"&gt;1&lt;/span&gt;
&lt;span rel="#L2" id="L2"&gt;2&lt;/span&gt;
&lt;span rel="#L3" id="L3"&gt;3&lt;/span&gt;
&lt;span rel="#L4" id="L4"&gt;4&lt;/span&gt;
&lt;/pre&gt;
          &lt;/td&gt;
          &lt;td width="100%"&gt;
            
              
                &lt;div class="highlight"&gt;&lt;pre /&gt;&lt;div class="line" id="LC1"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;login-info&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;atom&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;:logged-in?&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;false&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC2"&gt;&lt;span class="w"&gt;                       &lt;/span&gt;&lt;span class="no"&gt;:admin?&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;false&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC3"&gt;&lt;span class="w"&gt;                       &lt;/span&gt;&lt;span class="no"&gt;:email&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC4"&gt;&lt;span class="w"&gt;                       &lt;/span&gt;&lt;span class="no"&gt;:auth-domain&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;}))&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;/pre&gt;&lt;/div&gt;
              
            
          &lt;/td&gt;
        &lt;/tr&gt;
      &lt;/table&gt;
    
  &lt;/div&gt;&lt;/p&gt;

&lt;p&gt;The updated Environment proxy just reads from the atom:&lt;/p&gt;

&lt;p&gt;&lt;div class="data type-clojure"&gt;
    
      &lt;table class="lines" cellspacing="0" cellpadding="0"&gt;
        &lt;tr&gt;
          &lt;td&gt;
            &lt;pre class="line_numbers"&gt;&lt;span rel="#L1" id="L1"&gt;1&lt;/span&gt;
&lt;span rel="#L2" id="L2"&gt;2&lt;/span&gt;
&lt;span rel="#L3" id="L3"&gt;3&lt;/span&gt;
&lt;span rel="#L4" id="L4"&gt;4&lt;/span&gt;
&lt;span rel="#L5" id="L5"&gt;5&lt;/span&gt;
&lt;span rel="#L6" id="L6"&gt;6&lt;/span&gt;
&lt;span rel="#L7" id="L7"&gt;7&lt;/span&gt;
&lt;span rel="#L8" id="L8"&gt;8&lt;/span&gt;
&lt;span rel="#L9" id="L9"&gt;9&lt;/span&gt;
&lt;span rel="#L10" id="L10"&gt;10&lt;/span&gt;
&lt;span rel="#L11" id="L11"&gt;11&lt;/span&gt;
&lt;span rel="#L12" id="L12"&gt;12&lt;/span&gt;
&lt;span rel="#L13" id="L13"&gt;13&lt;/span&gt;
&lt;span rel="#L14" id="L14"&gt;14&lt;/span&gt;
&lt;/pre&gt;
          &lt;/td&gt;
          &lt;td width="100%"&gt;
            
              
                &lt;div class="highlight"&gt;&lt;pre /&gt;&lt;div class="line" id="LC1"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;defn-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;set-app-engine-environment&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC2"&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Sets up the App Engine environment for the current thread.&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC3"&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;let&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;att&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;HashMap.&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;com.google.appengine.server_url_key&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC4"&gt;&lt;span class="w"&gt;                       &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;http://localhost:&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;*port*&lt;/span&gt;&lt;span class="p"&gt;)})&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC5"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nv"&gt;env-proxy&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;proxy&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;ApiProxy$Environment&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC6"&gt;&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;isLoggedIn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;:logged-in?&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="nv"&gt;login-info&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC7"&gt;&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;getEmail&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;:email&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="nv"&gt;login-info&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC8"&gt;&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;getAuthDomain&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;:auth-domain&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="nv"&gt;login-info&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC9"&gt;&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;isAdmin&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;:admin?&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="nv"&gt;login-info&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC10"&gt;&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;getRequestNamespace&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC11"&gt;&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;getDefaultNamespace&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC12"&gt;&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;getAttributes&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;att&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC13"&gt;&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;getAppId&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;_local_&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;))]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC14"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;ApiProxy/setEnvironmentForCurrentThread&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;env-proxy&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;/pre&gt;&lt;/div&gt;
              
            
          &lt;/td&gt;
        &lt;/tr&gt;
      &lt;/table&gt;
    
  &lt;/div&gt;&lt;/p&gt;

&lt;p&gt;I added two helper functions to easily modify the atom:&lt;/p&gt;

&lt;p&gt;&lt;div class="data type-clojure"&gt;
      &lt;table class="lines" cellspacing="0" cellpadding="0"&gt;
        &lt;tr&gt;
          &lt;td&gt;
            &lt;pre class="line_numbers"&gt;&lt;span rel="#L1" id="L1"&gt;1&lt;/span&gt;
&lt;span rel="#L2" id="L2"&gt;2&lt;/span&gt;
&lt;span rel="#L3" id="L3"&gt;3&lt;/span&gt;
&lt;span rel="#L4" id="L4"&gt;4&lt;/span&gt;
&lt;span rel="#L5" id="L5"&gt;5&lt;/span&gt;
&lt;span rel="#L6" id="L6"&gt;6&lt;/span&gt;
&lt;span rel="#L7" id="L7"&gt;7&lt;/span&gt;
&lt;span rel="#L8" id="L8"&gt;8&lt;/span&gt;
&lt;span rel="#L9" id="L9"&gt;9&lt;/span&gt;
&lt;span rel="#L10" id="L10"&gt;10&lt;/span&gt;
&lt;/pre&gt;
          &lt;/td&gt;
          &lt;td width="100%"&gt;
                &lt;div class="highlight"&gt;&lt;pre /&gt;&lt;div class="line" id="LC1"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;defn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;login&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC2"&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nv"&gt;email&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;login&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;email&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;false&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC3"&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nv"&gt;email&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;admin?&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;swap!&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;login-info&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;merge&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;:email&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;email&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC4"&gt;&lt;span class="w"&gt;                                           &lt;/span&gt;&lt;span class="no"&gt;:logged-in?&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;true&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC5"&gt;&lt;span class="w"&gt;                                           &lt;/span&gt;&lt;span class="no"&gt;:admin?&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;admin?&lt;/span&gt;&lt;span class="p"&gt;})))&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC6"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="line" id="LC7"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;defn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;logout&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC8"&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;swap!&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;login-info&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;merge&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;:email&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC9"&gt;&lt;span class="w"&gt;                           &lt;/span&gt;&lt;span class="no"&gt;:logged-in?&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;false&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC10"&gt;&lt;span class="w"&gt;                           &lt;/span&gt;&lt;span class="no"&gt;:admin?&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;false&lt;/span&gt;&lt;span class="p"&gt;}))&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;/pre&gt;&lt;/div&gt;
          &lt;/td&gt;
        &lt;/tr&gt;
      &lt;/table&gt;
  &lt;/div&gt;&lt;/p&gt;

&lt;p&gt;Now I can login and logout by calling the functions from the REPL and
the pages served by my Jetty server immediately reflect this. But the
login and logout links are still broken. I need to define handlers for
these:&lt;/p&gt;

&lt;p&gt;&lt;div class="data type-clojure"&gt;
      &lt;table class="lines" cellspacing="0" cellpadding="0"&gt;
        &lt;tr&gt;
          &lt;td&gt;
            &lt;pre class="line_numbers"&gt;&lt;span rel="#L1" id="L1"&gt;1&lt;/span&gt;
&lt;span rel="#L2" id="L2"&gt;2&lt;/span&gt;
&lt;span rel="#L3" id="L3"&gt;3&lt;/span&gt;
&lt;span rel="#L4" id="L4"&gt;4&lt;/span&gt;
&lt;span rel="#L5" id="L5"&gt;5&lt;/span&gt;
&lt;span rel="#L6" id="L6"&gt;6&lt;/span&gt;
&lt;span rel="#L7" id="L7"&gt;7&lt;/span&gt;
&lt;span rel="#L8" id="L8"&gt;8&lt;/span&gt;
&lt;/pre&gt;
          &lt;/td&gt;
          &lt;td width="100%"&gt;
                &lt;div class="highlight"&gt;&lt;pre /&gt;&lt;div class="line" id="LC1"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;defroutes&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;login-routes&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC2"&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;GET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;/_ah/login&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;continue&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;login-form&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;continue&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC3"&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;POST&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;/_ah/login&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;action&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;email&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;isAdmin&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;continue&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;do&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;action&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Log In&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC4"&gt;&lt;span class="w"&gt;                                                           &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;login&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;email&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;boolean&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;isAdmin&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC5"&gt;&lt;span class="w"&gt;                                                           &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;logout&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC6"&gt;&lt;span class="w"&gt;                                                         &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;redirect&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;continue&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC7"&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;GET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;/_ah/logout&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;continue&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;do&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;logout&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC8"&gt;&lt;span class="w"&gt;                                    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;redirect&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;continue&lt;/span&gt;&lt;span class="p"&gt;))))&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;/pre&gt;&lt;/div&gt;
          &lt;/td&gt;
        &lt;/tr&gt;
      &lt;/table&gt;
  &lt;/div&gt;&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;login-form&lt;/code&gt; function just builds an exact copy of the login page
provided by the Google dev_server.&lt;/p&gt;

&lt;p&gt;Last but not least, I have to update the &lt;code&gt;start-server&lt;/code&gt; function to
combine these handlers with my app (the change is in line 9):&lt;/p&gt;

&lt;p&gt;&lt;div class="data type-clojure"&gt;
      &lt;table class="lines" cellspacing="0" cellpadding="0"&gt;
        &lt;tr&gt;
          &lt;td&gt;
            &lt;pre class="line_numbers"&gt;&lt;span rel="#L1" id="L1"&gt;1&lt;/span&gt;
&lt;span rel="#L2" id="L2"&gt;2&lt;/span&gt;
&lt;span rel="#L3" id="L3"&gt;3&lt;/span&gt;
&lt;span rel="#L4" id="L4"&gt;4&lt;/span&gt;
&lt;span rel="#L5" id="L5"&gt;5&lt;/span&gt;
&lt;span rel="#L6" id="L6"&gt;6&lt;/span&gt;
&lt;span rel="#L7" id="L7"&gt;7&lt;/span&gt;
&lt;span rel="#L8" id="L8"&gt;8&lt;/span&gt;
&lt;span rel="#L9" id="L9"&gt;9&lt;/span&gt;
&lt;span rel="#L10" id="L10"&gt;10&lt;/span&gt;
&lt;span rel="#L11" id="L11"&gt;11&lt;/span&gt;
&lt;span rel="#L12" id="L12"&gt;12&lt;/span&gt;
&lt;span rel="#L13" id="L13"&gt;13&lt;/span&gt;
&lt;span rel="#L14" id="L14"&gt;14&lt;/span&gt;
&lt;/pre&gt;
          &lt;/td&gt;
          &lt;td width="100%"&gt;
                &lt;div class="highlight"&gt;&lt;pre /&gt;&lt;div class="line" id="LC1"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;defn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;start-server&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;app&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC2"&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Initializes the App Engine services and (re-)starts a Jetty server&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC3"&gt;&lt;span class="s"&gt;   running the supplied ring app, wrapping it to enable App Engine API use&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC4"&gt;&lt;span class="s"&gt;   and serving of static files.&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC5"&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;set-app-engine-delegate&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;/tmp&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC6"&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;swap!&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;*server*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;fn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC7"&gt;&lt;span class="w"&gt;                   &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;when&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;instance&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC8"&gt;&lt;span class="w"&gt;                     &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;.stop&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC9"&gt;&lt;span class="w"&gt;                   &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;let&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;app&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;routes&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;login-routes&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;app&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC10"&gt;&lt;span class="w"&gt;                                 &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;wrap-local-app-engine&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC11"&gt;&lt;span class="w"&gt;                                 &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;wrap-file&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;./war&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC12"&gt;&lt;span class="w"&gt;                                 &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;wrap-file-info&lt;/span&gt;&lt;span class="p"&gt;))]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC13"&gt;&lt;span class="w"&gt;                     &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;run-jetty&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;app&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;:port&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;*port*&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC14"&gt;&lt;span class="w"&gt;                                     &lt;/span&gt;&lt;span class="no"&gt;:join?&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;false&lt;/span&gt;&lt;span class="p"&gt;})))))&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;/pre&gt;&lt;/div&gt;
          &lt;/td&gt;
        &lt;/tr&gt;
      &lt;/table&gt;
  &lt;/div&gt;&lt;/p&gt;

&lt;p&gt;That&amp;rsquo;s all &amp;ndash; a functioning local implementation of the Users API
complete with working login page. I hope you enjoy it!&lt;/p&gt;

&lt;p&gt;As always, the complete source code can be found on
&lt;a href="http://github.com/christianberg/compojureongae"&gt;Github&lt;/a&gt;, the version
as of this writing is
&lt;a href="http://github.com/christianberg/compojureongae/tree/v0.3.0"&gt;here&lt;/a&gt;.
You can see the deployed app
&lt;a href="http://v0-3.latest.compojureongae.appspot.com/"&gt;here&lt;/a&gt; (of course I&amp;rsquo;m
the only admin user, so you might want to try it locally to see the
full functionality&amp;hellip;). Questions and suggestions are very welcome in
the comments below!&lt;/p&gt;
	
&lt;/p&gt;

&lt;p&gt;&lt;a href="http://compojureongae.posterous.com/using-the-app-engine-users-api-from-clojure"&gt;Permalink&lt;/a&gt; 

	| &lt;a href="http://compojureongae.posterous.com/using-the-app-engine-users-api-from-clojure#comment"&gt;Leave a comment&amp;nbsp;&amp;nbsp;&amp;raquo;&lt;/a&gt;

&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/CompojureOnGAE/~4/HupkuzWmQs0" height="1" width="1"/&gt;</description>
      <posterous:author>
        <posterous:userImage>http://files.posterous.com/user_profile_pics/548315/gravatar.jpeg</posterous:userImage>
        <posterous:profileUrl>http://posterous.com/users/1bbRpyByNcB</posterous:profileUrl>
        <posterous:firstName>Christian</posterous:firstName>
        <posterous:lastName>Berg</posterous:lastName>
        <posterous:nickName>Christian</posterous:nickName>
        <posterous:displayName>Christian Berg</posterous:displayName>
      </posterous:author>
    <feedburner:origLink>http://compojureongae.posterous.com/using-the-app-engine-users-api-from-clojure</feedburner:origLink></item>
    <item>
      <pubDate>Fri, 04 Jun 2010 04:55:00 -0700</pubDate>
      <title>Getting interactive development to work (again)</title>
      <link>http://feedproxy.google.com/~r/CompojureOnGAE/~3/8HUupoQolqs/getting-interactive-development-to-work-again</link>
      <guid isPermaLink="false">http://compojureongae.posterous.com/getting-interactive-development-to-work-again</guid>
      <description>&lt;p&gt;
	&lt;p&gt;In my &lt;a href="http://compojureongae.posterous.com/accessing-the-app-engine-datastore"&gt;last post&lt;/a&gt;,
I promised to fix my local development setup to enable the interactive
development style typical for Clojure and make the App Engine services
(such as the datastore) available from the REPL.&lt;/p&gt;

&lt;p&gt;Others have already tackled the same problem. The best resource I
found is the &lt;a href="http://www.hackers-with-attitude.com/2010/04/clojure-google-app-engine-setup-update.html"&gt;hackers with attitude
blog&lt;/a&gt;,
another one is &lt;a href="http://carpathia.blogspot.com/2010/05/yet-another-clojure-compojure-google.html"&gt;here&lt;/a&gt;.
My code is largely based on these contributions, I rolled my own
version mainly to get a better understanding of the setup.&lt;/p&gt;

&lt;h2&gt;Initializing the App Engine services&lt;/h2&gt;

&lt;p&gt;To use the App Engine APIs outside of the Google servers, a local
ApiProxy and Environment needs to be provided. While the ApiProxy
needs to be initialized only once per JVM, the Environment needs to be
set for every thread on which API calls are made. This is trivial for
the REPL, which runs in one thread. It&amp;rsquo;s a bit more work when you want
to run a local Jetty server, since it spawns new threads for handling
requests. Fortunately, the design of Ring makes it easy to add
so-called middleware to an existing web app that can handle the
environment setup.&lt;/p&gt;

&lt;p&gt;Enough said, here&amp;rsquo;s the code. I&amp;rsquo;ll go through it def by def below.&lt;/p&gt;

&lt;p&gt;&lt;div class="data type-clojure"&gt;
      &lt;table class="lines" cellspacing="0" cellpadding="0"&gt;
        &lt;tr&gt;
          &lt;td&gt;
            &lt;pre class="line_numbers"&gt;&lt;span rel="#L1" id="L1"&gt;1&lt;/span&gt;
&lt;span rel="#L2" id="L2"&gt;2&lt;/span&gt;
&lt;span rel="#L3" id="L3"&gt;3&lt;/span&gt;
&lt;span rel="#L4" id="L4"&gt;4&lt;/span&gt;
&lt;span rel="#L5" id="L5"&gt;5&lt;/span&gt;
&lt;span rel="#L6" id="L6"&gt;6&lt;/span&gt;
&lt;span rel="#L7" id="L7"&gt;7&lt;/span&gt;
&lt;span rel="#L8" id="L8"&gt;8&lt;/span&gt;
&lt;span rel="#L9" id="L9"&gt;9&lt;/span&gt;
&lt;span rel="#L10" id="L10"&gt;10&lt;/span&gt;
&lt;span rel="#L11" id="L11"&gt;11&lt;/span&gt;
&lt;span rel="#L12" id="L12"&gt;12&lt;/span&gt;
&lt;span rel="#L13" id="L13"&gt;13&lt;/span&gt;
&lt;span rel="#L14" id="L14"&gt;14&lt;/span&gt;
&lt;span rel="#L15" id="L15"&gt;15&lt;/span&gt;
&lt;span rel="#L16" id="L16"&gt;16&lt;/span&gt;
&lt;span rel="#L17" id="L17"&gt;17&lt;/span&gt;
&lt;span rel="#L18" id="L18"&gt;18&lt;/span&gt;
&lt;span rel="#L19" id="L19"&gt;19&lt;/span&gt;
&lt;span rel="#L20" id="L20"&gt;20&lt;/span&gt;
&lt;span rel="#L21" id="L21"&gt;21&lt;/span&gt;
&lt;span rel="#L22" id="L22"&gt;22&lt;/span&gt;
&lt;span rel="#L23" id="L23"&gt;23&lt;/span&gt;
&lt;span rel="#L24" id="L24"&gt;24&lt;/span&gt;
&lt;span rel="#L25" id="L25"&gt;25&lt;/span&gt;
&lt;span rel="#L26" id="L26"&gt;26&lt;/span&gt;
&lt;span rel="#L27" id="L27"&gt;27&lt;/span&gt;
&lt;span rel="#L28" id="L28"&gt;28&lt;/span&gt;
&lt;span rel="#L29" id="L29"&gt;29&lt;/span&gt;
&lt;span rel="#L30" id="L30"&gt;30&lt;/span&gt;
&lt;span rel="#L31" id="L31"&gt;31&lt;/span&gt;
&lt;span rel="#L32" id="L32"&gt;32&lt;/span&gt;
&lt;span rel="#L33" id="L33"&gt;33&lt;/span&gt;
&lt;span rel="#L34" id="L34"&gt;34&lt;/span&gt;
&lt;span rel="#L35" id="L35"&gt;35&lt;/span&gt;
&lt;span rel="#L36" id="L36"&gt;36&lt;/span&gt;
&lt;span rel="#L37" id="L37"&gt;37&lt;/span&gt;
&lt;span rel="#L38" id="L38"&gt;38&lt;/span&gt;
&lt;span rel="#L39" id="L39"&gt;39&lt;/span&gt;
&lt;span rel="#L40" id="L40"&gt;40&lt;/span&gt;
&lt;span rel="#L41" id="L41"&gt;41&lt;/span&gt;
&lt;span rel="#L42" id="L42"&gt;42&lt;/span&gt;
&lt;span rel="#L43" id="L43"&gt;43&lt;/span&gt;
&lt;span rel="#L44" id="L44"&gt;44&lt;/span&gt;
&lt;span rel="#L45" id="L45"&gt;45&lt;/span&gt;
&lt;span rel="#L46" id="L46"&gt;46&lt;/span&gt;
&lt;span rel="#L47" id="L47"&gt;47&lt;/span&gt;
&lt;span rel="#L48" id="L48"&gt;48&lt;/span&gt;
&lt;span rel="#L49" id="L49"&gt;49&lt;/span&gt;
&lt;span rel="#L50" id="L50"&gt;50&lt;/span&gt;
&lt;span rel="#L51" id="L51"&gt;51&lt;/span&gt;
&lt;span rel="#L52" id="L52"&gt;52&lt;/span&gt;
&lt;span rel="#L53" id="L53"&gt;53&lt;/span&gt;
&lt;span rel="#L54" id="L54"&gt;54&lt;/span&gt;
&lt;span rel="#L55" id="L55"&gt;55&lt;/span&gt;
&lt;span rel="#L56" id="L56"&gt;56&lt;/span&gt;
&lt;span rel="#L57" id="L57"&gt;57&lt;/span&gt;
&lt;span rel="#L58" id="L58"&gt;58&lt;/span&gt;
&lt;span rel="#L59" id="L59"&gt;59&lt;/span&gt;
&lt;span rel="#L60" id="L60"&gt;60&lt;/span&gt;
&lt;span rel="#L61" id="L61"&gt;61&lt;/span&gt;
&lt;span rel="#L62" id="L62"&gt;62&lt;/span&gt;
&lt;span rel="#L63" id="L63"&gt;63&lt;/span&gt;
&lt;span rel="#L64" id="L64"&gt;64&lt;/span&gt;
&lt;span rel="#L65" id="L65"&gt;65&lt;/span&gt;
&lt;span rel="#L66" id="L66"&gt;66&lt;/span&gt;
&lt;span rel="#L67" id="L67"&gt;67&lt;/span&gt;
&lt;span rel="#L68" id="L68"&gt;68&lt;/span&gt;
&lt;span rel="#L69" id="L69"&gt;69&lt;/span&gt;
&lt;span rel="#L70" id="L70"&gt;70&lt;/span&gt;
&lt;span rel="#L71" id="L71"&gt;71&lt;/span&gt;
&lt;/pre&gt;
          &lt;/td&gt;
          &lt;td width="100%"&gt;
                &lt;div class="highlight"&gt;&lt;pre /&gt;&lt;div class="line" id="LC1"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;ns&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;local-dev&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC2"&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Tools for local development.&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC3"&gt;&lt;span class="s"&gt;   Enables the use of the App Engine APIs on the REPL and in a local Jetty instance.&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC4"&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;:use&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;ring.adapter.jetty&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC5"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;ring.middleware&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;file&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;file-info&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC6"&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;:import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;java.io&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;File&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC7"&gt;&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;java.util&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;HashMap&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC8"&gt;&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;com.google.apphosting.api&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;ApiProxy&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;ApiProxy$Environment&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC9"&gt;&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;com.google.appengine.tools.development&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC10"&gt;&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nv"&gt;ApiProxyLocalFactory&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC11"&gt;&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nv"&gt;LocalServerEnvironment&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC12"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="line" id="LC13"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;defonce&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;*server*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;atom&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC14"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;*port*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;8181&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC15"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="line" id="LC16"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;defn-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;set-app-engine-environment&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC17"&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Sets up the App Engine environment for the current thread.&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC18"&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;let&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;att&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;HashMap.&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;com.google.appengine.server_url_key&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC19"&gt;&lt;span class="w"&gt;                       &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;http://localhost:&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;*port*&lt;/span&gt;&lt;span class="p"&gt;)})&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC20"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nv"&gt;env-proxy&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;proxy&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;ApiProxy$Environment&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC21"&gt;&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;isLoggedIn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC22"&gt;&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;getRequestNamespace&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC23"&gt;&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;getDefaultNamespace&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC24"&gt;&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;getAttributes&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;att&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC25"&gt;&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;getAppId&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;_local_&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;))]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC26"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;ApiProxy/setEnvironmentForCurrentThread&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;env-proxy&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC27"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="line" id="LC28"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;defn-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;set-app-engine-delegate&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;dir&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC29"&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Initializes the App Engine services. Needs to be run (at least) per JVM.&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC30"&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;let&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;local-env&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;proxy&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;LocalServerEnvironment&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC31"&gt;&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;getAppDir&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;File.&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;dir&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC32"&gt;&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;getAddress&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;localhost&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC33"&gt;&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;getPort&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;*port*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC34"&gt;&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;waitForServerToStart&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC35"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nv"&gt;api-proxy&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;.create&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;ApiProxyLocalFactory.&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC36"&gt;&lt;span class="w"&gt;                           &lt;/span&gt;&lt;span class="nv"&gt;local-env&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC37"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;ApiProxy/setDelegate&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;api-proxy&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC38"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="line" id="LC39"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;defn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;init-app-engine&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC40"&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Initializes the App Engine services and sets up the environment. To be called from the REPL.&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC41"&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;init-app-engine&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;/tmp&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC42"&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nv"&gt;dir&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC43"&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;set-app-engine-delegate&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;dir&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC44"&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;set-app-engine-environment&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC45"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="line" id="LC46"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;defn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;wrap-local-app-engine&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;app&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC47"&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Wraps a ring app to enable the use of App Engine Services.&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC48"&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;fn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;req&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC49"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;set-app-engine-environment&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC50"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;app&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;req&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC51"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="line" id="LC52"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;defn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;start-server&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;app&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC53"&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Initializes the App Engine services and (re-)starts a Jetty server&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC54"&gt;&lt;span class="s"&gt;   running the supplied ring app, wrapping it to enable App Engine API use&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC55"&gt;&lt;span class="s"&gt;   and serving of static files.&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC56"&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;set-app-engine-delegate&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;/tmp&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC57"&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;swap!&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;*server*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;fn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC58"&gt;&lt;span class="w"&gt;                   &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;when&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;instance&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC59"&gt;&lt;span class="w"&gt;                     &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;.stop&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC60"&gt;&lt;span class="w"&gt;                   &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;let&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;app&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;app&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC61"&gt;&lt;span class="w"&gt;                                 &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;wrap-local-app-engine&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC62"&gt;&lt;span class="w"&gt;                                 &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;wrap-file&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;./war&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC63"&gt;&lt;span class="w"&gt;                                 &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;wrap-file-info&lt;/span&gt;&lt;span class="p"&gt;))]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC64"&gt;&lt;span class="w"&gt;                     &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;run-jetty&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;app&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;:port&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;*port*&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC65"&gt;&lt;span class="w"&gt;                                     &lt;/span&gt;&lt;span class="no"&gt;:join?&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;false&lt;/span&gt;&lt;span class="p"&gt;})))))&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC66"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="line" id="LC67"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;defn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;stop-server&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC68"&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Stops the local Jetty server.&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC69"&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;swap!&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;*server*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;when&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;%&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;.stop&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;%&lt;/span&gt;&lt;span class="p"&gt;))))&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC70"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="line" id="LC71"&gt;&lt;br /&gt;&lt;/div&gt;&lt;/pre&gt;&lt;/div&gt;
          &lt;/td&gt;
        &lt;/tr&gt;
      &lt;/table&gt;
  &lt;/div&gt;&lt;/p&gt;

&lt;p&gt;The code is in a separate namespace, so it doesn&amp;rsquo;t get AOT-compiled
and deployed with the rest of the app. I&amp;rsquo;m using an atom to store the
Jetty server instance. Using &lt;code&gt;defonce&lt;/code&gt; was helpful while developing
this, because I could recompile the file (&lt;code&gt;C-c C-k&lt;/code&gt; in Emacs) without
losing the reference to the running Jetty server.&lt;/p&gt;

&lt;p&gt;The two functions &lt;code&gt;set-app-engine-environment&lt;/code&gt; and
&lt;code&gt;set-app-engine-delegate&lt;/code&gt; do the necessary setup work on the
per-thread and per-jvm basis, respectively.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;init-app-engine&lt;/code&gt; just calls these two functions. It&amp;rsquo;s intended to be
called from the REPL, after which you&amp;rsquo;re able to use API calls like
&lt;code&gt;create-entity&lt;/code&gt; in the REPL.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;wrap-local-app-engine&lt;/code&gt; is a Ring middleware that sets the environment
for the current thread before passing the request on to the wrapped
Ring (or Compojure) app.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;start-server&lt;/code&gt; function takes a Ring app, does the per-JVM setup,
wraps the app with the middleware for the per-thread setup and starts
a Jetty server running the app. If there already is a Jetty server
stored in the atom, it is stopped first, so you can use the function
to restart the Jetty as well. The &lt;code&gt;:join? false&lt;/code&gt; argument is
important, otherwise the call to &lt;code&gt;run-jetty&lt;/code&gt; will not return.&lt;/p&gt;

&lt;p&gt;I also added the &lt;code&gt;wrap-file&lt;/code&gt; middleware to serve static files (and
&lt;code&gt;wrap-file-info&lt;/code&gt; to add Content-Type and Content-Length headers). This
mimics the behaviour of the Google servers, which by default serve all
files included in the war directory. (Note that, unlike the Google
servers, this setup also serves the files in the WEB-INF directory. In
a production system that would be a security concern, for local
development I don&amp;rsquo;t mind.)&lt;/p&gt;

&lt;p&gt;Last (and also least interesting), the &lt;code&gt;stop-server&lt;/code&gt; function stops
the Jetty server (and sets the atom back to nil).&lt;/p&gt;

&lt;h2&gt;Setting up the classpath&lt;/h2&gt;

&lt;p&gt;To use the local API implementations we need some additional jars on
the classpath. Here&amp;rsquo;s the updated project.clj:&lt;/p&gt;

&lt;p&gt;&lt;div class="data type-clojure"&gt;
      &lt;table class="lines" cellspacing="0" cellpadding="0"&gt;
        &lt;tr&gt;
          &lt;td&gt;
            &lt;pre class="line_numbers"&gt;&lt;span rel="#L1" id="L1"&gt;1&lt;/span&gt;
&lt;span rel="#L2" id="L2"&gt;2&lt;/span&gt;
&lt;span rel="#L3" id="L3"&gt;3&lt;/span&gt;
&lt;span rel="#L4" id="L4"&gt;4&lt;/span&gt;
&lt;span rel="#L5" id="L5"&gt;5&lt;/span&gt;
&lt;span rel="#L6" id="L6"&gt;6&lt;/span&gt;
&lt;span rel="#L7" id="L7"&gt;7&lt;/span&gt;
&lt;span rel="#L8" id="L8"&gt;8&lt;/span&gt;
&lt;span rel="#L9" id="L9"&gt;9&lt;/span&gt;
&lt;span rel="#L10" id="L10"&gt;10&lt;/span&gt;
&lt;span rel="#L11" id="L11"&gt;11&lt;/span&gt;
&lt;span rel="#L12" id="L12"&gt;12&lt;/span&gt;
&lt;span rel="#L13" id="L13"&gt;13&lt;/span&gt;
&lt;span rel="#L14" id="L14"&gt;14&lt;/span&gt;
&lt;span rel="#L15" id="L15"&gt;15&lt;/span&gt;
&lt;/pre&gt;
          &lt;/td&gt;
          &lt;td width="100%"&gt;
                &lt;div class="highlight"&gt;&lt;pre /&gt;&lt;div class="line" id="LC1"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;defproject&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;compojureongae&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;0.2.0&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC2"&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="no"&gt;:description&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Example app for deployoing Compojure on Google App Engine&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC3"&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="no"&gt;:namespaces&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;compojureongae.core&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC4"&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="no"&gt;:dependencies&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="nv"&gt;compojure&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;0.4.0-RC3&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC5"&gt;&lt;span class="w"&gt;                 &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;ring/ring-servlet&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;0.2.1&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC6"&gt;&lt;span class="w"&gt;                 &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;hiccup&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;0.2.4&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC7"&gt;&lt;span class="w"&gt;                 &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;appengine&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;0.2&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC8"&gt;&lt;span class="w"&gt;                 &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;com.google.appengine/appengine-api-1.0-sdk&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;1.3.4&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC9"&gt;&lt;span class="w"&gt;                 &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;com.google.appengine/appengine-api-labs&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;1.3.4&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC10"&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="no"&gt;:dev-dependencies&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="nv"&gt;swank-clojure&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;1.2.0&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC11"&gt;&lt;span class="w"&gt;                     &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;ring/ring-jetty-adapter&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;0.2.0&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC12"&gt;&lt;span class="w"&gt;                     &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;com.google.appengine/appengine-local-runtime&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;1.3.4&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC13"&gt;&lt;span class="w"&gt;                     &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;com.google.appengine/appengine-api-stubs&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;1.3.4&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC14"&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="no"&gt;:compile-path&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;war/WEB-INF/classes&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC15"&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="no"&gt;:library-path&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;war/WEB-INF/lib&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;/pre&gt;&lt;/div&gt;
          &lt;/td&gt;
        &lt;/tr&gt;
      &lt;/table&gt;
  &lt;/div&gt;&lt;/p&gt;

&lt;p&gt;The new dependencies go into dev-dependencies, since they mustn&amp;rsquo;t be
deployed with the app. However, in the current development version of
Leiningen 1.2 (which separates dependencies and dev-dependencies into
different directories), the dev-dependencies are apparently only
intended for Leiningen plugins such as swank-clojure &amp;ndash; they are not
put on the classpath for the REPL. I had to patch Leiningen to make
this work. Here&amp;rsquo;s the diff:&lt;/p&gt;

&lt;p&gt;&lt;div class="data type-diff"&gt;
      &lt;table class="lines" cellspacing="0" cellpadding="0"&gt;
        &lt;tr&gt;
          &lt;td&gt;
            &lt;pre class="line_numbers"&gt;&lt;span rel="#L1" id="L1"&gt;1&lt;/span&gt;
&lt;span rel="#L2" id="L2"&gt;2&lt;/span&gt;
&lt;span rel="#L3" id="L3"&gt;3&lt;/span&gt;
&lt;span rel="#L4" id="L4"&gt;4&lt;/span&gt;
&lt;span rel="#L5" id="L5"&gt;5&lt;/span&gt;
&lt;span rel="#L6" id="L6"&gt;6&lt;/span&gt;
&lt;span rel="#L7" id="L7"&gt;7&lt;/span&gt;
&lt;span rel="#L8" id="L8"&gt;8&lt;/span&gt;
&lt;span rel="#L9" id="L9"&gt;9&lt;/span&gt;
&lt;span rel="#L10" id="L10"&gt;10&lt;/span&gt;
&lt;span rel="#L11" id="L11"&gt;11&lt;/span&gt;
&lt;span rel="#L12" id="L12"&gt;12&lt;/span&gt;
&lt;span rel="#L13" id="L13"&gt;13&lt;/span&gt;
&lt;span rel="#L14" id="L14"&gt;14&lt;/span&gt;
&lt;span rel="#L15" id="L15"&gt;15&lt;/span&gt;
&lt;span rel="#L16" id="L16"&gt;16&lt;/span&gt;
&lt;/pre&gt;
          &lt;/td&gt;
          &lt;td width="100%"&gt;
                &lt;div class="highlight"&gt;&lt;pre /&gt;&lt;div class="line" id="LC1"&gt;&lt;span class="gh"&gt;diff --git a/src/leiningen/classpath.clj b/src/leiningen/classpath.clj&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC2"&gt;&lt;span class="gh"&gt;index 3be7e1f..836740e 100644&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC3"&gt;&lt;span class="gd"&gt;--- a/src/leiningen/classpath.clj&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC4"&gt;&lt;span class="gi"&gt;+++ b/src/leiningen/classpath.clj&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC5"&gt;&lt;span class="gu"&gt;@@ -8,7 +8,9 @@&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC6"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;Returns a seq of Files for all the jars in the project&amp;#39;s library directory.&amp;quot;&lt;/div&gt;&lt;div class="line" id="LC7"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;[project]&lt;/div&gt;&lt;div class="line" id="LC8"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;(filter #(.endsWith (.getName %) &amp;quot;.jar&amp;quot;)&lt;/div&gt;&lt;div class="line" id="LC9"&gt;&lt;span class="gd"&gt;-          (file-seq (file (:library-path project)))))&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC10"&gt;&lt;span class="gi"&gt;+          (concat&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC11"&gt;&lt;span class="gi"&gt;+           (file-seq (file (:library-path project)))&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC12"&gt;&lt;span class="gi"&gt;+           (file-seq (file (str (:root project) &amp;quot;/lib/dev&amp;quot;))))))&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC13"&gt;&amp;nbsp;&lt;/div&gt;&lt;div class="line" id="LC14"&gt;&amp;nbsp;(defn make-path&lt;/div&gt;&lt;div class="line" id="LC15"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;quot;Constructs an ant Path object from Files and strings.&amp;quot;&lt;/div&gt;&lt;div class="line" id="LC16"&gt;&lt;br /&gt;&lt;/div&gt;&lt;/pre&gt;&lt;/div&gt;
          &lt;/td&gt;
        &lt;/tr&gt;
      &lt;/table&gt;
  &lt;/div&gt;&lt;/p&gt;

&lt;p&gt;I&amp;rsquo;ll try to get this (or something similar) into Leiningen. &lt;strong&gt;Update:
I wasn&amp;rsquo;t the only one with this problem. It was recently patched in Leiningen.&lt;/strong&gt;
Stable Leiningen (1.1) will probably work out of the box &amp;ndash; I haven&amp;rsquo;t tried.&lt;/p&gt;

&lt;p&gt;Running &lt;code&gt;lein deps&lt;/code&gt; installs the new dependencies. As I said in my
last post, you&amp;rsquo;ll likely have to manually install the jars from the
App Engine SDK into your local Maven repository. Here&amp;rsquo;s an example
command for one of the jars:&lt;/p&gt;

&lt;p&gt;&lt;div class="data type-shell"&gt;
      &lt;table class="lines" cellspacing="0" cellpadding="0"&gt;
        &lt;tr&gt;
          &lt;td&gt;
            &lt;pre class="line_numbers"&gt;&lt;span rel="#L1" id="L1"&gt;1&lt;/span&gt;
&lt;span rel="#L2" id="L2"&gt;2&lt;/span&gt;
&lt;span rel="#L3" id="L3"&gt;3&lt;/span&gt;
&lt;/pre&gt;
          &lt;/td&gt;
          &lt;td width="100%"&gt;
                &lt;div class="highlight"&gt;&lt;pre /&gt;&lt;div class="line" id="LC1"&gt;mvn install:install-file -DgroupId&lt;span class="o"&gt;=&lt;/span&gt;com.google.appengine &lt;span class="se"&gt;\&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC2"&gt;-DartifactId&lt;span class="o"&gt;=&lt;/span&gt;appengine-api-labs -Dversion&lt;span class="o"&gt;=&lt;/span&gt;1.3.4 -Dpackaging&lt;span class="o"&gt;=&lt;/span&gt;jar &lt;span class="se"&gt;\&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC3"&gt;-Dfile&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$GAESDK&lt;/span&gt;/lib/user/appengine-api-labs-1.3.4.jar&lt;/div&gt;&lt;/pre&gt;&lt;/div&gt;
          &lt;/td&gt;
        &lt;/tr&gt;
      &lt;/table&gt;
  &lt;/div&gt;&lt;/p&gt;

&lt;h2&gt;Putting it to use&lt;/h2&gt;

&lt;p&gt;Run &lt;code&gt;lein swank&lt;/code&gt;, enter &lt;code&gt;M-x slime-connect&lt;/code&gt; in Emacs to connect to the
REPL and code away as usual. To call functions that make use of the
App Engine API, enter this in the REPL:&lt;/p&gt;

&lt;p&gt;&lt;div class="data type-clojure"&gt;
    
      &lt;table class="lines" cellspacing="0" cellpadding="0"&gt;
        &lt;tr&gt;
          &lt;td&gt;
            &lt;pre class="line_numbers"&gt;&lt;span rel="#L1" id="L1"&gt;1&lt;/span&gt;
&lt;span rel="#L2" id="L2"&gt;2&lt;/span&gt;
&lt;/pre&gt;
          &lt;/td&gt;
          &lt;td width="100%"&gt;
            
              
                &lt;div class="highlight"&gt;&lt;pre /&gt;&lt;div class="line" id="LC1"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;require&lt;/span&gt; &lt;span class="ss"&gt;&amp;#39;local-dev&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC2"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;local-dev/init-app-engine&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/pre&gt;&lt;/div&gt;
              
            
          &lt;/td&gt;
        &lt;/tr&gt;
      &lt;/table&gt;
    
  &lt;/div&gt;&lt;/p&gt;

&lt;p&gt;To start a Jetty server, just enter:&lt;/p&gt;

&lt;p&gt;&lt;div class="data type-clojure"&gt;
    
      &lt;table class="lines" cellspacing="0" cellpadding="0"&gt;
        &lt;tr&gt;
          &lt;td&gt;
            &lt;pre class="line_numbers"&gt;&lt;span rel="#L1" id="L1"&gt;1&lt;/span&gt;
&lt;/pre&gt;
          &lt;/td&gt;
          &lt;td width="100%"&gt;
            
              
                &lt;div class="highlight"&gt;&lt;pre /&gt;&lt;div class="line" id="LC1"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;local-dev/start-server&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;example&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;/div&gt;&lt;/pre&gt;&lt;/div&gt;
              
            
          &lt;/td&gt;
        &lt;/tr&gt;
      &lt;/table&gt;
    
  &lt;/div&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;example&lt;/code&gt; is the name of the Compojure app defined by &lt;code&gt;defroutes&lt;/code&gt; in core.clj.
&lt;strong&gt;Update: Using &lt;code&gt;var&lt;/code&gt; here allows you to change the definition of &lt;code&gt;example&lt;/code&gt;
itself without having to restart the server.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;What&amp;rsquo;s next?&lt;/h2&gt;

&lt;p&gt;The next thing I&amp;rsquo;m working on is using the Users API for
authentication and authorization (instead of the simple
security-constraint method described in my &lt;a href="http://compojureongae.posterous.com/accessing-the-app-engine-datastore"&gt;last
post&lt;/a&gt;).
I&amp;rsquo;ll need to make some changes to this local-dev code in order to
properly test that locally. So stay tuned&amp;hellip;&lt;/p&gt;

&lt;p&gt;As always, questions and suggestions are very welcome in the comments
section below!&lt;/p&gt;
	
&lt;/p&gt;

&lt;p&gt;&lt;a href="http://compojureongae.posterous.com/getting-interactive-development-to-work-again"&gt;Permalink&lt;/a&gt; 

	| &lt;a href="http://compojureongae.posterous.com/getting-interactive-development-to-work-again#comment"&gt;Leave a comment&amp;nbsp;&amp;nbsp;&amp;raquo;&lt;/a&gt;

&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/CompojureOnGAE/~4/8HUupoQolqs" height="1" width="1"/&gt;</description>
      <posterous:author>
        <posterous:userImage>http://files.posterous.com/user_profile_pics/548315/gravatar.jpeg</posterous:userImage>
        <posterous:profileUrl>http://posterous.com/users/1bbRpyByNcB</posterous:profileUrl>
        <posterous:firstName>Christian</posterous:firstName>
        <posterous:lastName>Berg</posterous:lastName>
        <posterous:nickName>Christian</posterous:nickName>
        <posterous:displayName>Christian Berg</posterous:displayName>
      </posterous:author>
    <feedburner:origLink>http://compojureongae.posterous.com/getting-interactive-development-to-work-again</feedburner:origLink></item>
    <item>
      <pubDate>Tue, 01 Jun 2010 05:51:00 -0700</pubDate>
      <title>Accessing the App Engine Datastore</title>
      <link>http://feedproxy.google.com/~r/CompojureOnGAE/~3/giQ983NZIbY/accessing-the-app-engine-datastore</link>
      <guid isPermaLink="false">http://compojureongae.posterous.com/accessing-the-app-engine-datastore</guid>
      <description>&lt;p&gt;
	&lt;p&gt;In my &lt;a href="http://compojureongae.posterous.com/deploying-to-app-engine"&gt;last post&lt;/a&gt;,
I managed to deploy a Compojure app to Google App Engine. Serving
static content isn&amp;rsquo;t very exciting, though. Pretty much every app will
need some way to store and retrieve data. So let&amp;rsquo;s try to access the
App Engine Datastore.&lt;/p&gt;

&lt;h2&gt;New Dependencies&lt;/h2&gt;

&lt;p&gt;To use the datastore API I need to include a jar that comes with the
GAE SDK in my app. I could call the Java API directly, but there are
already a few Clojure libraries that provide friendly wrappers around
it. One of the first (that I know of) was
&lt;a href="http://github.com/duelinmarkers/appengine-clj"&gt;appengine-clj&lt;/a&gt; by John
Hume (who was also one of the first to &lt;a href="http://elhumidor.blogspot.com/2009/04/clojure-on-google-appengine.html"&gt;write about using Clojure on
GAE&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;I decided to go with &lt;a href="http://github.com/r0man/appengine-clj"&gt;this
fork&lt;/a&gt; of appengine-clj by Roman
Scherer, which seems to be more complete and actively maintained.
Another interesting option would be
&lt;a href="http://github.com/smartrevolution/clj-gae-datastore"&gt;clj-gae-datastore&lt;/a&gt;
by the people at freiheit.com.&lt;/p&gt;

&lt;p&gt;I updated my project.clj file with the new dependencies:&lt;/p&gt;

&lt;p&gt;&lt;div class="data type-clojure"&gt;
    
      &lt;table class="lines" cellspacing="0" cellpadding="0"&gt;
        &lt;tr&gt;
          &lt;td&gt;
            &lt;pre class="line_numbers"&gt;&lt;span rel="#L1" id="L1"&gt;1&lt;/span&gt;
&lt;span rel="#L2" id="L2"&gt;2&lt;/span&gt;
&lt;span rel="#L3" id="L3"&gt;3&lt;/span&gt;
&lt;span rel="#L4" id="L4"&gt;4&lt;/span&gt;
&lt;span rel="#L5" id="L5"&gt;5&lt;/span&gt;
&lt;span rel="#L6" id="L6"&gt;6&lt;/span&gt;
&lt;span rel="#L7" id="L7"&gt;7&lt;/span&gt;
&lt;span rel="#L8" id="L8"&gt;8&lt;/span&gt;
&lt;span rel="#L9" id="L9"&gt;9&lt;/span&gt;
&lt;span rel="#L10" id="L10"&gt;10&lt;/span&gt;
&lt;span rel="#L11" id="L11"&gt;11&lt;/span&gt;
&lt;/pre&gt;
          &lt;/td&gt;
          &lt;td width="100%"&gt;
            
              
                &lt;div class="highlight"&gt;&lt;pre /&gt;&lt;div class="line" id="LC1"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;defproject&lt;/span&gt; &lt;span class="nv"&gt;compojureongae&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;0.2.0&amp;quot;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC2"&gt;&amp;nbsp;&amp;nbsp;&lt;span class="nv"&gt;:description&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;Example app for deployoing Compojure on Google App Engine&amp;quot;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC3"&gt;&amp;nbsp;&amp;nbsp;&lt;span class="nv"&gt;:namespaces&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;compojureongae&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;core&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC4"&gt;&amp;nbsp;&amp;nbsp;&lt;span class="nv"&gt;:dependencies&lt;/span&gt; &lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="nv"&gt;compojure&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;0.4.0-RC3&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC5"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;ring/ring-servlet&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;0.2.1&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC6"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;hiccup&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;0.2.4&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC7"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;appengine&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;0.2&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC8"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;com&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;google&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;appengine/appengine-api-1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="nv"&gt;-sdk&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;1.3.4&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC9"&gt;&amp;nbsp;&amp;nbsp;&lt;span class="nv"&gt;:dev-dependencies&lt;/span&gt; &lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="nv"&gt;swank-clojure&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;1.2.0&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC10"&gt;&amp;nbsp;&amp;nbsp;&lt;span class="nv"&gt;:compile-path&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;war/WEB-INF/classes&amp;quot;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC11"&gt;&amp;nbsp;&amp;nbsp;&lt;span class="nv"&gt;:library-path&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;war/WEB-INF/lib&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/pre&gt;&lt;/div&gt;
              
            
          &lt;/td&gt;
        &lt;/tr&gt;
      &lt;/table&gt;
    
  &lt;/div&gt;&lt;/p&gt;

&lt;p&gt;I&amp;rsquo;m using &lt;a href="http://github.com/weavejester/hiccup"&gt;Hiccup&lt;/a&gt; (formerly
part of Compojure) for HTML generation. Running &lt;code&gt;lein deps&lt;/code&gt; runs into
an error, because it can&amp;rsquo;t find the Google SDK jar in the public
repositories. Luckily, Leiningen (or Maven) already tells me how to
fix this by installing the jar from the SDK download into my local
Maven repository &amp;ndash; I just have to copy and paste the command from the
error message and enter the path to the local jar. After that, &lt;code&gt;lein
deps&lt;/code&gt; executes cleanly and copies the new dependencies into my lib
dir.&lt;/p&gt;

&lt;p&gt;Along with updating the dependencies in project.clj I have to import
the needed symbols into my namespace:&lt;/p&gt;

&lt;p&gt;&lt;div class="data type-clojure"&gt;
    
      &lt;table class="lines" cellspacing="0" cellpadding="0"&gt;
        &lt;tr&gt;
          &lt;td&gt;
            &lt;pre class="line_numbers"&gt;&lt;span rel="#L1" id="L1"&gt;1&lt;/span&gt;
&lt;span rel="#L2" id="L2"&gt;2&lt;/span&gt;
&lt;span rel="#L3" id="L3"&gt;3&lt;/span&gt;
&lt;span rel="#L4" id="L4"&gt;4&lt;/span&gt;
&lt;span rel="#L5" id="L5"&gt;5&lt;/span&gt;
&lt;span rel="#L6" id="L6"&gt;6&lt;/span&gt;
&lt;span rel="#L7" id="L7"&gt;7&lt;/span&gt;
&lt;span rel="#L8" id="L8"&gt;8&lt;/span&gt;
&lt;span rel="#L9" id="L9"&gt;9&lt;/span&gt;
&lt;span rel="#L10" id="L10"&gt;10&lt;/span&gt;
&lt;span rel="#L11" id="L11"&gt;11&lt;/span&gt;
&lt;span rel="#L12" id="L12"&gt;12&lt;/span&gt;
&lt;/pre&gt;
          &lt;/td&gt;
          &lt;td width="100%"&gt;
            
              
                &lt;div class="highlight"&gt;&lt;pre /&gt;&lt;div class="line" id="LC1"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;ns&lt;/span&gt; &lt;span class="nv"&gt;compojureongae&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;core&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC2"&gt;&amp;nbsp;&amp;nbsp;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;:gen-class&lt;/span&gt; &lt;span class="nv"&gt;:extends&lt;/span&gt; &lt;span class="nv"&gt;javax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;servlet&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;HttpServlet&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC3"&gt;&amp;nbsp;&amp;nbsp;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;:use&lt;/span&gt; &lt;span class="nv"&gt;compojure&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;core&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC4"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;ring&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;util&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;servlet&lt;/span&gt;   &lt;span class="nv"&gt;:only&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;defservice&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC5"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;ring&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;util&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;response&lt;/span&gt;  &lt;span class="nv"&gt;:only&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;redirect&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC6"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;hiccup&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;core&lt;/span&gt;         &lt;span class="nv"&gt;:only&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;h&lt;/span&gt; &lt;span class="nv"&gt;html&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC7"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;hiccup&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;page-helpers&lt;/span&gt; &lt;span class="nv"&gt;:only&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;doctype&lt;/span&gt; &lt;span class="nv"&gt;include-css&lt;/span&gt; &lt;span class="nv"&gt;link-to&lt;/span&gt; &lt;span class="nv"&gt;xhtml-tag&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC8"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;hiccup&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;form-helpers&lt;/span&gt; &lt;span class="nv"&gt;:only&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;form-to&lt;/span&gt; &lt;span class="nv"&gt;text-area&lt;/span&gt; &lt;span class="nv"&gt;text-field&lt;/span&gt;&lt;span class="p"&gt;]])&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC9"&gt;&amp;nbsp;&amp;nbsp;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;:import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;com&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;google&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;appengine&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;api&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;datastore&lt;/span&gt; &lt;span class="nv"&gt;Query&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC10"&gt;&amp;nbsp;&amp;nbsp;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;:require&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;compojure&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;route&lt;/span&gt;          &lt;span class="nv"&gt;:as&lt;/span&gt; &lt;span class="nv"&gt;route&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC11"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;appengine&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;datastore&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;core&lt;/span&gt; &lt;span class="nv"&gt;:as&lt;/span&gt; &lt;span class="nv"&gt;ds&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC12"&gt;&lt;br /&gt;&lt;/div&gt;&lt;/pre&gt;&lt;/div&gt;
              
            
          &lt;/td&gt;
        &lt;/tr&gt;
      &lt;/table&gt;
    
  &lt;/div&gt;&lt;/p&gt;

&lt;p&gt;The choice of using &lt;code&gt;:use&lt;/code&gt; or &lt;code&gt;:require&lt;/code&gt; is pretty arbitrary in this
case &amp;ndash; I just used both to demonstrate the different options. With
&lt;code&gt;:require&lt;/code&gt; I need to call the functions using the full namespace
(using a short alias), with &lt;code&gt;:use&lt;/code&gt; they are imported into my
namespace. For the latter case, I explicitly named all the definitions
I need using &lt;code&gt;:only&lt;/code&gt;. This is pretty verbose and not strictly
necessary, but for a little howto like this I want you to immediately
see where every function comes from, so you don&amp;rsquo;t have to rummage
through all the libraries (although the &lt;code&gt;doc&lt;/code&gt; function makes this
easy&amp;hellip;). I guess it generally is a good idea to not clutter your
namespace with definitions you don&amp;rsquo;t need.&lt;/p&gt;

&lt;h2&gt;Storing Data&lt;/h2&gt;

&lt;p&gt;Now comes the more interesting part: Actually accessing the datastore.
I want to be able to create simple blog posts, consisting of a title
and a body. I need two new routes, one for displaying a form, and one
that is used as the action URL for the form:&lt;/p&gt;

&lt;p&gt;&lt;div class="data type-clojure"&gt;
    
      &lt;table class="lines" cellspacing="0" cellpadding="0"&gt;
        &lt;tr&gt;
          &lt;td&gt;
            &lt;pre class="line_numbers"&gt;&lt;span rel="#L1" id="L1"&gt;1&lt;/span&gt;
&lt;span rel="#L2" id="L2"&gt;2&lt;/span&gt;
&lt;span rel="#L3" id="L3"&gt;3&lt;/span&gt;
&lt;span rel="#L4" id="L4"&gt;4&lt;/span&gt;
&lt;span rel="#L5" id="L5"&gt;5&lt;/span&gt;
&lt;span rel="#L6" id="L6"&gt;6&lt;/span&gt;
&lt;/pre&gt;
          &lt;/td&gt;
          &lt;td width="100%"&gt;
            
              
                &lt;div class="highlight"&gt;&lt;pre /&gt;&lt;div class="line" id="LC1"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;defroutes&lt;/span&gt; &lt;span class="nv"&gt;example&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC2"&gt;&amp;nbsp;&amp;nbsp;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;GET&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;/&amp;quot;&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;main-page&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC3"&gt;&amp;nbsp;&amp;nbsp;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;GET&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;/new&amp;quot;&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;render-page&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;New Post&amp;quot;&lt;/span&gt; &lt;span class="nv"&gt;new-form&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC4"&gt;&amp;nbsp;&amp;nbsp;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;POST&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;/post&amp;quot;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;title&lt;/span&gt; &lt;span class="nv"&gt;body&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;create-post&lt;/span&gt; &lt;span class="nv"&gt;title&lt;/span&gt; &lt;span class="nv"&gt;body&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC5"&gt;&amp;nbsp;&amp;nbsp;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;route/not-found&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;Page not found&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC6"&gt;&lt;br /&gt;&lt;/div&gt;&lt;/pre&gt;&lt;/div&gt;
              
            
          &lt;/td&gt;
        &lt;/tr&gt;
      &lt;/table&gt;
    
  &lt;/div&gt;&lt;/p&gt;

&lt;p&gt;Here&amp;rsquo;s the code that handles the form submission:&lt;/p&gt;

&lt;p&gt;&lt;div class="data type-clojure"&gt;
    
      &lt;table class="lines" cellspacing="0" cellpadding="0"&gt;
        &lt;tr&gt;
          &lt;td&gt;
            &lt;pre class="line_numbers"&gt;&lt;span rel="#L1" id="L1"&gt;1&lt;/span&gt;
&lt;span rel="#L2" id="L2"&gt;2&lt;/span&gt;
&lt;span rel="#L3" id="L3"&gt;3&lt;/span&gt;
&lt;span rel="#L4" id="L4"&gt;4&lt;/span&gt;
&lt;span rel="#L5" id="L5"&gt;5&lt;/span&gt;
&lt;/pre&gt;
          &lt;/td&gt;
          &lt;td width="100%"&gt;
            
              
                &lt;div class="highlight"&gt;&lt;pre /&gt;&lt;div class="line" id="LC1"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;defn &lt;/span&gt;&lt;span class="nv"&gt;create-post&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;title&lt;/span&gt; &lt;span class="nv"&gt;body&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC2"&gt;&amp;nbsp;&amp;nbsp;&lt;span class="s"&gt;&amp;quot;Stores a new post in the datastore and issues an HTTP Redirect to the main page.&amp;quot;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC3"&gt;&amp;nbsp;&amp;nbsp;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;ds/create-entity&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;:kind&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;post&amp;quot;&lt;/span&gt; &lt;span class="nv"&gt;:title&lt;/span&gt; &lt;span class="nv"&gt;title&lt;/span&gt; &lt;span class="nv"&gt;:body&lt;/span&gt; &lt;span class="nv"&gt;body&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC4"&gt;&amp;nbsp;&amp;nbsp;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;redirect&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;/&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC5"&gt;&lt;br /&gt;&lt;/div&gt;&lt;/pre&gt;&lt;/div&gt;
              
            
          &lt;/td&gt;
        &lt;/tr&gt;
      &lt;/table&gt;
    
  &lt;/div&gt;&lt;/p&gt;

&lt;p&gt;Amazingly simple. The &lt;code&gt;create-entity&lt;/code&gt; function just takes a Clojure
map, which needs to have a &amp;ldquo;&lt;code&gt;:kind&lt;/code&gt;&amp;rdquo; entry, and stores it in the
datastore. After that I issue an HTTP redirect to the main page.&lt;/p&gt;

&lt;h2&gt;Retrieving Data&lt;/h2&gt;

&lt;p&gt;Retrieving data is just as simple. On the main page, I just display all posts:&lt;/p&gt;

&lt;p&gt;&lt;div class="data type-clojure"&gt;
    
      &lt;table class="lines" cellspacing="0" cellpadding="0"&gt;
        &lt;tr&gt;
          &lt;td&gt;
            &lt;pre class="line_numbers"&gt;&lt;span rel="#L1" id="L1"&gt;1&lt;/span&gt;
&lt;span rel="#L2" id="L2"&gt;2&lt;/span&gt;
&lt;span rel="#L3" id="L3"&gt;3&lt;/span&gt;
&lt;span rel="#L4" id="L4"&gt;4&lt;/span&gt;
&lt;span rel="#L5" id="L5"&gt;5&lt;/span&gt;
&lt;span rel="#L6" id="L6"&gt;6&lt;/span&gt;
&lt;span rel="#L7" id="L7"&gt;7&lt;/span&gt;
&lt;span rel="#L8" id="L8"&gt;8&lt;/span&gt;
&lt;span rel="#L9" id="L9"&gt;9&lt;/span&gt;
&lt;span rel="#L10" id="L10"&gt;10&lt;/span&gt;
&lt;span rel="#L11" id="L11"&gt;11&lt;/span&gt;
&lt;span rel="#L12" id="L12"&gt;12&lt;/span&gt;
&lt;span rel="#L13" id="L13"&gt;13&lt;/span&gt;
&lt;span rel="#L14" id="L14"&gt;14&lt;/span&gt;
&lt;span rel="#L15" id="L15"&gt;15&lt;/span&gt;
&lt;/pre&gt;
          &lt;/td&gt;
          &lt;td width="100%"&gt;
            
              
                &lt;div class="highlight"&gt;&lt;pre /&gt;&lt;div class="line" id="LC1"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;defn &lt;/span&gt;&lt;span class="nv"&gt;render-post&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;post&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC2"&gt;&amp;nbsp;&amp;nbsp;&lt;span class="s"&gt;&amp;quot;Renders a post to HTML.&amp;quot;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC3"&gt;&amp;nbsp;&amp;nbsp;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;:div&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC4"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;:h2&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;h&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;:title&lt;/span&gt; &lt;span class="nv"&gt;post&lt;/span&gt;&lt;span class="p"&gt;))]&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC5"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;:p&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;h&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;:body&lt;/span&gt; &lt;span class="nv"&gt;post&lt;/span&gt;&lt;span class="p"&gt;))]])&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC6"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="line" id="LC7"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;defn &lt;/span&gt;&lt;span class="nv"&gt;get-posts&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC8"&gt;&amp;nbsp;&amp;nbsp;&lt;span class="s"&gt;&amp;quot;Returns all posts stored in the datastore.&amp;quot;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC9"&gt;&amp;nbsp;&amp;nbsp;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;ds/find-all&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;Query&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;post&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC10"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="line" id="LC11"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;defn &lt;/span&gt;&lt;span class="nv"&gt;main-page&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC12"&gt;&amp;nbsp;&amp;nbsp;&lt;span class="s"&gt;&amp;quot;Renders the main page by displaying all posts.&amp;quot;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC13"&gt;&amp;nbsp;&amp;nbsp;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;render-page&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;Compojure on GAE&amp;quot;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC14"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;map &lt;/span&gt;&lt;span class="nv"&gt;render-post&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;get-posts&lt;/span&gt;&lt;span class="p"&gt;))))&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC15"&gt;&lt;br /&gt;&lt;/div&gt;&lt;/pre&gt;&lt;/div&gt;
              
            
          &lt;/td&gt;
        &lt;/tr&gt;
      &lt;/table&gt;
    
  &lt;/div&gt;&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;h&lt;/code&gt; function takes care of escaping special characters in the user input, so I don&amp;rsquo;t run into any cross-site scripting trouble. &lt;code&gt;render-page&lt;/code&gt; is a little helper function that takes care of
constructing the common HTML around the payload for all pages.&lt;/p&gt;

&lt;p&gt;As usual, the whole code can be found at
&lt;a href="http://github.com/christianberg/compojureongae"&gt;Github&lt;/a&gt;. The version
as of this writing is
&lt;a href="http://github.com/christianberg/compojureongae/tree/v0.2.0"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;Basic Security&lt;/h2&gt;

&lt;p&gt;I don&amp;rsquo;t want the whole world to be able to post to my blog, so I need
some authentication and authorization. I could use the App Engine
Users API, but I&amp;rsquo;ll leave that for a later post. Instead I&amp;rsquo;ll go the
simple route and enable security for some URLs in the deployment
descriptor. That way the application itself is blissfully unaware of
it. I just need to add this to the web.xml file:&lt;/p&gt;

&lt;p&gt;&lt;div class="data type-xml"&gt;
    
      &lt;table class="lines" cellspacing="0" cellpadding="0"&gt;
        &lt;tr&gt;
          &lt;td&gt;
            &lt;pre class="line_numbers"&gt;&lt;span rel="#L1" id="L1"&gt;1&lt;/span&gt;
&lt;span rel="#L2" id="L2"&gt;2&lt;/span&gt;
&lt;span rel="#L3" id="L3"&gt;3&lt;/span&gt;
&lt;span rel="#L4" id="L4"&gt;4&lt;/span&gt;
&lt;span rel="#L5" id="L5"&gt;5&lt;/span&gt;
&lt;span rel="#L6" id="L6"&gt;6&lt;/span&gt;
&lt;span rel="#L7" id="L7"&gt;7&lt;/span&gt;
&lt;span rel="#L8" id="L8"&gt;8&lt;/span&gt;
&lt;span rel="#L9" id="L9"&gt;9&lt;/span&gt;
&lt;span rel="#L10" id="L10"&gt;10&lt;/span&gt;
&lt;/pre&gt;
          &lt;/td&gt;
          &lt;td width="100%"&gt;
            
              
                &lt;div class="highlight"&gt;&lt;pre /&gt;&lt;div class="line" id="LC1"&gt;&amp;nbsp;&amp;nbsp;&lt;span class="nt"&gt;&amp;lt;security-constraint&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC2"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="nt"&gt;&amp;lt;web-resource-collection&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC3"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="nt"&gt;&amp;lt;url-pattern&amp;gt;&lt;/span&gt;/new&lt;span class="nt"&gt;&amp;lt;/url-pattern&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC4"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="nt"&gt;&amp;lt;url-pattern&amp;gt;&lt;/span&gt;/post&lt;span class="nt"&gt;&amp;lt;/url-pattern&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC5"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="nt"&gt;&amp;lt;/web-resource-collection&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC6"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="nt"&gt;&amp;lt;auth-constraint&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC7"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="nt"&gt;&amp;lt;role-name&amp;gt;&lt;/span&gt;admin&lt;span class="nt"&gt;&amp;lt;/role-name&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC8"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="nt"&gt;&amp;lt;/auth-constraint&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC9"&gt;&amp;nbsp;&amp;nbsp;&lt;span class="nt"&gt;&amp;lt;/security-constraint&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC10"&gt;&lt;br /&gt;&lt;/div&gt;&lt;/pre&gt;&lt;/div&gt;
              
            
          &lt;/td&gt;
        &lt;/tr&gt;
      &lt;/table&gt;
    
  &lt;/div&gt;&lt;/p&gt;

&lt;p&gt;Now only logged-in admin users can post new entries. You can see the
deployed version of the app here:
&lt;a href="http://v0-2.latest.compojureongae.appspot.com/"&gt;http://v0-2.latest.compojureongae.appspot.com/&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;What about the REPL!?&lt;/h2&gt;

&lt;p&gt;Okay, everything works fine. I can compile the project, start the
dev_appserver to test it locally and deploy it to the Google cloud
(see &lt;a href="http://compojureongae.posterous.com/deploying-to-app-engine"&gt;my last post&lt;/a&gt;
for the steps). But what about interactive development? When I try to
call e.g. the &lt;code&gt;create-entity&lt;/code&gt; function from a REPL, I only get an
Exception. So I can develop and deploy working software, but I&amp;rsquo;m back
to the dreaded edit-compile-run cycle &amp;ndash; that&amp;rsquo;s not the Clojure way.&lt;/p&gt;

&lt;p&gt;I need to fix this, but it&amp;rsquo;ll have to wait until the next post. Sorry&amp;hellip;&lt;/p&gt;
	
&lt;/p&gt;

&lt;p&gt;&lt;a href="http://compojureongae.posterous.com/accessing-the-app-engine-datastore"&gt;Permalink&lt;/a&gt; 

	| &lt;a href="http://compojureongae.posterous.com/accessing-the-app-engine-datastore#comment"&gt;Leave a comment&amp;nbsp;&amp;nbsp;&amp;raquo;&lt;/a&gt;

&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/CompojureOnGAE/~4/giQ983NZIbY" height="1" width="1"/&gt;</description>
      <posterous:author>
        <posterous:userImage>http://files.posterous.com/user_profile_pics/548315/gravatar.jpeg</posterous:userImage>
        <posterous:profileUrl>http://posterous.com/users/1bbRpyByNcB</posterous:profileUrl>
        <posterous:firstName>Christian</posterous:firstName>
        <posterous:lastName>Berg</posterous:lastName>
        <posterous:nickName>Christian</posterous:nickName>
        <posterous:displayName>Christian Berg</posterous:displayName>
      </posterous:author>
    <feedburner:origLink>http://compojureongae.posterous.com/accessing-the-app-engine-datastore</feedburner:origLink></item>
    <item>
      <pubDate>Tue, 11 May 2010 09:59:00 -0700</pubDate>
      <title>Deploying to App Engine</title>
      <link>http://feedproxy.google.com/~r/CompojureOnGAE/~3/Q4lBW_wz57Q/deploying-to-app-engine</link>
      <guid isPermaLink="false">http://compojureongae.posterous.com/deploying-to-app-engine</guid>
      <description>&lt;p&gt;
	&lt;p&gt;In my &lt;a href="http://compojureongae.posterous.com/a-fresh-start-42"&gt;last post&lt;/a&gt;, I set up a basic Hello World Compojure app, running on a local Jetty instance. Now I want to deploy this to Google App Engine.&lt;/p&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;&lt;span style="font-size: large;"&gt;Creating a Servlet&lt;/span&gt;&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;App Engine expects a standard Java web application, which means we have to take a small step out of pure Clojure-land into the Java realm and implement the HttpServlet interface. The defservice macro from the ring API makes this trivial.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;Obviously, Google runs their own app servers, so we don't need to start a Jetty instance. The updated core.clj looks like this:&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;&lt;div class="data type-clojure"&gt;
      &lt;table class="lines" cellspacing="0" cellpadding="0"&gt;
        &lt;tr&gt;
          &lt;td&gt;
            &lt;pre class="line_numbers"&gt;&lt;span rel="#L1" id="L1"&gt;1&lt;/span&gt;
&lt;span rel="#L2" id="L2"&gt;2&lt;/span&gt;
&lt;span rel="#L3" id="L3"&gt;3&lt;/span&gt;
&lt;span rel="#L4" id="L4"&gt;4&lt;/span&gt;
&lt;span rel="#L5" id="L5"&gt;5&lt;/span&gt;
&lt;span rel="#L6" id="L6"&gt;6&lt;/span&gt;
&lt;span rel="#L7" id="L7"&gt;7&lt;/span&gt;
&lt;span rel="#L8" id="L8"&gt;8&lt;/span&gt;
&lt;span rel="#L9" id="L9"&gt;9&lt;/span&gt;
&lt;span rel="#L10" id="L10"&gt;10&lt;/span&gt;
&lt;span rel="#L11" id="L11"&gt;11&lt;/span&gt;
&lt;/pre&gt;
          &lt;/td&gt;
          &lt;td width="100%"&gt;
                &lt;div class="highlight"&gt;&lt;pre /&gt;&lt;div class="line" id="LC1"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;ns&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;compojureongae.core&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC2"&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;:gen-class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;:extends&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;javax.servlet.http.HttpServlet&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC3"&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;:use&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;compojure.core&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC4"&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nv"&gt;ring.util.servlet&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC5"&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;:require&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;compojure.route&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;:as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;route&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC6"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="line" id="LC7"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;defroutes&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;example&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC8"&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;GET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;/&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&amp;lt;h1&amp;gt;Hello World Wide Web!&amp;lt;/h1&amp;gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC9"&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;route/not-found&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Page not found&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC10"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="line" id="LC11"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;defservice&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;example&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;/pre&gt;&lt;/div&gt;
          &lt;/td&gt;
        &lt;/tr&gt;
      &lt;/table&gt;
  &lt;/div&gt;&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;The project.clj file needs to be updated to reflect the changed dependencies:&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;&lt;div class="data type-clojure"&gt;
    
      &lt;table class="lines" cellspacing="0" cellpadding="0"&gt;
        &lt;tr&gt;
          &lt;td&gt;
            &lt;pre class="line_numbers"&gt;&lt;span rel="#L1" id="L1"&gt;1&lt;/span&gt;
&lt;span rel="#L2" id="L2"&gt;2&lt;/span&gt;
&lt;span rel="#L3" id="L3"&gt;3&lt;/span&gt;
&lt;span rel="#L4" id="L4"&gt;4&lt;/span&gt;
&lt;span rel="#L5" id="L5"&gt;5&lt;/span&gt;
&lt;span rel="#L6" id="L6"&gt;6&lt;/span&gt;
&lt;span rel="#L7" id="L7"&gt;7&lt;/span&gt;
&lt;span rel="#L8" id="L8"&gt;8&lt;/span&gt;
&lt;/pre&gt;
          &lt;/td&gt;
          &lt;td width="100%"&gt;
            
              
                &lt;div class="highlight"&gt;&lt;pre /&gt;&lt;div class="line" id="LC1"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;defproject&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;compojureongae&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;0.1.0&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC2"&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="no"&gt;:description&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Example app for deployoing Compojure on Google App Engine&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC3"&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="no"&gt;:namespaces&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;compojureongae.core&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC4"&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="no"&gt;:dependencies&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="nv"&gt;compojure&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;0.4.0-SNAPSHOT&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC5"&gt;&lt;span class="w"&gt;                 &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;ring/ring-servlet&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;0.2.1&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC6"&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="no"&gt;:dev-dependencies&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="nv"&gt;leiningen/lein-swank&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;1.2.0-SNAPSHOT&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC7"&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="no"&gt;:compile-path&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;war/WEB-INF/classes&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC8"&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="no"&gt;:library-path&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;war/WEB-INF/lib&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;&lt;/div&gt;&lt;/pre&gt;&lt;/div&gt;
              
            
          &lt;/td&gt;
        &lt;/tr&gt;
      &lt;/table&gt;
    
  &lt;/div&gt;&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;Note that I added a :namespaces entry. This triggers the AOT compilation of the Clojure source into Java bytecode. &lt;strong&gt;[Edit]&lt;/strong&gt; I also customized some paths - more on that below. &lt;strong&gt;[/Edit]&lt;/strong&gt;
&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;Google App Engine requires two config files, web.xml and appengine-web.xml. For my simple app, these are pretty straight-forward. The web.xml defines the mapping from URL patterns to servlet classes. Here it is:&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;&lt;div class="data type-xml"&gt;
    
      &lt;table class="lines" cellspacing="0" cellpadding="0"&gt;
        &lt;tr&gt;
          &lt;td&gt;
            &lt;pre class="line_numbers"&gt;&lt;span rel="#L1" id="L1"&gt;1&lt;/span&gt;
&lt;span rel="#L2" id="L2"&gt;2&lt;/span&gt;
&lt;span rel="#L3" id="L3"&gt;3&lt;/span&gt;
&lt;span rel="#L4" id="L4"&gt;4&lt;/span&gt;
&lt;span rel="#L5" id="L5"&gt;5&lt;/span&gt;
&lt;span rel="#L6" id="L6"&gt;6&lt;/span&gt;
&lt;span rel="#L7" id="L7"&gt;7&lt;/span&gt;
&lt;span rel="#L8" id="L8"&gt;8&lt;/span&gt;
&lt;span rel="#L9" id="L9"&gt;9&lt;/span&gt;
&lt;span rel="#L10" id="L10"&gt;10&lt;/span&gt;
&lt;span rel="#L11" id="L11"&gt;11&lt;/span&gt;
&lt;span rel="#L12" id="L12"&gt;12&lt;/span&gt;
&lt;span rel="#L13" id="L13"&gt;13&lt;/span&gt;
&lt;span rel="#L14" id="L14"&gt;14&lt;/span&gt;
&lt;span rel="#L15" id="L15"&gt;15&lt;/span&gt;
&lt;span rel="#L16" id="L16"&gt;16&lt;/span&gt;
&lt;span rel="#L17" id="L17"&gt;17&lt;/span&gt;
&lt;span rel="#L18" id="L18"&gt;18&lt;/span&gt;
&lt;span rel="#L19" id="L19"&gt;19&lt;/span&gt;
&lt;/pre&gt;
          &lt;/td&gt;
          &lt;td width="100%"&gt;
            
              
                &lt;div class="highlight"&gt;&lt;pre /&gt;&lt;div class="line" id="LC1"&gt;&lt;span class="cp"&gt;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;ISO-8859-1&amp;quot;?&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC2"&gt;&lt;span class="nt"&gt;&amp;lt;web-app&lt;/span&gt; &lt;/div&gt;&lt;div class="line" id="LC3"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="na"&gt;xmlns=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;http://java.sun.com/xml/ns/javaee&amp;quot;&lt;/span&gt; &lt;/div&gt;&lt;div class="line" id="LC4"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="na"&gt;xmlns:xsi=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;http://www.w3.org/2001/XMLSchema-instance&amp;quot;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC5"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="na"&gt;xsi:schemaLocation=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd&amp;quot;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC6"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="na"&gt;version=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;2.5&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt; &lt;/div&gt;&lt;div class="line" id="LC7"&gt;&amp;nbsp;&amp;nbsp;&lt;span class="nt"&gt;&amp;lt;display-name&amp;gt;&lt;/span&gt;Compojure on GAE&lt;span class="nt"&gt;&amp;lt;/display-name&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC8"&gt;&amp;nbsp;&amp;nbsp;&lt;/div&gt;&lt;div class="line" id="LC9"&gt;&amp;nbsp;&amp;nbsp;&lt;span class="nt"&gt;&amp;lt;servlet&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC10"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="nt"&gt;&amp;lt;servlet-name&amp;gt;&lt;/span&gt;blog&lt;span class="nt"&gt;&amp;lt;/servlet-name&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC11"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="nt"&gt;&amp;lt;servlet-class&amp;gt;&lt;/span&gt;compojureongae.core&lt;span class="nt"&gt;&amp;lt;/servlet-class&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC12"&gt;&amp;nbsp;&amp;nbsp;&lt;span class="nt"&gt;&amp;lt;/servlet&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC13"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="line" id="LC14"&gt;&amp;nbsp;&amp;nbsp;&lt;span class="nt"&gt;&amp;lt;servlet-mapping&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC15"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="nt"&gt;&amp;lt;servlet-name&amp;gt;&lt;/span&gt;blog&lt;span class="nt"&gt;&amp;lt;/servlet-name&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC16"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="nt"&gt;&amp;lt;url-pattern&amp;gt;&lt;/span&gt;/&lt;span class="nt"&gt;&amp;lt;/url-pattern&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC17"&gt;&amp;nbsp;&amp;nbsp;&lt;span class="nt"&gt;&amp;lt;/servlet-mapping&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC18"&gt;&lt;span class="nt"&gt;&amp;lt;/web-app&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC19"&gt;&lt;br /&gt;&lt;/div&gt;&lt;/pre&gt;&lt;/div&gt;
              
            
          &lt;/td&gt;
        &lt;/tr&gt;
      &lt;/table&gt;
    
  &lt;/div&gt;&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;The servlet name ("blog") is a generic identifier, you can use anything you like. The servlet-class needs to be the clojure namespace that implements the HttpServlet interface - in this case compojureongae.core.&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;In the appengine-web.xml we set the GAE application id and an arbitrary version string:&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;&lt;div class="data type-xml"&gt;
    
      &lt;table class="lines" cellspacing="0" cellpadding="0"&gt;
        &lt;tr&gt;
          &lt;td&gt;
            &lt;pre class="line_numbers"&gt;&lt;span rel="#L1" id="L1"&gt;1&lt;/span&gt;
&lt;span rel="#L2" id="L2"&gt;2&lt;/span&gt;
&lt;span rel="#L3" id="L3"&gt;3&lt;/span&gt;
&lt;span rel="#L4" id="L4"&gt;4&lt;/span&gt;
&lt;span rel="#L5" id="L5"&gt;5&lt;/span&gt;
&lt;span rel="#L6" id="L6"&gt;6&lt;/span&gt;
&lt;span rel="#L7" id="L7"&gt;7&lt;/span&gt;
&lt;span rel="#L8" id="L8"&gt;8&lt;/span&gt;
&lt;/pre&gt;
          &lt;/td&gt;
          &lt;td width="100%"&gt;
            
              
                &lt;div class="highlight"&gt;&lt;pre /&gt;&lt;div class="line" id="LC1"&gt;&lt;span class="nt"&gt;&amp;lt;appengine-web-app&lt;/span&gt; &lt;span class="na"&gt;xmlns=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;http://appengine.google.com/ns/1.0&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC2"&gt;&amp;nbsp;&amp;nbsp;&lt;span class="c"&gt;&amp;lt;!-- Replace this with your application id from http://appengine.google.com --&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC3"&gt;&amp;nbsp;&amp;nbsp;&lt;span class="nt"&gt;&amp;lt;application&amp;gt;&lt;/span&gt;compojureongae&lt;span class="nt"&gt;&amp;lt;/application&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC4"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="line" id="LC5"&gt;&amp;nbsp;&amp;nbsp;&lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;v0-1&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC6"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="line" id="LC7"&gt;&lt;span class="nt"&gt;&amp;lt;/appengine-web-app&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC8"&gt;&lt;br /&gt;&lt;/div&gt;&lt;/pre&gt;&lt;/div&gt;
              
            
          &lt;/td&gt;
        &lt;/tr&gt;
      &lt;/table&gt;
    
  &lt;/div&gt;&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;I set up a github repository for my experiments at &lt;a href="http://github.com/christianberg/compojureongae"&gt;http://github.com/christianberg/compojureongae&lt;/a&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;a href="http://github.com/christianberg/compojureongae"&gt;&lt;/a&gt;The code as of the time of this blog post can be found at &lt;a href="http://github.com/christianberg/compojureongae/tree/v0.1.1"&gt;http://github.com/christianberg/compojureongae/tree/v0.1.1&lt;/a&gt;&lt;br /&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;&lt;span style="font-size: large;"&gt;Building the war&lt;/span&gt;&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;&lt;strong&gt;[Update]&lt;/strong&gt;&lt;/div&gt;
&lt;div&gt;Sometimes things are much easier than they first appear. My initial "build process" (using &lt;a href="http://github.com/alienscience/leiningen-war"&gt;leiningen-war&lt;/a&gt;) was way too complicated. Thanks to &lt;a href="http://buntin.org/2010/03/02/leiningen-clojure-google-app-engine-interesting/"&gt;http://buntin.org/2010/03/02/leiningen-clojure-google-app-engine-interesting/&lt;/a&gt; for putting me on the right track. Here's how I do it now:&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;The deployment artifact for GAE is a standard java war file - actually a war directory, i.e. an unzipped war file. This makes the build process pretty trivial, you just have to adhere to the standard war directory structure. This is accomplished by customizing the :library-path and :compile-path in the project.clj (see above). Building the project is simply done with the standard lein commands:&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;blockquote&gt;
&lt;div&gt;lein clean&lt;/div&gt;
&lt;div&gt;lein deps&lt;/div&gt;
&lt;div&gt;lein compile&lt;/div&gt;
&lt;/blockquote&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;The current stable version of leiningen (1.1.0) mixes the dependencies and the dev-dependencies. If you don't want the dev-dependency jars included in your deployment, run this sequence of commands before deploying:&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;blockquote&gt;
&lt;div&gt;lein clean&lt;/div&gt;
&lt;div&gt;lein deps skip&lt;/div&gt;
&lt;div&gt;lein compile&lt;/div&gt;
&lt;/blockquote&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;The development version of leiningen (1.2.0-SNAPSHOT) separates the dev-dependencies into lib/dev, so you might want to check it out.&lt;/div&gt;
&lt;div&gt;&lt;strong&gt;[/Update]&lt;/strong&gt;&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;Now we have a war directory that can be used by the scripts that come with the App Engine SDK. If you haven't yet, &lt;a href="http://code.google.com/appengine/downloads.html#Google_App_Engine_SDK_for_Java"&gt;download&lt;/a&gt; it now.&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;&lt;span style="font-size: large;"&gt;Testing the war&lt;/span&gt;&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;To make sure our war file is ok, let's test it locally. I unpacked the SDK in the directory $GAESDK. Here's how to start the local server:&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;$GAESDK/bin/dev_appserver.sh war&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;You should see the familiar page at &lt;a href="http://localhost:8080/"&gt;http://localhost:8080/&lt;/a&gt;
&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;&lt;span style="font-size: large;"&gt;Into the Cloud!&lt;/span&gt;&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;It's time to deploy. Just run&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;$GAESDK/bin/appcfg.sh update war&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;Enter your Google login when prompted and wait for the app to deploy. (Remember that you need to create an Application in the GAE admin dashboard first and put it's app id in the appengine-web.xml.)&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;The app is now live in the cloud. You can see my deployed version here:&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;&lt;a href="http://v0-1.latest.compojureongae.appspot.com/"&gt;http://v0-1.latest.compojureongae.appspot.com/&lt;/a&gt;&lt;/div&gt;
&lt;div&gt; &lt;/div&gt;
&lt;div&gt;Have fun! If this inspires you to do your own experiments with Clojure on App Engine, leave a comment below!&lt;/div&gt;
	
&lt;/p&gt;

&lt;p&gt;&lt;a href="http://compojureongae.posterous.com/deploying-to-app-engine"&gt;Permalink&lt;/a&gt; 

	| &lt;a href="http://compojureongae.posterous.com/deploying-to-app-engine#comment"&gt;Leave a comment&amp;nbsp;&amp;nbsp;&amp;raquo;&lt;/a&gt;

&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/CompojureOnGAE/~4/Q4lBW_wz57Q" height="1" width="1"/&gt;</description>
      <posterous:author>
        <posterous:userImage>http://files.posterous.com/user_profile_pics/548315/gravatar.jpeg</posterous:userImage>
        <posterous:profileUrl>http://posterous.com/users/1bbRpyByNcB</posterous:profileUrl>
        <posterous:firstName>Christian</posterous:firstName>
        <posterous:lastName>Berg</posterous:lastName>
        <posterous:nickName>Christian</posterous:nickName>
        <posterous:displayName>Christian Berg</posterous:displayName>
      </posterous:author>
    <feedburner:origLink>http://compojureongae.posterous.com/deploying-to-app-engine</feedburner:origLink></item>
    <item>
      <pubDate>Fri, 07 May 2010 04:59:00 -0700</pubDate>
      <title>A Fresh Start</title>
      <link>http://feedproxy.google.com/~r/CompojureOnGAE/~3/iIGzUBNXa48/a-fresh-start-42</link>
      <guid isPermaLink="false">http://compojureongae.posterous.com/a-fresh-start-42</guid>
      <description>&lt;p&gt;
	&lt;p&gt;Since my last post a lot has happened in Clojure- and Compojure-Land. Managing dependencies and building projects is much easier now that there is &lt;a href="http://github.com/technomancy/leiningen" target="_blank"&gt;Leiningen&lt;/a&gt; and more people have played around with Clojure on Google App Engine, some are even deploying live apps (check out &lt;a href="http://the-deadline.appspot.com/" target="_blank"&gt;TheDeadline&lt;/a&gt;).&lt;p /&gt; So I decided to build upon these great contributions and (finally) continue this little tutorial.&lt;p /&gt;&lt;span style="font-size: large;"&gt;Create a new project&lt;/span&gt;&lt;p /&gt;From my last post, you can still read the part about Emacs, but you can forget about getting all the dependencies. We'll use Leiningen for that. To install Leiningen, follow the &lt;a href="http://github.com/technomancy/leiningen" target="_blank"&gt;installation instructions&lt;/a&gt;. Then create a new project:&lt;/p&gt;
&lt;p /&gt;
&lt;blockquote&gt;
&lt;div&gt;&lt;span style="font-family: courier new, monospace;"&gt;lein new &lt;em&gt;compojureongae&lt;/em&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/blockquote&gt;
&lt;p /&gt;
&lt;div&gt;This creates the basic directory structure with some skeleton code. Edit the project.clj file to look like this:&lt;/div&gt;
&lt;p /&gt;
&lt;div&gt;&lt;div class="data type-clojure"&gt;
    
      &lt;table class="lines" cellspacing="0" cellpadding="0"&gt;
        &lt;tr&gt;
          &lt;td&gt;
            &lt;pre class="line_numbers"&gt;&lt;span rel="#L1" id="L1"&gt;1&lt;/span&gt;
&lt;span rel="#L2" id="L2"&gt;2&lt;/span&gt;
&lt;span rel="#L3" id="L3"&gt;3&lt;/span&gt;
&lt;span rel="#L4" id="L4"&gt;4&lt;/span&gt;
&lt;span rel="#L5" id="L5"&gt;5&lt;/span&gt;
&lt;/pre&gt;
          &lt;/td&gt;
          &lt;td width="100%"&gt;
            
              
                &lt;div class="highlight"&gt;&lt;pre /&gt;&lt;div class="line" id="LC1"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;defproject&lt;/span&gt; &lt;span class="nv"&gt;compojureongae&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;0.1.0-SNAPSHOT&amp;quot;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC2"&gt;&amp;nbsp;&amp;nbsp;&lt;span class="nv"&gt;:description&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;Example app for deployoing Compojure on Google App Engine&amp;quot;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC3"&gt;&amp;nbsp;&amp;nbsp;&lt;span class="nv"&gt;:dependencies&lt;/span&gt; &lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="nv"&gt;compojure&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;0.4.0-SNAPSHOT&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC4"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;ring/ring-jetty-adapter&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;0.2.0&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC5"&gt;&amp;nbsp;&amp;nbsp;&lt;span class="nv"&gt;:dev-dependencies&lt;/span&gt; &lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="nv"&gt;leiningen/lein-swank&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;1.1.0&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]])&lt;/span&gt;&lt;/div&gt;&lt;/pre&gt;&lt;/div&gt;
              
            
          &lt;/td&gt;
        &lt;/tr&gt;
      &lt;/table&gt;
    
  &lt;/div&gt;&lt;/div&gt;
&lt;p /&gt;
&lt;div&gt;I removed the direct dependencies on clojure and clojure-contrib, since depending on compojure automatically pulls these, but you could leave them in (e.g. if you need a specific version). The dev-dependency on lein-swank gives me integration with Emacs while letting leiningen handle the classpath config.&lt;/div&gt;
&lt;p /&gt;
&lt;div&gt;Running&lt;/div&gt;
&lt;p /&gt;
&lt;blockquote&gt;
&lt;div&gt;&lt;span style="font-family: courier new, monospace;"&gt;lein deps&lt;/span&gt;&lt;/div&gt;
&lt;/blockquote&gt;
&lt;p /&gt;
&lt;div&gt;(in the directory containing project.clj) downloads all required libraries and puts them in the lib directory.&lt;/div&gt;
&lt;p /&gt;
&lt;div&gt;&lt;span style="font-size: large;"&gt;Start Hacking&lt;/span&gt;&lt;/div&gt;
&lt;p /&gt;
&lt;div&gt;Run&lt;/div&gt;
&lt;p /&gt;
&lt;blockquote&gt;
&lt;div&gt;&lt;span style="font-family: courier new, monospace;"&gt;lein swank&lt;/span&gt;&lt;/div&gt;
&lt;/blockquote&gt;
&lt;p /&gt;
&lt;div&gt;to start a REPL, open Emacs and enter&lt;/div&gt;
&lt;p /&gt;
&lt;blockquote&gt;
&lt;div&gt;&lt;span style="font-family: courier new, monospace;"&gt;M-x slime-connect&lt;/span&gt;&lt;/div&gt;
&lt;/blockquote&gt;
&lt;p /&gt;
&lt;div&gt;to connect to the REPL. Now we can start hacking away in Emacs! Open src/compojureongae/core.clj and enter the following:&lt;/div&gt;
&lt;p /&gt;
&lt;div&gt;&lt;div class="data type-clojure"&gt;
    
      &lt;table class="lines" cellspacing="0" cellpadding="0"&gt;
        &lt;tr&gt;
          &lt;td&gt;
            &lt;pre class="line_numbers"&gt;&lt;span rel="#L1" id="L1"&gt;1&lt;/span&gt;
&lt;span rel="#L2" id="L2"&gt;2&lt;/span&gt;
&lt;span rel="#L3" id="L3"&gt;3&lt;/span&gt;
&lt;span rel="#L4" id="L4"&gt;4&lt;/span&gt;
&lt;span rel="#L5" id="L5"&gt;5&lt;/span&gt;
&lt;span rel="#L6" id="L6"&gt;6&lt;/span&gt;
&lt;span rel="#L7" id="L7"&gt;7&lt;/span&gt;
&lt;span rel="#L8" id="L8"&gt;8&lt;/span&gt;
&lt;span rel="#L9" id="L9"&gt;9&lt;/span&gt;
&lt;span rel="#L10" id="L10"&gt;10&lt;/span&gt;
&lt;/pre&gt;
          &lt;/td&gt;
          &lt;td width="100%"&gt;
            
              
                &lt;div class="highlight"&gt;&lt;pre /&gt;&lt;div class="line" id="LC1"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;ns&lt;/span&gt; &lt;span class="nv"&gt;compojureongae&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;core&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC2"&gt;&amp;nbsp;&amp;nbsp;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;:use&lt;/span&gt; &lt;span class="nv"&gt;compojure&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;core&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC3"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="nv"&gt;ring&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;adapter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;jetty&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC4"&gt;&amp;nbsp;&amp;nbsp;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;:require&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;compojure&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;route&lt;/span&gt; &lt;span class="nv"&gt;:as&lt;/span&gt; &lt;span class="nv"&gt;route&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC5"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="line" id="LC6"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;defroutes&lt;/span&gt; &lt;span class="nv"&gt;example&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC7"&gt;&amp;nbsp;&amp;nbsp;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;GET&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;/&amp;quot;&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;&amp;lt;h1&amp;gt;Hello World Wide Web!&amp;lt;/h1&amp;gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC8"&gt;&amp;nbsp;&amp;nbsp;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;route/not-found&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;Page not found&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC9"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="line" id="LC10"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;run-jetty&lt;/span&gt; &lt;span class="nv"&gt;example&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;:port&lt;/span&gt; &lt;span class="mi"&gt;8080&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;&lt;/div&gt;&lt;/pre&gt;&lt;/div&gt;
              
            
          &lt;/td&gt;
        &lt;/tr&gt;
      &lt;/table&gt;
    
  &lt;/div&gt;&lt;/div&gt;
&lt;p /&gt;
&lt;div&gt;(This is taken directly from Compojure's &lt;a href="http://weavejester.github.com/compojure/docs/getting-started.html"&gt;Getting Started&lt;/a&gt; page.) Pressing &lt;span style="font-family: courier new, monospace;"&gt;C-c C-k&lt;/span&gt; compiles the file and starts the server - you can see the output in the shell where you ran lein swank. Now browse to &lt;a href="http://localhost:8080/"&gt;http://localhost:8080/&lt;/a&gt; to see your first Compojure app.&lt;/div&gt;
&lt;p /&gt;
&lt;div&gt;Next step: Deploying this to Google App Engine!&lt;/div&gt;
	
&lt;/p&gt;

&lt;p&gt;&lt;a href="http://compojureongae.posterous.com/a-fresh-start-42"&gt;Permalink&lt;/a&gt; 

	| &lt;a href="http://compojureongae.posterous.com/a-fresh-start-42#comment"&gt;Leave a comment&amp;nbsp;&amp;nbsp;&amp;raquo;&lt;/a&gt;

&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/CompojureOnGAE/~4/iIGzUBNXa48" height="1" width="1"/&gt;</description>
      <posterous:author>
        <posterous:userImage>http://files.posterous.com/user_profile_pics/548315/gravatar.jpeg</posterous:userImage>
        <posterous:profileUrl>http://posterous.com/users/1bbRpyByNcB</posterous:profileUrl>
        <posterous:firstName>Christian</posterous:firstName>
        <posterous:lastName>Berg</posterous:lastName>
        <posterous:nickName>Christian</posterous:nickName>
        <posterous:displayName>Christian Berg</posterous:displayName>
      </posterous:author>
    <feedburner:origLink>http://compojureongae.posterous.com/a-fresh-start-42</feedburner:origLink></item>
    <item>
      <pubDate>Sat, 24 Oct 2009 07:44:00 -0700</pubDate>
      <title>Setting up the Dev Environment</title>
      <link>http://feedproxy.google.com/~r/CompojureOnGAE/~3/ndtAvAqNVFM/setting-up-the-dev-environment</link>
      <guid isPermaLink="false">http://compojureongae.posterous.com/setting-up-the-dev-environment</guid>
      <description>&lt;p&gt;
	&lt;p&gt;In this post I'll cover the setup I use for developing my Compojure/GAE app.&lt;p /&gt;&lt;strong&gt;&lt;span style="font-size: medium;"&gt;Emacs&lt;/span&gt;&lt;/strong&gt;&lt;br /&gt;Of course you can use any editor you like to edit your source code, but Emacs has some great features for editing Lisp code that make developing in Clojure a pure joy. When properly set up, you can add new or modify existing code and inspect all your data while the application is running.&lt;p /&gt; I followed the instructions at &lt;a href="http://technomancy.us/126" target="_blank"&gt;http://technomancy.us/126&lt;/a&gt; to set up Slime/Swank for Clojure and it worked flawlessly without any modifications. I can also recommend the &lt;a href="http://github.com/technomancy/emacs-starter-kit" target="_blank"&gt;Emacs Starter Kit&lt;/a&gt; that is mentioned in the above post.&lt;p /&gt; &lt;strong&gt;&lt;span style="font-size: medium;"&gt;Clojure&lt;/span&gt;&lt;/strong&gt;&lt;br /&gt;There are several options for getting the clojure.jar that you'll need:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Download it from &lt;a href="http://code.google.com/p/clojure/downloads/list" target="_blank"&gt;http://code.google.com/p/clojure/downloads/list&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Clone the git repository at &lt;a&gt;git://github.com/richhickey/clojure.git&lt;/a&gt; and build from source using ant&lt;/li&gt;
&lt;li&gt;If you're using Emacs and followed the instructions above, you can automatically download the source and build it using the &lt;span style="font-family: courier new,monospace;"&gt;clojure-install&lt;/span&gt; command.&lt;/li&gt;
&lt;li&gt;Compojure provides a zip file of its dependendies (see below), this also includes clojure&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;&lt;span style="font-size: medium;"&gt;Compojure&lt;/span&gt;&lt;/strong&gt;&lt;br /&gt;You can download a tarball of the Compojure sources from &lt;a href="http://github.com/weavejester/compojure/downloads"&gt;http://github.com/weavejester/compojure/downloads&lt;/a&gt;, but I'd recommend cloning the git repository at &lt;a&gt;git://github.com/weavejester/compojure.git&lt;/a&gt;. Either way you'll build the compojure.jar from source using ant.&lt;p /&gt; Compojure has a few dependencies. You can download a zip file containing all needed jars (including clojure.jar and clojure-contrib.jar) from the download link above, or you can just run &lt;span style="font-family: courier new,monospace;"&gt;ant dep&lt;/span&gt;, which will download the zip for you.&lt;p /&gt; &lt;strong&gt;&lt;span style="font-size: medium;"&gt;Google App Engine SDK&lt;/span&gt;&lt;/strong&gt;&lt;br /&gt;Download the latest GAE SDK from &lt;a href="http://code.google.com/intl/de-DE/appengine/downloads.html"&gt;http://code.google.com/intl/de-DE/appengine/downloads.html&lt;/a&gt;. Choose the SDK for Java and unzip it somewhere.&lt;p /&gt; In the next post I'll create a simplistic Hello World Compojure app.&lt;/p&gt;
	
&lt;/p&gt;

&lt;p&gt;&lt;a href="http://compojureongae.posterous.com/setting-up-the-dev-environment"&gt;Permalink&lt;/a&gt; 

	| &lt;a href="http://compojureongae.posterous.com/setting-up-the-dev-environment#comment"&gt;Leave a comment&amp;nbsp;&amp;nbsp;&amp;raquo;&lt;/a&gt;

&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/CompojureOnGAE/~4/ndtAvAqNVFM" height="1" width="1"/&gt;</description>
      <posterous:author>
        <posterous:userImage>http://files.posterous.com/user_profile_pics/548315/gravatar.jpeg</posterous:userImage>
        <posterous:profileUrl>http://posterous.com/users/1bbRpyByNcB</posterous:profileUrl>
        <posterous:firstName>Christian</posterous:firstName>
        <posterous:lastName>Berg</posterous:lastName>
        <posterous:nickName>Christian</posterous:nickName>
        <posterous:displayName>Christian Berg</posterous:displayName>
      </posterous:author>
    <feedburner:origLink>http://compojureongae.posterous.com/setting-up-the-dev-environment</feedburner:origLink></item>
    <item>
      <pubDate>Thu, 08 Oct 2009 05:13:00 -0700</pubDate>
      <title>Compojure on GAE: What's this about?</title>
      <link>http://feedproxy.google.com/~r/CompojureOnGAE/~3/ILLFMrfZq5s/compojure-on-gae-whats-this-about</link>
      <guid isPermaLink="false">http://compojureongae.posterous.com/compojure-on-gae-whats-this-about</guid>
      <description>&lt;p&gt;
	&lt;p&gt;I'm interested in the Clojure programming language and the Google App Engine platform right now, and I'm playing around with the combination of both. Since there isn't a whole lot of information on this on the net, I thought I'd share the results of my experiments in this blog. Here's the rundown on what this will (and won't) be about:&lt;p /&gt; &lt;strong&gt;&lt;span style="font-size: medium;"&gt;Clojure&lt;/span&gt;&lt;/strong&gt;&lt;br /&gt;Clojure is a functional programming language of the Lisp family, designed with concurrency in mind to make it easy to write multi-threaded programs. It runs on the Java Virtual Machine and can call (and be called from) Java code. I'm not going to write a tutorial on programming Clojure (many others can do this better than me) nor am I going to try to convince you that Clojure is the greatest language in the world. I just think it's very interesting and I assume you do, too - otherwise you probably wouldn't have stumbled across this site. If you want to learn more about Clojure, the &lt;a href="http://www.clojure.org" target="_blank"&gt;official website&lt;/a&gt; provides very good documentation. I highly recommend watching the &lt;a href="http://clojure.blip.tv/" target="_blank"&gt;videos&lt;/a&gt; of Rich Hickey's talks, they got me hooked in the first place.&lt;p /&gt; &lt;strong&gt;&lt;span style="font-size: medium;"&gt;Compojure&lt;/span&gt;&lt;/strong&gt;&lt;br /&gt;Compojure is one of the frameworks for developing web applications in Clojure that are being developed right now. I don't know if it's the best, but it's the one I'm playing around with. The documentation isn't very extensive, but you can find some at &lt;a href="http://preview.compojure.org" target="_blank"&gt;http://preview.compojure.org&lt;/a&gt; and there's an active &lt;a href="http://groups.google.com/group/compojure" target="_blank"&gt;Google group&lt;/a&gt;. You can grab the code at &lt;a href="http://github.com/weavejester/compojure" target="_blank"&gt;GitHub&lt;/a&gt;. For getting started I recommend this &lt;a href="http://groups.google.com/group/compojure/browse_thread/thread/3c507da23540da6e" target="_blank"&gt;short tutorial&lt;/a&gt; by Compojure's creator, James Reeves.&lt;br /&gt; &lt;span style="font-size: medium;"&gt;&lt;br /&gt;&lt;strong&gt;Google App Engine&lt;/strong&gt;&lt;/span&gt;&lt;br /&gt;&lt;a href="http://appengine.google.com/"&gt;Google App Engine&lt;/a&gt; (GAE) is a service provided by Google that let's you develop web applications that can be deployed to Google's server infrastructure. Google provides several APIs that applications can use, e.g. for user authentication and storing data in a distributed data store. The idea is that applications can easily scale to handle everything from very small to very large loads. When App Engine was initially released it only provided a Python runtime environment. In April 2009 introduced the Java runtime for App Engine. This opened the door not only for Java programs but for a number of languages that run on the JVM, including Clojure.&lt;p /&gt; &lt;strong&gt;&lt;span style="font-size: medium;"&gt;The example app: A blog!&lt;/span&gt;&lt;/strong&gt; (yawn)&lt;br /&gt;I chose to implement a little blogging application to experiment with Clojure/Compojure on GAE. This isn't very exciting at all and I don't intend to actually use it. But it is simple and straightforward and displays much of the functionality of a typical web app: displaying pages, handling form input, storing and retrieving persistent data and authenticating users. (Edit: After reading &lt;a href="http://stackoverflow.com/questions/471940/why-does-every-man-and-his-dog-want-to-code-a-blogging-engine"&gt;this question&lt;/a&gt; on stackoverflow I feel a little bad about my choice of example app. But at least I'm in good company...)&lt;p /&gt; So, that's the plan. In the next post I'll talk about setting up the development environment.&lt;/p&gt;
	
&lt;/p&gt;

&lt;p&gt;&lt;a href="http://compojureongae.posterous.com/compojure-on-gae-whats-this-about"&gt;Permalink&lt;/a&gt; 

	| &lt;a href="http://compojureongae.posterous.com/compojure-on-gae-whats-this-about#comment"&gt;Leave a comment&amp;nbsp;&amp;nbsp;&amp;raquo;&lt;/a&gt;

&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/CompojureOnGAE/~4/ILLFMrfZq5s" height="1" width="1"/&gt;</description>
      <posterous:author>
        <posterous:userImage>http://files.posterous.com/user_profile_pics/548315/gravatar.jpeg</posterous:userImage>
        <posterous:profileUrl>http://posterous.com/users/1bbRpyByNcB</posterous:profileUrl>
        <posterous:firstName>Christian</posterous:firstName>
        <posterous:lastName>Berg</posterous:lastName>
        <posterous:nickName>Christian</posterous:nickName>
        <posterous:displayName>Christian Berg</posterous:displayName>
      </posterous:author>
    <feedburner:origLink>http://compojureongae.posterous.com/compojure-on-gae-whats-this-about</feedburner:origLink></item>
  </channel>
</rss>

