mirror of
https://github.com/almet/notmyidea.git
synced 2025-04-28 19:42:37 +02:00
336 lines
No EOL
29 KiB
HTML
336 lines
No EOL
29 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
|
<meta http-equiv="content-type" content="text/html; charset=utf-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1">
|
|
<link rel="shortcut icon" type="image/x-icon" href="favicon.ico" />
|
|
|
|
<title>Refactoring Cornice - Alexis - Carnets en ligne</title>
|
|
|
|
<meta charset="utf-8" />
|
|
<link href="https://blog.notmyidea.org/feeds/all.atom.xml" type="application/atom+xml" rel="alternate" title="Alexis - Carnets en ligne Full Atom Feed" />
|
|
<link rel="stylesheet" href="https://blog.notmyidea.org/theme/css/poole.css"/>
|
|
<link rel="stylesheet" href="https://blog.notmyidea.org/theme/css/syntax.css"/>
|
|
<link rel="stylesheet" href="https://blog.notmyidea.org/theme/css/lanyon.css"/>
|
|
<link rel="stylesheet" href="//fonts.googleapis.com/css?family=PT+Serif:400,400italic,700%7CPT+Sans:400">
|
|
<link rel="stylesheet" href="https://blog.notmyidea.org/theme/css/styles.css"/>
|
|
|
|
|
|
|
|
<style>
|
|
|
|
h1 {
|
|
font-family: "Avant Garde", Avantgarde, "Century Gothic", CenturyGothic, "AppleGothic", sans-serif;
|
|
padding: 80px 50px;
|
|
text-align: center;
|
|
text-transform: uppercase;
|
|
text-rendering: optimizeLegibility;
|
|
color: #202020;
|
|
letter-spacing: .1em;
|
|
text-shadow:
|
|
-1px -1px 1px #111,
|
|
2px 2px 1px #eaeaea;
|
|
}
|
|
|
|
#main {
|
|
text-align: justify;
|
|
text-justify: inter-word;
|
|
}
|
|
#main h1 {
|
|
padding: 10px;
|
|
}
|
|
|
|
.post-headline {
|
|
padding: 15px;
|
|
text-align: center;
|
|
}
|
|
</style>
|
|
</head>
|
|
|
|
<body>
|
|
<!-- Target for toggling the sidebar `.sidebar-checkbox` is for regular
|
|
styles, `#sidebar-checkbox` for behavior. -->
|
|
<input type="checkbox" class="sidebar-checkbox" id="sidebar-checkbox">
|
|
<!-- Toggleable sidebar -->
|
|
<div class="sidebar" id="sidebar">
|
|
<div class="sidebar-item">
|
|
<div class="profile">
|
|
<img src="https://blog.notmyidea.org/theme/img/profile.png"/>
|
|
</div>
|
|
</div>
|
|
|
|
<nav class="sidebar-nav">
|
|
<a class="sidebar-nav-item" href="/">Articles</a>
|
|
|
|
<a class="sidebar-nav-item" href="https://www.vieuxsinge.com">Brasserie du Vieux Singe</a>
|
|
<a class="sidebar-nav-item" href="http://blog.notmyidea.org/pages/about.html">A propos</a>
|
|
<a class="sidebar-nav-item" href="https://twitter.com/ametaireau">Messages courts</a>
|
|
<a class="sidebar-nav-item" href="https://github.com/almet">Code</a>
|
|
</nav>
|
|
</div> <div class="wrap">
|
|
<div class="masthead">
|
|
<div class="container">
|
|
<h3 class="masthead-title">
|
|
<a href="https://blog.notmyidea.org/" title="Home">Alexis - Carnets en ligne</a>
|
|
</h3>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="container content">
|
|
<div id="main" class="posts">
|
|
<h1 class="post-title">Refactoring Cornice</h1>
|
|
|
|
<span class="post-date">
|
|
01 mai 2012, dans <a class="no-color" href="category/technologie.html">Technologie</a>
|
|
</span>
|
|
<img id="illustration" class="illustration-Technologie" src="" />
|
|
|
|
<div class="post article">
|
|
<h1>🌟</h1>
|
|
|
|
<p>After working for a while with <a href="http://cornice.readthedocs.com">Cornice</a>
|
|
to define our APIs at <a href="http://docs.services.mozilla.com">Services</a>, it
|
|
turned out that the current implementation wasn't flexible enough to
|
|
allow us to do what we wanted to do.</p>
|
|
<p>Cornice started as a toolkit on top of the
|
|
<a href="http://docs.pylonsproject.org/en/latest/docs/pyramid.html">pyramid</a>
|
|
routing system, allowing to register services in a simpler way. Then we
|
|
added some niceties such as the ability to automatically generate the
|
|
services documentation or returning the correct HTTP headers <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html">as defined
|
|
by the HTTP
|
|
specification</a>
|
|
without the need from the developer to deal with them nor to know them.</p>
|
|
<p>If you're not familiar with Cornice, here is how you define a simple
|
|
service with it:</p>
|
|
<p>``` sourceCode python
|
|
from cornice.service import Service
|
|
bar = Service(path="/bar")</p>
|
|
<p>@bar.get(validators=validators, accept='application/json')
|
|
def get_drink(request):
|
|
# do something with the request (with moderation).</p>
|
|
<div class="highlight"><pre><span></span><span class="nv">This</span> <span class="nv">external</span> <span class="nv">API</span> <span class="nv">is</span> <span class="nv">quite</span> <span class="nv">cool</span>, <span class="nv">as</span> <span class="nv">it</span> <span class="nv">allows</span> <span class="nv">to</span> <span class="k">do</span> <span class="nv">a</span> <span class="nv">bunch</span> <span class="nv">of</span> <span class="nv">things</span>
|
|
<span class="nv">quite</span> <span class="nv">easily</span>. <span class="k">For</span> <span class="nv">instance</span>, <span class="nv">we</span><span class="s1">'</span><span class="s">ve written our</span>
|
|
[<span class="nv">token</span><span class="o">-</span><span class="nv">server</span>]<span class="ss">(</span><span class="nv">https</span>:<span class="o">//</span><span class="nv">github</span>.<span class="nv">com</span><span class="o">/</span><span class="nv">mozilla</span><span class="o">-</span><span class="nv">services</span><span class="o">/</span><span class="nv">tokenserver</span><span class="ss">)</span> <span class="nv">code</span> <span class="nv">on</span>
|
|
<span class="nv">top</span> <span class="nv">of</span> <span class="nv">this</span> <span class="nv">in</span> <span class="nv">a</span> <span class="nv">blast</span>.
|
|
|
|
## <span class="nv">The</span> <span class="nv">burden</span>
|
|
|
|
<span class="nv">The</span> <span class="nv">problem</span> <span class="nv">with</span> <span class="nv">this</span> <span class="nv">was</span> <span class="nv">that</span> <span class="nv">we</span> <span class="nv">were</span> <span class="nv">mixing</span> <span class="nv">internally</span> <span class="nv">the</span> <span class="nv">service</span>
|
|
<span class="nv">description</span> <span class="nv">logic</span> <span class="nv">with</span> <span class="nv">the</span> <span class="nv">route</span> <span class="nv">registration</span> <span class="nv">one</span>. <span class="nv">The</span> <span class="nv">way</span> <span class="nv">we</span> <span class="nv">were</span> <span class="nv">doing</span>
|
|
<span class="nv">this</span> <span class="nv">was</span> <span class="nv">via</span> <span class="nv">an</span> <span class="nv">extensive</span> <span class="nv">use</span> <span class="nv">of</span> <span class="nv">decorators</span> <span class="nv">internally</span>.
|
|
|
|
<span class="nv">The</span> <span class="nv">API</span> <span class="nv">of</span> <span class="nv">the</span> <span class="nv">cornice</span>.<span class="nv">service</span>.<span class="nv">Service</span> <span class="nv">class</span> <span class="nv">was</span> <span class="nv">as</span> <span class="nv">following</span>
|
|
<span class="ss">(</span><span class="nv">simplified</span> <span class="nv">so</span> <span class="nv">you</span> <span class="nv">can</span> <span class="nv">get</span> <span class="nv">the</span> <span class="nv">gist</span> <span class="nv">of</span> <span class="nv">it</span><span class="ss">)</span>.
|
|
|
|
``` <span class="nv">sourceCode</span> <span class="nv">python</span>
|
|
<span class="nv">class</span> <span class="nv">Service</span><span class="ss">(</span><span class="nv">object</span><span class="ss">)</span>:
|
|
|
|
<span class="nv">def</span> <span class="nv">__init__</span><span class="ss">(</span><span class="nv">self</span>, <span class="o">**</span><span class="nv">service_kwargs</span><span class="ss">)</span>:
|
|
# <span class="nv">some</span> <span class="nv">information</span>, <span class="nv">such</span> <span class="nv">as</span> <span class="nv">the</span> <span class="nv">colander</span> <span class="nv">schemas</span> <span class="ss">(</span><span class="k">for</span> <span class="nv">validation</span><span class="ss">)</span>,
|
|
# <span class="nv">the</span> <span class="nv">defined</span> <span class="nv">methods</span> <span class="nv">that</span> <span class="nv">had</span> <span class="nv">been</span> <span class="nv">registered</span> <span class="k">for</span> <span class="nv">this</span> <span class="nv">service</span> <span class="nv">and</span>
|
|
# <span class="nv">some</span> <span class="nv">other</span> <span class="nv">things</span> <span class="nv">were</span> <span class="nv">registered</span> <span class="nv">as</span> <span class="nv">instance</span> <span class="nv">variables</span>.
|
|
<span class="nv">self</span>.<span class="nv">schemas</span> <span class="o">=</span> <span class="nv">service_kwargs</span>.<span class="nv">get</span><span class="ss">(</span><span class="nv">schema</span><span class="s1">'</span><span class="s">, None)</span>
|
|
<span class="nv">self</span>.<span class="nv">defined_methods</span> <span class="o">=</span> []
|
|
<span class="nv">self</span>.<span class="nv">definitions</span> <span class="o">=</span> []
|
|
|
|
<span class="nv">def</span> <span class="nv">api</span><span class="ss">(</span><span class="nv">self</span>, <span class="o">**</span><span class="nv">view_kwargs</span><span class="ss">)</span>:
|
|
<span class="s2">"""</span><span class="s">This method is a decorator that is being used by some alias</span>
|
|
<span class="nv">methods</span>.
|
|
<span class="s2">"""</span>
|
|
<span class="nv">def</span> <span class="nv">wrapper</span><span class="ss">(</span><span class="nv">view</span><span class="ss">)</span>:
|
|
# <span class="nv">all</span> <span class="nv">the</span> <span class="nv">logic</span> <span class="nv">goes</span> <span class="nv">here</span>. <span class="nv">And</span> <span class="nv">when</span> <span class="nv">I</span> <span class="nv">mean</span> <span class="nv">all</span> <span class="nv">the</span> <span class="nv">logic</span>, <span class="nv">I</span>
|
|
# <span class="nv">mean</span> <span class="nv">it</span>.
|
|
# <span class="mi">1</span>. <span class="nv">we</span> <span class="nv">are</span> <span class="nv">registering</span> <span class="nv">a</span> <span class="nv">callback</span> <span class="nv">to</span> <span class="nv">the</span> <span class="nv">pyramid</span> <span class="nv">routing</span>
|
|
# <span class="nv">system</span> <span class="nv">so</span> <span class="nv">it</span> <span class="nv">gets</span> <span class="nv">called</span> <span class="nv">whenever</span> <span class="nv">the</span> <span class="nv">module</span> <span class="nv">using</span> <span class="nv">the</span>
|
|
# <span class="nv">decorator</span> <span class="nv">is</span> <span class="nv">used</span>.
|
|
# <span class="mi">2</span>. <span class="nv">we</span> <span class="nv">are</span> <span class="nv">transforming</span> <span class="nv">the</span> <span class="nv">passed</span> <span class="nv">arguments</span> <span class="nv">so</span> <span class="nv">they</span> <span class="nv">conform</span>
|
|
# <span class="nv">to</span> <span class="nv">what</span> <span class="nv">is</span> <span class="nv">expected</span> <span class="nv">by</span> <span class="nv">the</span> <span class="nv">pyramid</span> <span class="nv">routing</span> <span class="nv">system</span>.
|
|
# <span class="mi">3</span>. <span class="nv">We</span> <span class="nv">are</span> <span class="nv">storing</span> <span class="nv">some</span> <span class="nv">of</span> <span class="nv">the</span> <span class="nv">passed</span> <span class="nv">arguments</span> <span class="nv">into</span> <span class="nv">the</span>
|
|
# <span class="nv">object</span> <span class="nv">so</span> <span class="nv">we</span> <span class="nv">can</span> <span class="nv">retrieve</span> <span class="nv">them</span> <span class="nv">later</span> <span class="nv">on</span>.
|
|
# <span class="mi">4</span>. <span class="nv">Also</span>, <span class="nv">we</span> <span class="nv">are</span> <span class="nv">transforming</span> <span class="nv">the</span> <span class="nv">passed</span> <span class="nv">view</span> <span class="nv">before</span>
|
|
# <span class="nv">registering</span> <span class="nv">it</span> <span class="nv">in</span> <span class="nv">the</span> <span class="nv">pyramid</span> <span class="nv">routing</span> <span class="nv">system</span> <span class="nv">so</span> <span class="nv">that</span> <span class="nv">it</span>
|
|
# <span class="nv">can</span> <span class="k">do</span> <span class="nv">what</span> <span class="nv">Cornice</span> <span class="nv">wants</span> <span class="nv">it</span> <span class="nv">to</span> <span class="k">do</span> <span class="ss">(</span><span class="nv">checking</span> <span class="nv">some</span> <span class="nv">rules</span>,
|
|
# <span class="nv">applying</span> <span class="nv">validators</span> <span class="nv">and</span> <span class="nv">filters</span> <span class="nv">etc</span>.
|
|
<span class="k">return</span> <span class="nv">wrapper</span>
|
|
|
|
<span class="nv">def</span> <span class="nv">get</span><span class="ss">(</span><span class="nv">self</span>, <span class="o">**</span><span class="nv">kwargs</span><span class="ss">)</span>:
|
|
<span class="s2">"""</span><span class="s">A shortcut of the api decorator</span><span class="s2">"""</span>
|
|
<span class="k">return</span> <span class="nv">self</span>.<span class="nv">api</span><span class="ss">(</span><span class="nv">request_method</span><span class="o">=</span><span class="s2">"</span><span class="s">GET</span><span class="s2">"</span>, <span class="o">**</span><span class="nv">kwargs</span><span class="ss">)</span>
|
|
</pre></div>
|
|
|
|
|
|
<p>I encourage you to go read <a href="https://github.com/mozilla-services/cornice/blob/4e0392a2ae137b6a11690459bcafd7325e86fa9e/cornice/service.py#L44">the entire
|
|
file</a>.
|
|
on github so you can get a better opinion on how all of this was done.</p>
|
|
<p>A bunch of things are wrong:</p>
|
|
<ul>
|
|
<li>first, we are not separating the description logic from the
|
|
registration one. This causes problems when we need to access the
|
|
parameters passed to the service, because the parameters you get are
|
|
not exactly the ones you passed but the ones that the pyramid
|
|
routing system is expecting. For instance, if you want to get the
|
|
view get_drink, you will instead get a decorator which contains
|
|
this view.</li>
|
|
<li>second, we are using decorators as APIs we expose. Even if
|
|
decorators are good as shortcuts, they shouldn't be the default way
|
|
to deal with an API. A good example of this is <a href="https://github.com/mozilla-services/cornice/blob/4e0392a2ae137b6a11690459bcafd7325e86fa9e/cornice/resource.py#L56">how the resource
|
|
module consumes this
|
|
API</a>.
|
|
This is quite hard to follow.</li>
|
|
<li>Third, in the api method, a bunch of things are done regarding
|
|
inheritance of parameters that are passed to the service or to its
|
|
decorator methods. This leaves you with a really hard to follow path
|
|
when it comes to add new parameters to your API.</li>
|
|
</ul>
|
|
<h2 id="how-do-we-improve-this">How do we improve this?</h2>
|
|
<p>Python is great because it allows you to refactor things in an easy way.
|
|
What I did isn't breaking our APIs, but make things way simpler to
|
|
hack-on. One example is that it allowed me to add features that we
|
|
wanted to bring to Cornice really quickly (a matter of minutes), without
|
|
touching the API that much.</p>
|
|
<p>Here is the gist of the new architecture:</p>
|
|
<p>``` sourceCode python
|
|
class Service(object):
|
|
# we define class-level variables that will be the default values for
|
|
# this service. This makes things more extensible than it was before.
|
|
renderer = 'simplejson'
|
|
default_validators = DEFAULT_VALIDATORS
|
|
default_filters = DEFAULT_FILTERS</p>
|
|
<div class="highlight"><pre><span></span># <span class="nv">we</span> <span class="nv">also</span> <span class="nv">have</span> <span class="nv">some</span> <span class="nv">class</span><span class="o">-</span><span class="nv">level</span> <span class="nv">parameters</span> <span class="nv">that</span> <span class="nv">are</span> <span class="nv">useful</span> <span class="nv">to</span> <span class="nv">know</span>
|
|
# <span class="nv">which</span> <span class="nv">parameters</span> <span class="nv">are</span> <span class="nv">supposed</span> <span class="nv">to</span> <span class="nv">be</span> <span class="nv">lists</span> <span class="ss">(</span><span class="nv">and</span> <span class="nv">so</span> <span class="nv">converted</span> <span class="nv">as</span> <span class="nv">such</span><span class="ss">)</span>
|
|
# <span class="nv">or</span> <span class="nv">which</span> <span class="nv">are</span> <span class="nv">mandatory</span>.
|
|
<span class="nv">mandatory_arguments</span> <span class="o">=</span> <span class="ss">(</span><span class="s1">'</span><span class="s">renderer</span><span class="s1">'</span>,<span class="ss">)</span>
|
|
<span class="nv">list_arguments</span> <span class="o">=</span> <span class="ss">(</span><span class="s1">'</span><span class="s">validators</span><span class="s1">'</span>, <span class="s1">'</span><span class="s">filters</span><span class="s1">'</span><span class="ss">)</span>
|
|
|
|
<span class="nv">def</span> <span class="nv">__init__</span><span class="ss">(</span><span class="nv">self</span>, <span class="nv">name</span>, <span class="nv">path</span>, <span class="nv">description</span><span class="o">=</span><span class="nv">None</span>, <span class="o">**</span><span class="nv">kw</span><span class="ss">)</span>:
|
|
# <span class="nv">setup</span> <span class="nv">name</span>, <span class="nv">path</span> <span class="nv">and</span> <span class="nv">description</span> <span class="nv">as</span> <span class="nv">instance</span> <span class="nv">variables</span>
|
|
<span class="nv">self</span>.<span class="nv">name</span> <span class="o">=</span> <span class="nv">name</span>
|
|
<span class="nv">self</span>.<span class="nv">path</span> <span class="o">=</span> <span class="nv">path</span>
|
|
<span class="nv">self</span>.<span class="nv">description</span> <span class="o">=</span> <span class="nv">description</span>
|
|
|
|
# <span class="nv">convert</span> <span class="nv">the</span> <span class="nv">arguments</span> <span class="nv">passed</span> <span class="nv">to</span> <span class="nv">something</span> <span class="nv">we</span> <span class="nv">want</span> <span class="nv">to</span> <span class="nv">store</span>
|
|
# <span class="nv">and</span> <span class="k">then</span> <span class="nv">store</span> <span class="nv">them</span> <span class="nv">as</span> <span class="nv">attributes</span> <span class="nv">of</span> <span class="nv">the</span> <span class="nv">instance</span> <span class="ss">(</span><span class="nv">because</span> <span class="nv">they</span>
|
|
# <span class="nv">were</span> <span class="nv">passed</span> <span class="nv">to</span> <span class="nv">the</span> <span class="nv">constructor</span>
|
|
<span class="nv">self</span>.<span class="nv">arguments</span> <span class="o">=</span> <span class="nv">self</span>.<span class="nv">get_arguments</span><span class="ss">(</span><span class="nv">kw</span><span class="ss">)</span>
|
|
<span class="k">for</span> <span class="nv">key</span>, <span class="nv">value</span> <span class="nv">in</span> <span class="nv">self</span>.<span class="nv">arguments</span>.<span class="nv">items</span><span class="ss">()</span>:
|
|
<span class="nv">setattr</span><span class="ss">(</span><span class="nv">self</span>, <span class="nv">key</span>, <span class="nv">value</span><span class="ss">)</span>
|
|
|
|
# <span class="nv">we</span> <span class="nv">keep</span> <span class="nv">having</span> <span class="nv">the</span> <span class="nv">defined_methods</span> <span class="nv">tuple</span> <span class="nv">and</span> <span class="nv">the</span> <span class="nv">list</span> <span class="nv">of</span>
|
|
# <span class="nv">definitions</span> <span class="nv">that</span> <span class="nv">are</span> <span class="nv">done</span> <span class="k">for</span> <span class="nv">this</span> <span class="nv">service</span>
|
|
<span class="nv">self</span>.<span class="nv">defined_methods</span> <span class="o">=</span> []
|
|
<span class="nv">self</span>.<span class="nv">definitions</span> <span class="o">=</span> []
|
|
|
|
<span class="nv">def</span> <span class="nv">get_arguments</span><span class="ss">(</span><span class="nv">self</span>, <span class="nv">conf</span><span class="o">=</span><span class="nv">None</span><span class="ss">)</span>:
|
|
<span class="s2">"""</span><span class="s">Returns a dict of arguments. It does all the conversions for</span>
|
|
<span class="nv">you</span>, <span class="nv">and</span> <span class="nv">uses</span> <span class="nv">the</span> <span class="nv">information</span> <span class="nv">that</span> <span class="nv">were</span> <span class="nv">defined</span> <span class="nv">at</span> <span class="nv">the</span> <span class="nv">instance</span>
|
|
<span class="nv">level</span> <span class="nv">as</span> <span class="nv">fallbacks</span>.
|
|
<span class="s2">"""</span>
|
|
|
|
<span class="nv">def</span> <span class="nv">add_view</span><span class="ss">(</span><span class="nv">self</span>, <span class="nv">method</span>, <span class="nv">view</span>, <span class="o">**</span><span class="nv">kwargs</span><span class="ss">)</span>:
|
|
<span class="s2">"""</span><span class="s">Add a view to this service.</span><span class="s2">"""</span>
|
|
# <span class="nv">this</span> <span class="nv">is</span> <span class="nv">really</span> <span class="nv">simple</span> <span class="nv">and</span> <span class="nv">looks</span> <span class="nv">a</span> <span class="nv">lot</span> <span class="nv">like</span> <span class="nv">this</span>
|
|
<span class="nv">method</span> <span class="o">=</span> <span class="nv">method</span>.<span class="nv">upper</span><span class="ss">()</span>
|
|
<span class="nv">self</span>.<span class="nv">definitions</span>.<span class="nv">append</span><span class="ss">((</span><span class="nv">method</span>, <span class="nv">view</span>, <span class="nv">args</span><span class="ss">))</span>
|
|
<span class="k">if</span> <span class="nv">method</span> <span class="nv">not</span> <span class="nv">in</span> <span class="nv">self</span>.<span class="nv">defined_methods</span>:
|
|
<span class="nv">self</span>.<span class="nv">defined_methods</span>.<span class="nv">append</span><span class="ss">(</span><span class="nv">method</span><span class="ss">)</span>
|
|
|
|
<span class="nv">def</span> <span class="nv">decorator</span><span class="ss">(</span><span class="nv">self</span>, <span class="nv">method</span>, <span class="o">**</span><span class="nv">kwargs</span><span class="ss">)</span>:
|
|
<span class="s2">"""</span><span class="s">This is only another interface to the add_view method, exposing a</span>
|
|
<span class="nv">decorator</span> <span class="nv">interface</span><span class="s2">"""</span>
|
|
<span class="nv">def</span> <span class="nv">wrapper</span><span class="ss">(</span><span class="nv">view</span><span class="ss">)</span>:
|
|
<span class="nv">self</span>.<span class="nv">add_view</span><span class="ss">(</span><span class="nv">method</span>, <span class="nv">view</span>, <span class="o">**</span><span class="nv">kwargs</span><span class="ss">)</span>
|
|
<span class="k">return</span> <span class="nv">view</span>
|
|
<span class="k">return</span> <span class="nv">wrapper</span>
|
|
</pre></div>
|
|
|
|
|
|
<div class="highlight"><pre><span></span><span class="n">So</span><span class="p">,</span> <span class="n">the</span> <span class="n">service</span> <span class="k">is</span> <span class="n">now</span> <span class="k">only</span> <span class="n">storing</span> <span class="n">the</span> <span class="n">information</span> <span class="n">that</span><span class="err">'</span><span class="n">s</span> <span class="n">passed</span> <span class="k">to</span> <span class="n">it</span>
|
|
<span class="k">and</span> <span class="k">nothing</span> <span class="k">more</span><span class="p">.</span> <span class="k">No</span> <span class="k">more</span> <span class="n">route</span> <span class="n">registration</span> <span class="n">logic</span> <span class="n">goes</span> <span class="n">here</span><span class="p">.</span> <span class="k">Instead</span><span class="p">,</span> <span class="n">I</span>
|
|
<span class="n">added</span> <span class="n">this</span> <span class="k">as</span> <span class="n">another</span> <span class="n">feature</span><span class="p">,</span> <span class="n">even</span> <span class="k">in</span> <span class="n">a</span> <span class="n">different</span> <span class="n">module</span><span class="p">.</span> <span class="n">The</span> <span class="k">function</span>
|
|
<span class="k">is</span> <span class="n">named</span> <span class="n">register</span><span class="err">\</span><span class="n">_service</span><span class="err">\</span><span class="n">_views</span> <span class="k">and</span> <span class="n">has</span> <span class="n">the</span> <span class="n">following</span> <span class="n">signature</span><span class="p">:</span>
|
|
|
|
<span class="o">```</span> <span class="n">sourceCode</span> <span class="n">python</span>
|
|
<span class="n">register_service_views</span><span class="p">(</span><span class="n">config</span><span class="p">,</span> <span class="n">service</span><span class="p">)</span>
|
|
</pre></div>
|
|
|
|
|
|
<p>To sum up, here are the changes I made:</p>
|
|
<ol>
|
|
<li>Service description is now separated from the route registration.</li>
|
|
<li>cornice.service.Service now provides a hook_view method, which is
|
|
not a decorator. decorators are still present but they are optional
|
|
(you don't need to use them if you don't want to).</li>
|
|
<li>Everything has been decoupled as much as possible, meaning that you
|
|
really can use the Service class as a container of information about
|
|
the services you are describing. This is especially useful when
|
|
generating documentation.</li>
|
|
</ol>
|
|
<p>As a result, it is now possible to use Cornice with other frameworks. It
|
|
means that you can stick with the service description but plug any other
|
|
framework on top of it. cornice.services.Service is now only a
|
|
description tool. To register routes, one would need to read the
|
|
information contained into this service and inject the right parameters
|
|
into their preferred routing system.</p>
|
|
<p>However, no integration with other frameworks is done at the moment even
|
|
if the design allows it.</p>
|
|
<p>The same way, the sphinx description layer is now only a consumer of
|
|
this service description tool: it looks at what's described and build-up
|
|
the documentation from it.</p>
|
|
<p>The resulting branch is not merged yet. Still, you can <a href="https://github.com/mozilla-services/cornice/tree/refactor-the-world">have a look at
|
|
it</a>.</p>
|
|
<p>Any suggestions are of course welcome :-)</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<label for="sidebar-checkbox" class="sidebar-toggle"></label>
|
|
|
|
<script>
|
|
(function(document) {
|
|
var i = 0;
|
|
// snip empty header rows since markdown can't
|
|
var rows = document.querySelectorAll('tr');
|
|
for(i=0; i<rows.length; i++) {
|
|
var ths = rows[i].querySelectorAll('th');
|
|
var rowlen = rows[i].children.length;
|
|
if (ths.length > 0 && ths.length === rowlen) {
|
|
rows[i].remove();
|
|
}
|
|
}
|
|
})(document);
|
|
</script>
|
|
|
|
<script>
|
|
/* Lanyon & Poole are Copyright (c) 2014 Mark Otto. Adapted to Pelican 20141223 and extended a bit by @thomaswilley */
|
|
(function(document) {
|
|
var toggle = document.querySelector('.sidebar-toggle');
|
|
var sidebar = document.querySelector('#sidebar');
|
|
var checkbox = document.querySelector('#sidebar-checkbox');
|
|
document.addEventListener('click', function(e) {
|
|
var target = e.target;
|
|
if(!checkbox.checked ||
|
|
sidebar.contains(target) ||
|
|
(target === checkbox || target === toggle)) return;
|
|
checkbox.checked = false;
|
|
}, false);
|
|
})(document);
|
|
</script>
|
|
<!-- Piwik -->
|
|
<script type="text/javascript">
|
|
var _paq = _paq || [];
|
|
_paq.push(['trackPageView']);
|
|
_paq.push(['enableLinkTracking']);
|
|
(function() {
|
|
var u="//tracker.notmyidea.org/";
|
|
_paq.push(['setTrackerUrl', u+'piwik.php']);
|
|
_paq.push(['setSiteId', 3]);
|
|
var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0];
|
|
g.type='text/javascript'; g.async=true; g.defer=true; g.src=u+'piwik.js'; s.parentNode.insertBefore(g,s);
|
|
})();
|
|
</script>
|
|
<noscript><p><img src="//tracker.notmyidea.org/piwik.php?idsite=3" style="border:0;" alt="" /></p></noscript>
|
|
<!-- End Piwik Code -->
|
|
</div>
|
|
</body>
|
|
</html> |