blob: d2483ad6dcc5af3268f52814e21af0867555c619 [file] [log] [blame]
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8">
<title>basic_with_auth</title>
<link rel="stylesheet" href="/css/pycco.css">
</head>
<body>
<div id="background"></div>
<div id='container'>
<div class='section'>
<div class='docs'><h1>basic_with_auth</h1></div>
</div>
<div class='clearall'>
<div class='section' id='section-0'>
<div class='docs'>
<div class='octowrap'>
<a class='octothorpe' href='#section-0'>#</a>
</div>
<p>If you have not yet seen the source in <a href="/examples/basic.html">basic</a>, please take a look.</p>
</div>
<div class='code'>
</div>
</div>
<div class='clearall'></div>
<div class='section' id='section-1'>
<div class='docs'>
<div class='octowrap'>
<a class='octothorpe' href='#section-1'>#</a>
</div>
</div>
<div class='code'>
<div class="highlight"><pre><span class="kn">import</span> <span class="n">endpoints</span>
<span class="kn">from</span> <span class="nn">google.appengine.ext</span> <span class="kn">import</span> <span class="n">ndb</span>
<span class="kn">from</span> <span class="nn">protorpc</span> <span class="kn">import</span> <span class="n">remote</span>
<span class="kn">from</span> <span class="nn">endpoints_proto_datastore.ndb</span> <span class="kn">import</span> <span class="n">EndpointsModel</span></pre></div>
</div>
</div>
<div class='clearall'></div>
<div class='section' id='section-2'>
<div class='docs'>
<div class='octowrap'>
<a class='octothorpe' href='#section-2'>#</a>
</div>
<p>In this model definition, we have added an extra field <code>owner</code> to the model
defined in <a href="/examples/basic.html">basic</a>. Since using auth, we will save the current user and
query by the current user, so saving a user property on each entity will allow
us to do this.</p>
</div>
<div class='code'>
<div class="highlight"><pre><span class="k">class</span> <span class="nc">MyModel</span><span class="p">(</span><span class="n">EndpointsModel</span><span class="p">):</span></pre></div>
</div>
</div>
<div class='clearall'></div>
<div class='section' id='section-3'>
<div class='docs'>
<div class='octowrap'>
<a class='octothorpe' href='#section-3'>#</a>
</div>
<p>By default, the ProtoRPC message schema corresponding to this model will
have four fields: <code>attr1</code>, <code>attr2</code>, <code>created</code> and <code>owner</code>
in an arbitrary order (the ordering of properties in a dictionary is not
guaranteed).</p>
</div>
<div class='code'>
<div class="highlight"><pre> <span class="n">attr1</span> <span class="o">=</span> <span class="n">ndb</span><span class="o">.</span><span class="n">StringProperty</span><span class="p">()</span>
<span class="n">attr2</span> <span class="o">=</span> <span class="n">ndb</span><span class="o">.</span><span class="n">StringProperty</span><span class="p">()</span>
<span class="n">created</span> <span class="o">=</span> <span class="n">ndb</span><span class="o">.</span><span class="n">DateTimeProperty</span><span class="p">(</span><span class="n">auto_now_add</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span></pre></div>
</div>
</div>
<div class='clearall'></div>
<div class='section' id='section-4'>
<div class='docs'>
<div class='octowrap'>
<a class='octothorpe' href='#section-4'>#</a>
</div>
<p>The three properties above are represented by string fields, but the
<code>UserProperty</code> below is represented in the ProtoRPC message schema as a
message field &mdash; a field whose value is itself a message. To hold a user
property, a custom ProtoRPC message class is defined in
<code>endpoints_proto_datastore.utils</code> and is used to convert to and from the NDB
property and the corresponding ProtoRPC field.</p>
</div>
<div class='code'>
<div class="highlight"><pre> <span class="n">owner</span> <span class="o">=</span> <span class="n">ndb</span><span class="o">.</span><span class="n">UserProperty</span><span class="p">()</span></pre></div>
</div>
</div>
<div class='clearall'></div>
<div class='section' id='section-5'>
<div class='docs'>
<div class='octowrap'>
<a class='octothorpe' href='#section-5'>#</a>
</div>
<p>Since we are using auth, we want to test with the
<a href="https://developers.google.com/apis-explorer/">Google APIs Explorer</a>.
By default, if <code>allowed_client_ids</code> is not specified, this is
enabled by default. If you specify <code>allowed_client_ids</code>, you'll
need to include <code>endpoints.API_EXPLORER_CLIENT_ID</code> in this list.
This is necessary for auth tokens obtained by the API Explorer (on behalf of
users) to be considered valid by our API.</p>
</div>
<div class='code'>
<div class="highlight"><pre><span class="nd">@endpoints.api</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s">&#39;myapi&#39;</span><span class="p">,</span> <span class="n">version</span><span class="o">=</span><span class="s">&#39;v1&#39;</span><span class="p">,</span> <span class="n">description</span><span class="o">=</span><span class="s">&#39;My Little API&#39;</span><span class="p">,</span>
<span class="n">audiences</span><span class="o">=</span><span class="p">[</span><span class="n">endpoints</span><span class="o">.</span><span class="n">API_EXPLORER_CLIENT_ID</span><span class="p">])</span>
<span class="k">class</span> <span class="nc">MyApi</span><span class="p">(</span><span class="n">remote</span><span class="o">.</span><span class="n">Service</span><span class="p">):</span></pre></div>
</div>
</div>
<div class='clearall'></div>
<div class='section' id='section-6'>
<div class='docs'>
<div class='octowrap'>
<a class='octothorpe' href='#section-6'>#</a>
</div>
<p>To specify that this method requires authentication, we can simply set the
keyword argument <code>user_required</code> to <code>True</code> in the <code>MyModel.method</code> decorator. The
remaining arguments to the decorator are the same as in <a href="/examples/basic.html">basic</a>. Once
<code>user_required</code> is set, the method will first determine if a user has been
detected from the token sent with the request (if any was sent it all) and
will return an HTTP 401 Unauthorized if no valid user is detected. In the
case of a 401, the method will not be executed. Conversely, if method
execution occurs, <code>user_required=True</code> will guarantee that the current user is
valid.</p>
</div>
<div class='code'>
<div class="highlight"><pre> <span class="nd">@MyModel.method</span><span class="p">(</span><span class="n">user_required</span><span class="o">=</span><span class="bp">True</span><span class="p">,</span>
<span class="n">path</span><span class="o">=</span><span class="s">&#39;mymodel&#39;</span><span class="p">,</span> <span class="n">http_method</span><span class="o">=</span><span class="s">&#39;POST&#39;</span><span class="p">,</span> <span class="n">name</span><span class="o">=</span><span class="s">&#39;mymodel.insert&#39;</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">MyModelInsert</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">my_model</span><span class="p">):</span></pre></div>
</div>
</div>
<div class='clearall'></div>
<div class='section' id='section-7'>
<div class='docs'>
<div class='octowrap'>
<a class='octothorpe' href='#section-7'>#</a>
</div>
<p>Since <code>user_required</code> is <code>True</code>, we know <code>endpoints.get_current_user</code> will
return a valid user.</p>
</div>
<div class='code'>
<div class="highlight"><pre> <span class="n">my_model</span><span class="o">.</span><span class="n">owner</span> <span class="o">=</span> <span class="n">endpoints</span><span class="o">.</span><span class="n">get_current_user</span><span class="p">()</span></pre></div>
</div>
</div>
<div class='clearall'></div>
<div class='section' id='section-8'>
<div class='docs'>
<div class='octowrap'>
<a class='octothorpe' href='#section-8'>#</a>
</div>
<p>Also note, since we don't override the default ProtoRPC message schema,
API users can send an owner object in the request, but we overwrite the
model property with the current user before the entity is inserted into
the datastore and this put operation will only occur if a valid token
identifying the user was sent in the Authorization header.</p>
</div>
<div class='code'>
<div class="highlight"><pre> <span class="n">my_model</span><span class="o">.</span><span class="n">put</span><span class="p">()</span>
<span class="k">return</span> <span class="n">my_model</span></pre></div>
</div>
</div>
<div class='clearall'></div>
<div class='section' id='section-9'>
<div class='docs'>
<div class='octowrap'>
<a class='octothorpe' href='#section-9'>#</a>
</div>
<p>As above with <code>MyModelInsert</code>, we add <code>user_required=True</code> to the arguments
passed to the <code>MyModel.query_method</code> decorator in <a href="/examples/basic.html">basic</a>. Therefore,
only queries can be made by a valid user.</p>
</div>
<div class='code'>
<div class="highlight"><pre> <span class="nd">@MyModel.query_method</span><span class="p">(</span><span class="n">user_required</span><span class="o">=</span><span class="bp">True</span><span class="p">,</span>
<span class="n">path</span><span class="o">=</span><span class="s">&#39;mymodels&#39;</span><span class="p">,</span> <span class="n">name</span><span class="o">=</span><span class="s">&#39;mymodel.list&#39;</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">MyModelList</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">query</span><span class="p">):</span></pre></div>
</div>
</div>
<div class='clearall'></div>
<div class='section' id='section-10'>
<div class='docs'>
<div class='octowrap'>
<a class='octothorpe' href='#section-10'>#</a>
</div>
<p>We only allow users to query the <code>MyModel</code> entities that they have created,
so query using owner equal to the current user. Since <code>user_required</code> is
set, we know <code>get_current_user</code> will return a valid user.</p>
</div>
<div class='code'>
<div class="highlight"><pre> <span class="k">return</span> <span class="n">query</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="n">MyModel</span><span class="o">.</span><span class="n">owner</span> <span class="o">==</span> <span class="n">endpoints</span><span class="o">.</span><span class="n">get_current_user</span><span class="p">())</span>
</pre></div>
</div>
</div>
<div class='clearall'></div>
<div class='section' id='section-11'>
<div class='docs'>
<div class='octowrap'>
<a class='octothorpe' href='#section-11'>#</a>
</div>
</div>
<div class='code'>
<div class="highlight"><pre>
<span class="n">application</span> <span class="o">=</span> <span class="n">endpoints</span><span class="o">.</span><span class="n">api_server</span><span class="p">([</span><span class="n">MyApi</span><span class="p">],</span> <span class="n">restricted</span><span class="o">=</span><span class="bp">False</span><span class="p">)</span>
</pre></div>
</div>
</div>
<div class='clearall'></div>
<div class='section' id='section-12'>
<div class='docs'>
<div class='octowrap'>
<a class='octothorpe' href='#section-12'>#</a>
</div>
<p>Head on to the next sample <a href="/examples/paging.html">paging<a>
or head back to the <a href="/">main page</a>.</p>
</div>
</div>
<div class='clearall'></div>
</div>
</body>