-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathgraphql-in-the-python-world.html
More file actions
121 lines (94 loc) · 28.7 KB
/
graphql-in-the-python-world.html
File metadata and controls
121 lines (94 loc) · 28.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
<!DOCTYPE html>
<html> <head lang=en><meta charset=UTF-8><title>GraphQL in the Python World | EF</title><link href=//cdnjs.cloudflare.com/ajax/libs/font-awesome/4.2.0/css/font-awesome.min.css rel=stylesheet><link href=http://fonts.googleapis.com/css?family=Inconsolata rel=stylesheet type=text/css><link rel=stylesheet href=http://nafiulis.me/theme/css/main.css><link rel=stylesheet href=http://nafiulis.me/theme/css/pygment.css><script src=http://nafiulis.me/theme/js/jquery.min.js></script><script src=http://nafiulis.me/theme/js/main.js></script></head> <body> <!--Heading at the top saying "Engineering Fantasy"--> <div id=header_top> <div class=title> <a href=http://nafiulis.me><span id=engineering>Engineering</span><span id=fantasy>Fantasy</span></a> </div> </div> <button type=button class="js-menu-trigger sliding-menu-button button-nav"> <img src=https://raw.githubusercontent.com/thoughtbot/refills/master/source/images/menu-white.png alt="Menu Icon"> </button> <!--Navigation Bar--> <nav class="js-menu sliding-menu-content"> <span class=section-header>Pages</span> <ul> <li><a href=http://nafiulis.me>Home</a></li> <li><a href=http://nafiulis.me/tags.html>Tags</a></li> <li><a href=http://nafiulis.me/pages/about-me.html>About Me</a></li> </ul> <span class=section-header>Categories</span> <ul> <li><a href=http://nafiulis.me/category/anime.html>Anime</a></li> <li><a href=http://nafiulis.me/category/education.html>Education</a></li> <li><a href=http://nafiulis.me/category/productivity.html>Productivity</a></li> <li><a href=http://nafiulis.me/category/programming.html>programming</a></li> <li><a href=http://nafiulis.me/category/rants.html>rants</a></li> </ul> </nav> <div class="js-menu-screen menu-screen"></div> <!--Main Container--> <div class=container> <!--Top most menu--> <div id=menu> <div class=left> <a href=http://nafiulis.me/feeds/all.atom.xml><i class="fa fa-rss
icon"></i></a> <a href=https://twitter.com/gamesbrainiac><i class="fa fa-twitter icon"></i></a> </div> <div class=center> <h1 class=message>Nafiul Islam on casting spells with code</h1> </div> <div class=right> <a href=https://github.com/gamesbrainiac><i class="fa fa-github icon"></i></a> <a href=http://stackoverflow.com/users/1624921/games-brainiac><i class="fa fa-stack-overflow icon" style="padding-right: 30px"></i></a> </div> </div> <!--Main blog list container--> <div id=blogroll> <div class=article-container> <h1>GraphQL in the Python World</h1> <p class=time>Friday, 23 June 2017</p> <div class=article-content> <div class="contents topic" id=table-of-contents> <p class="topic-title first">Table of Contents</p> <ul class=simple> <li><a class="reference internal" href=#getting-started id=id2>Getting Started</a><ul> <li><a class="reference internal" href=#here-comes-python id=id3>Here Comes Python</a></li> <li><a class="reference internal" href=#playing-with-graphene id=id4>Playing with Graphene</a></li> </ul> </li> <li><a class="reference internal" href=#basic-types id=id5>Basic Types</a><ul> <li><a class="reference internal" href=#a-few-opinions id=id6>A Few Opinions</a></li> </ul> </li> <li><a class="reference internal" href=#integration-with-orms id=id7>Integration with ORMs</a><ul> <li><a class="reference internal" href=#django id=id8>Django</a></li> <li><a class="reference internal" href=#sqlalchemy-and-others id=id9>SQLAlchemy and Others</a></li> </ul> </li> <li><a class="reference internal" href=#integration-with-web-frameworks id=id10>Integration with Web Frameworks</a></li> <li><a class="reference internal" href=#final-thoughts id=id11>Final Thoughts</a></li> </ul> </div> <p>Not too long ago, Facebook unveiled <a class="reference external" href=https://code.facebook.com/posts/1691455094417024/graphql-a-data-query-language/ >Graphql</a>. This was thought up to be a flexible data access layer designed to work as a simple interface on top of heterogeneous data sources. Not long after facebook had introduced it, github announced that the latest version of its API (version 4) would indeed be a <a class="reference external" href=https://developer.github.com/v4/ >GraphQL API</a>. Many other companies have followed including Meteor, Pinterest, Shopify to name a few.</p> <p>At its heart, Graphql is designed to replace REST APIs. It also has a proper specification so that developers aren't constantly fighting over the <em>proper</em> definition of Graphql. It has documentation inbuilt, with its powerful graphiql query application that allows people to quickly check out the results of a particular query, and get code completion on the fly, as they are writing the query.</p> <img alt="Graphql on Github" class=align-center src=/images/graphql_01.png> <div class=section id=getting-started> <h2><a class=toc-backref href=#id2>Getting Started</a></h2> <p>Python's main competitor in the ring is a nifty little library called <a class="reference external" href=http://graphene-python.org/ >graphene</a>. But before we get into graphene, we need to talk about some of the fundamental parts of Graphql.</p> <ul class=simple> <li>The <em>model</em> is an object defined by a Graphql schema.</li> <li>The <em>schema</em> defines models and their attribute.</li> <li>Each attribute of a model has its own <em>resolver</em>. This is a function that is responsible for getting the data for that particular model attribute.</li> <li>A <em>query</em> is basically what you use to get or set data inside Graphql</li> <li><em>Mutations</em> are particular queries that allow you to change the data for a given model or a set of models.</li> <li><em>Graphiql</em> is the UI that you use to interact with a Graphql server. The IDE-like thing that you see in the above screenshot is the Graphiql interface.</li> </ul> <div class=section id=here-comes-python> <h3><a class=toc-backref href=#id3>Here Comes Python</a></h3> <p>Python's attempt at Graphql can be broken down into three parts. Graphene, ORM specific graphene add-ons and graphene libraries that add support to web frameworks such as flask or django. Graphene allows you to define your models, define the attributes in your model, and also parses queries to get the data for those particular models.</p> <p>The ORM specific graphene libraries basically do the job of turning your SQLAlchemy or Django models into Graphql objects with the help of graphene. Some libraries will will also come in with views that fit in with your web framework like <code>graphene-django</code>.</p> </div> <div class=section id=playing-with-graphene> <h3><a class=toc-backref href=#id4>Playing with Graphene</a></h3> <p>Installation is quite easy, and graphene supports both python versions 2 and 3.</p> <div class=highlight><pre><span></span>pip install graphene
</pre></div> <p>Once you've installed it, import it, write a simple model, and the execute it like so:</p> <div class=highlight><pre><span></span><span class=kn>import</span> <span class=nn>graphene</span> <span class=c1># 1</span>
<span class=k>class</span> <span class=nc>Query</span><span class=p>(</span><span class=n>graphene</span><span class=o>.</span><span class=n>ObjectType</span><span class=p>):</span> <span class=c1># 2</span>
<span class=n>hello</span> <span class=o>=</span> <span class=n>graphene</span><span class=o>.</span><span class=n>String</span><span class=p>(</span><span class=n>description</span><span class=o>=</span><span class=s1>'A typical hello world'</span><span class=p>)</span> <span class=c1># 3</span>
<span class=k>def</span> <span class=nf>resolve_hello</span><span class=p>(</span><span class=bp>self</span><span class=p>,</span> <span class=n>args</span><span class=p>,</span> <span class=n>context</span><span class=p>,</span> <span class=n>info</span><span class=p>):</span> <span class=c1># 4</span>
<span class=k>return</span> <span class=s1>'World'</span>
<span class=n>schema</span> <span class=o>=</span> <span class=n>graphene</span><span class=o>.</span><span class=n>Schema</span><span class=p>(</span><span class=n>query</span><span class=o>=</span><span class=n>Query</span><span class=p>)</span> <span class=c1># 5</span>
<span class=n>query</span> <span class=o>=</span> <span class=s1>'''</span>
<span class=s1> query {</span>
<span class=s1> hello</span>
<span class=s1> }</span>
<span class=s1>'''</span> <span class=c1># 6</span>
<span class=n>result</span> <span class=o>=</span> <span class=n>schema</span><span class=o>.</span><span class=n>execute</span><span class=p>(</span><span class=n>query</span><span class=p>)</span> <span class=c1># 7</span>
</pre></div> <p>In <code class=coderef>1</code> we are importing the package. Note that in <code class=coderef>2</code> we are creating the query class. All query classes inherit from the <code>graphene.ObjectType</code> class. You can also embed queries within queries (this is great when you want to modularize your applications). Furthermore, even complex objects will also inherit from <code>graphene.ObjectType</code>.</p> <p>This class basically holds all the models. Right now, there is only one model, and that is hello, which happens to be a simple string. Yes, I know its not terribly exciting, but bare with me.</p> <p>In <code class=coderef>3</code> we add an object to the schema. In this case it is a simple string. In <code class=coderef>4</code> we basically write the <em>resolver</em> for that particular model in the schema, we will get into the details of the function signature soon enough.</p> <p>In <code class=coderef>5</code> we basically declare the schema, and we tell it that the query class object is <code>Query</code> (a query object can be made up of multiple query objects, and we will get into that later).</p> <p>Then, we declare the simplest query possible, in <code class=coderef>6</code> and in <code class=coderef>7</code> we finally execute it. This is what the result looks like:</p> <div class=highlight><pre><span></span><span class=n>In</span> <span class=p>[</span><span class=mi>6</span><span class=p>]:</span> <span class=n>result</span> <span class=o>=</span> <span class=n>schema</span><span class=o>.</span><span class=n>execute</span><span class=p>(</span><span class=n>query</span><span class=p>)</span>
<span class=n>In</span> <span class=p>[</span><span class=mi>7</span><span class=p>]:</span> <span class=nb>type</span><span class=p>(</span><span class=n>result</span><span class=p>)</span>
<span class=n>Out</span><span class=p>[</span><span class=mi>7</span><span class=p>]:</span> <span class=n>graphql</span><span class=o>.</span><span class=n>execution</span><span class=o>.</span><span class=n>base</span><span class=o>.</span><span class=n>ExecutionResult</span>
<span class=n>In</span> <span class=p>[</span><span class=mi>8</span><span class=p>]:</span> <span class=n>result</span><span class=o>.</span><span class=n>data</span>
<span class=n>Out</span><span class=p>[</span><span class=mi>8</span><span class=p>]:</span> <span class=n>OrderedDict</span><span class=p>([(</span><span class=s1>'hello'</span><span class=p>,</span> <span class=s1>'world'</span><span class=p>)])</span>
</pre></div> <p>The result comes with three main attributes.</p> <div class=highlight><pre><span></span><span class=n>In</span> <span class=p>[</span><span class=mi>12</span><span class=p>]:</span> <span class=n>result</span><span class=o>.</span><span class=n>data</span>
<span class=n>Out</span><span class=p>[</span><span class=mi>12</span><span class=p>]:</span> <span class=n>OrderedDict</span><span class=p>([(</span><span class=s1>'hello'</span><span class=p>,</span> <span class=s1>'world'</span><span class=p>)])</span>
<span class=n>In</span> <span class=p>[</span><span class=mi>13</span><span class=p>]:</span> <span class=n>result</span><span class=o>.</span><span class=n>errors</span>
<span class=n>In</span> <span class=p>[</span><span class=mi>14</span><span class=p>]:</span> <span class=n>result</span><span class=o>.</span><span class=n>invalid</span>
<span class=n>Out</span><span class=p>[</span><span class=mi>14</span><span class=p>]:</span> <span class=bp>False</span>
</pre></div> <p><code>data</code> gives us the return data that we want. <code>errors</code> points any errors that we might <a class=footnote-reference href=#errors id=id1>[1]</a> have and finally, <code>invalid</code> basically tells us that if the query itself is valid.</p> </div> </div> <div class=section id=basic-types> <h2><a class=toc-backref href=#id5>Basic Types</a></h2> <p>So, now that we've gotten the hang of the fundamental parts of the Graphql system, its time that we explored the other data types, and started playing around with more complex objects. There is already plenty of good documentation on this stuff, so I won't do a copy of the tutorials that are already available. The first thing to take a look at is the <a class="reference external" href=http://docs.graphene-python.org/en/latest/types/ >type reference</a>.</p> <p>There are quite a few types to go over, but in basic terms, there is a dichotomy between scalars and non-scalars. Scalars are the base object types, they are things like strings, integers, booleans etc. Non-Scalars on the other hand are more complex objects, often they are containers of scalars, like lists, <code>graphene.List</code>. They can also be interfaces, that other graphene <code>ObjectType</code>s inherit from and of course, there are mutation types, that basically make changes on top of the data.</p> <p>In simple terms, there are a lot of types, but what it comes down to are basically types that hold information, types that contain basic scalar types, types that other types inherit from in a concrete sense and types that other objects inherit from in an abstract sense. Pretty much what you'd expect from a simple object oriented system.</p> <div class=section id=a-few-opinions> <h3><a class=toc-backref href=#id6>A Few Opinions</a></h3> <p>However, what I have come to notice is that it is almost always better to avoid using abstract types, and just go straight for interfaces. Most of the time, you just don't need abstract objects. In the case of Graphql, composition is almost always better than inheritance. Probably the only place that it makes sense to use the <code>AbstractType</code> class is for <code>Query</code> types that you are later on going to use in your final <code>Query</code> object.</p> <p>Make sure to keep your names simple, and avoid using <code>graphene.NotNull</code>, because you can always set <code>required=True</code> for scalar types anyway. This is similar to what you get in other serializer libraries, so people looking at the codebase can see commonalities between graphene and other libraries.</p> </div> </div> <div class=section id=integration-with-orms> <h2><a class=toc-backref href=#id7>Integration with ORMs</a></h2> <p>If you think about it, at its core, graphene is basically a combination of a serialization library and a Graphql query interpreter, so it would make a lot of sense for it to work with ORMs and it does so quite well. At the time of writing this, there is support for django, sqlalchemy as well as google app engine. Most are really quite simple to integrate. Most of the time, you just have to set the meta model attribute of an object type and you're done.</p> <div class=section id=django> <h3><a class=toc-backref href=#id8>Django</a></h3> <div class=highlight><pre><span></span><span class=kn>from</span> <span class=nn>django.db</span> <span class=kn>import</span> <span class=n>models</span>
<span class=kn>from</span> <span class=nn>graphene_django</span> <span class=kn>import</span> <span class=n>DjangoObjectType</span>
<span class=k>class</span> <span class=nc>Account</span><span class=p>(</span><span class=n>models</span><span class=o>.</span><span class=n>Model</span><span class=p>):</span>
<span class=n>birth_date</span> <span class=o>=</span> <span class=n>models</span><span class=o>.</span><span class=n>DateField</span><span class=p>(</span><span class=n>db_column</span><span class=o>=</span><span class=s1>'personbirthdate'</span><span class=p>,</span> <span class=n>null</span><span class=o>=</span><span class=bp>True</span><span class=p>)</span>
<span class=n>created_date</span> <span class=o>=</span> <span class=n>models</span><span class=o>.</span><span class=n>DateTimeField</span><span class=p>(</span><span class=n>blank</span><span class=o>=</span><span class=bp>True</span><span class=p>,</span> <span class=n>null</span><span class=o>=</span><span class=bp>True</span><span class=p>,</span> <span class=n>db_column</span><span class=o>=</span><span class=s1>'createddate'</span><span class=p>)</span>
<span class=n>is_paying_customer</span> <span class=o>=</span> <span class=n>models</span><span class=o>.</span><span class=n>NullBooleanField</span><span class=p>(</span><span class=n>db_column</span><span class=o>=</span><span class=s1>'iscustomer'</span><span class=p>)</span>
<span class=n>country</span> <span class=o>=</span> <span class=n>models</span><span class=o>.</span><span class=n>CharField</span><span class=p>(</span><span class=n>db_column</span><span class=o>=</span><span class=s1>'country'</span><span class=p>,</span> <span class=n>max_length</span><span class=o>=</span><span class=mi>3</span><span class=p>,</span> <span class=n>null</span><span class=o>=</span><span class=bp>True</span><span class=p>,</span> <span class=n>blank</span><span class=o>=</span><span class=bp>True</span><span class=p>)</span>
<span class=n>customer_number</span> <span class=o>=</span> <span class=n>models</span><span class=o>.</span><span class=n>CharField</span><span class=p>(</span> <span class=n>db_column</span><span class=o>=</span><span class=s1>'cnumber'</span><span class=p>,</span> <span class=n>unique</span><span class=o>=</span><span class=bp>True</span><span class=p>,</span> <span class=n>max_length</span><span class=o>=</span><span class=mi>255</span><span class=p>,</span>
<span class=n>blank</span><span class=o>=</span><span class=bp>True</span><span class=p>,</span> <span class=n>null</span><span class=o>=</span><span class=bp>True</span><span class=p>,</span> <span class=n>editable</span><span class=o>=</span><span class=bp>False</span><span class=p>)</span>
<span class=k>class</span> <span class=nc>Meta</span><span class=p>:</span>
<span class=n>managed</span> <span class=o>=</span> <span class=bp>False</span>
<span class=n>db_table</span> <span class=o>=</span><span class=s1>'accountinfo'</span>
<span class=k>class</span> <span class=nc>AccountType</span><span class=p>(</span><span class=n>DjangoObjectType</span><span class=p>):</span>
<span class=k>class</span> <span class=nc>Meta</span><span class=p>:</span>
<span class=n>model</span> <span class=o>=</span> <span class=n>Account</span>
</pre></div> <p>You can now use <code>AccountType</code> just like you would any other object type. But most of the time, you don't even have to manually add things to the query objects. If you have django-filter installed, you can do something pretty simple, and add <code>graphene.Node</code> to your list of interfaces for a give type. This allows you to set some variables in the metaclass that allows for simple filtering and also allows your type to be easily integrated into the query using <code>DjangoConnectedFilterField</code>. Here's an example of what that would look like from the perspective of the <code>Account</code> model:</p> <div class=highlight><pre><span></span><span class=k>class</span> <span class=nc>AccountNode</span><span class=p>(</span><span class=n>DjangoObjectType</span><span class=p>):</span>
<span class=k>class</span> <span class=nc>Meta</span><span class=p>:</span>
<span class=n>model</span> <span class=o>=</span> <span class=n>Account</span>
<span class=n>interfaces</span> <span class=o>=</span> <span class=p>(</span><span class=n>graphene</span><span class=o>.</span><span class=n>Node</span><span class=p>,</span> <span class=p>)</span>
<span class=n>filter_fields</span> <span class=o>=</span> <span class=p>[</span>
<span class=s1>'customer_number'</span><span class=p>,</span>
<span class=s1>'is_paying_customer'</span><span class=p>,</span>
<span class=p>]</span>
</pre></div> <p>And this is what it would look like in the query object:</p> <div class=highlight><pre><span></span><span class=kn>from</span> <span class=nn>graphene_django.filter</span> <span class=kn>import</span> <span class=n>DjangoConnectedFilterField</span>
<span class=k>class</span> <span class=nc>AccountQuery</span><span class=p>(</span><span class=n>graphene</span><span class=o>.</span><span class=n>AbstractType</span><span class=p>):</span>
<span class=c1># Gives you a particular account</span>
<span class=n>account</span> <span class=o>=</span> <span class=n>graphene</span><span class=o>.</span><span class=n>Node</span><span class=o>.</span><span class=n>Field</span><span class=p>(</span><span class=n>AccountNode</span><span class=p>)</span>
<span class=c1># Gives you all the accounts available</span>
<span class=n>all_accounts</span> <span class=o>=</span> <span class=n>DjangoFilterConnectionField</span><span class=p>(</span><span class=n>AccountNode</span><span class=p>,</span> <span class=n>order_by</span><span class=o>=</span><span class=s1>'-customer_number'</span><span class=p>)</span>
</pre></div> <p>This really simplifies your whole query process, and focuses on fat database models and not fat graphene objects. Note, that I use <code>graphene.AbstractType</code> for this <code>AccountQuery</code> objects because I'm basically going to use it as a mixin for my final <code>Query</code> Object. Here is what that looks like:</p> <div class=highlight><pre><span></span><span class=kn>from</span> <span class=nn>.queries</span> <span class=kn>import</span> <span class=n>AccountQuery</span>
<span class=k>class</span> <span class=nc>Query</span><span class=p>(</span><span class=n>AccountQuery</span><span class=p>,</span> <span class=n>graphene</span><span class=o>.</span><span class=n>ObjectType</span><span class=p>):</span>
<span class=k>pass</span>
<span class=n>schema</span> <span class=o>=</span> <span class=n>graphene</span><span class=o>.</span><span class=n>Schema</span><span class=p>(</span><span class=n>query</span><span class=o>=</span><span class=n>Query</span><span class=p>)</span>
</pre></div> <p>This way, your main query object won't be cluttered, and you can keep adding your queries as you please. Make sure to add <code>graphene.ObjectType</code> as the <em>last</em> argument for inheritance, otherwise your final <code>Query</code> object will not be a concrete class.</p> </div> <div class=section id=sqlalchemy-and-others> <h3><a class=toc-backref href=#id9>SQLAlchemy and Others</a></h3> <p>Other ORMs are also similarly supported. With SQLAlchemy, you just use <code>SQLAlchemyObjectType</code> instead of <code>DjangoObjectType</code>, you can also add the <code>Node</code> interface to it, and have a similar querying experience that you do with django using <code>SQLAlchemyConnectionField</code>. The same is true for google app engine. Peewee support is still in the works.</p> </div> </div> <div class=section id=integration-with-web-frameworks> <h2><a class=toc-backref href=#id10>Integration with Web Frameworks</a></h2> <p>As you might expect, graphene supports a few popular frameworks, with more support coming. Right now there is awesome support for <code>flask</code> and <code>django</code>. Here is what a flask Graphql application looks like:</p> <div class=highlight><pre><span></span><span class=kn>from</span> <span class=nn>flask</span> <span class=kn>import</span> <span class=n>Flask</span>
<span class=kn>from</span> <span class=nn>flask_graphql</span> <span class=kn>import</span> <span class=n>GraphQLView</span>
<span class=kn>from</span> <span class=nn>models</span> <span class=kn>import</span> <span class=n>db_session</span>
<span class=kn>from</span> <span class=nn>schema</span> <span class=kn>import</span> <span class=n>schema</span><span class=p>,</span> <span class=n>Department</span>
<span class=n>app</span> <span class=o>=</span> <span class=n>Flask</span><span class=p>(</span><span class=vm>__name__</span><span class=p>)</span>
<span class=n>app</span><span class=o>.</span><span class=n>debug</span> <span class=o>=</span> <span class=bp>True</span>
<span class=n>app</span><span class=o>.</span><span class=n>add_url_rule</span><span class=p>(</span>
<span class=s1>'/graphql'</span><span class=p>,</span>
<span class=n>view_func</span><span class=o>=</span><span class=n>GraphQLView</span><span class=o>.</span><span class=n>as_view</span><span class=p>(</span>
<span class=s1>'graphql'</span><span class=p>,</span>
<span class=n>schema</span><span class=o>=</span><span class=n>schema</span><span class=p>,</span>
<span class=n>graphiql</span><span class=o>=</span><span class=bp>True</span>
<span class=p>)</span>
<span class=p>)</span>
<span class=nd>@app.teardown_appcontext</span>
<span class=k>def</span> <span class=nf>shutdown_session</span><span class=p>(</span><span class=n>exception</span><span class=o>=</span><span class=bp>None</span><span class=p>):</span>
<span class=n>db_session</span><span class=o>.</span><span class=n>remove</span><span class=p>()</span>
<span class=k>if</span> <span class=vm>__name__</span> <span class=o>==</span> <span class=s1>'__main__'</span><span class=p>:</span>
<span class=n>app</span><span class=o>.</span><span class=n>run</span><span class=p>()</span>
</pre></div> <p>I would of course suggest that you have separate endpoints for graphiql and for your HTTP requests. You can also subclass <code>GraphQLView</code> if you want to add some custom authentication.</p> </div> <div class=section id=final-thoughts> <h2><a class=toc-backref href=#id11>Final Thoughts</a></h2> <p>I really like Graphql, I've recently launched a production application based on top of Graphql, and <code>graphene-django</code> has really helped me replace my current REST API with a Graphql API (or service or whatever it is that you want to call it). The delcarative syntax makes it quite easy to use, and so there really is not much of a learning curve, especially if you've used serializer libraries like Marshmallow or DRF's serializers.</p> <p>Currently, graphene is basically a python port of the Graphql nodejs package at version 0.6. I'm pretty sure there will be version bumps in the future as the library has a healthy following. It also supports all kinds of clients including the apollo client.</p> <hr class=docutils> <table class="docutils footnote" frame=void id=errors rules=none> <colgroup><col class=label><col></colgroup> <tbody valign=top> <tr><td class=label><a class=fn-backref href=#id1>[1]</a></td><td>You will always get back errors in a separate sub-object in a query if you have any. You will not get any errors in HTTP status codes.</td></tr> </tbody> </table> </div> </div> </div> <div class=post-meta><span class=meta-type>Category: </span> <span><a href=http://nafiulis.me/category/programming.html>programming</a></span> <span class=meta-type> Tags: </span> <span> <a href=http://nafiulis.me/tag/python.html>python</a>, <a href=http://nafiulis.me/tag/graphql.html>graphql</a>, <a href=http://nafiulis.me/tag/rest.html>REST</a>, <a href=http://nafiulis.me/tag/api.html>API</a>, <a href=http://nafiulis.me/tag/web.html>web</a> </span> </div> <div id=disqus_thread style="margin-top: 10px; margin-left: 20px; margin-right: 20px;"></div> <script type=text/javascript>
/* * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO YOUR WEBPAGE * * */
var disqus_shortname = 'nafiulisme'; // required: replace example with your forum shortname
/* * * DON'T EDIT BELOW THIS LINE * * */
(function() {
var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true;
dsq.src = '//' + disqus_shortname + '.disqus.com/embed.js';
(document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);
})();
</script> <noscript>Please enable JavaScript to view the <a href=http://disqus.com/?ref_noscript>comments powered by Disqus.</a></noscript> </div> <!--Footer--> <div id=footer> <footer> Code examples licenced under MIT License <br> Copyright <i class="fa fa-copyright"></i> 2018 Quazi Nafiul Islam </footer> </div> </div> <script>
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
ga('create', 'UA-55554110-1', 'auto');
ga('send', 'pageview');
</script> </body> </html>