Skip to content

Commit 70df6c7

Browse files
authored
Merge pull request #128 from kigen/feature-nameko-example
Nameko example - Pure API based example.
2 parents 5346496 + 2e8d836 commit 70df6c7

File tree

11 files changed

+228
-2
lines changed

11 files changed

+228
-2
lines changed

README.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,10 +98,12 @@ class Query(graphene.ObjectType):
9898
schema = graphene.Schema(query=Query)
9999
```
100100

101-
To learn more check out the following [examples](examples/):
101+
### Full Examples
102102

103-
* **Full example**: [Flask SQLAlchemy example](examples/flask_sqlalchemy)
103+
To learn more check out the following [examples](examples/):
104104

105+
- [Flask SQLAlchemy example](examples/flask_sqlalchemy)
106+
- [Nameko SQLAlchemy example](examples/nameko_sqlalchemy)
105107

106108
## Contributing
107109

examples/nameko_sqlalchemy/README.md

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
Example Nameko+Graphene-SQLAlchemy Project
2+
================================
3+
4+
This example is for those who are not using frameworks like Flask | Django which already have a View wrapper implemented to handle graphql request and response accordingly
5+
6+
If you need a [graphiql](https://github.com/graphql/graphiql) interface on your application, kindly look at [flask_sqlalchemy](../flask_sqlalchemy).
7+
8+
Using [nameko](https://github.com/nameko/nameko) as an example, but you can get rid of `service.py`
9+
10+
The project contains two models, one named `Department` and another
11+
named `Employee`.
12+
13+
Getting started
14+
---------------
15+
16+
First you'll need to get the source of the project. Do this by cloning the
17+
whole Graphene repository:
18+
19+
```bash
20+
# Get the example project code
21+
git clone https://github.com/graphql-python/graphene-sqlalchemy.git
22+
cd graphene-sqlalchemy/examples/nameko_sqlalchemy
23+
```
24+
25+
It is good idea (but not required) to create a virtual environment
26+
for this project. We'll do this using
27+
[virtualenv](http://docs.python-guide.org/en/latest/dev/virtualenvs/)
28+
to keep things simple,
29+
but you may also find something like
30+
[virtualenvwrapper](https://virtualenvwrapper.readthedocs.org/en/latest/)
31+
to be useful:
32+
33+
```bash
34+
# Create a virtualenv in which we can install the dependencies
35+
virtualenv env
36+
source env/bin/activate
37+
```
38+
39+
Now we can install our dependencies:
40+
41+
```bash
42+
pip install -r requirements.txt
43+
```
44+
45+
Now the following command will setup the database, and start the server:
46+
47+
```bash
48+
./run.sh
49+
50+
```
51+
52+
Now head on over to postman and send POST request to:
53+
[http://127.0.0.1:5000/graphql](http://127.0.0.1:5000/graphql)
54+
and run some queries!

examples/nameko_sqlalchemy/__init__.py

Whitespace-only changes.

examples/nameko_sqlalchemy/app.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
from database import db_session, init_db
2+
from schema import schema
3+
4+
from graphql_server import (HttpQueryError, default_format_error,
5+
encode_execution_results, json_encode,load_json_body, run_http_query)
6+
7+
8+
class App():
9+
def __init__(self):
10+
init_db()
11+
12+
def query(self, request):
13+
data = self.parse_body(request)
14+
execution_results, params = run_http_query(
15+
schema,
16+
'post',
17+
data)
18+
result, status_code = encode_execution_results(
19+
execution_results,
20+
format_error=default_format_error,is_batch=False, encode=json_encode)
21+
return result
22+
23+
def parse_body(self,request):
24+
# We use mimetype here since we don't need the other
25+
# information provided by content_type
26+
content_type = request.mimetype
27+
if content_type == 'application/graphql':
28+
return {'query': request.data.decode('utf8')}
29+
30+
elif content_type == 'application/json':
31+
return load_json_body(request.data.decode('utf8'))
32+
33+
elif content_type in ('application/x-www-form-urlencoded', 'multipart/form-data'):
34+
return request.form
35+
36+
return {}

examples/nameko_sqlalchemy/config.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
WEB_SERVER_ADDRESS: '0.0.0.0:5000'
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
from sqlalchemy import create_engine
2+
from sqlalchemy.ext.declarative import declarative_base
3+
from sqlalchemy.orm import scoped_session, sessionmaker
4+
5+
engine = create_engine('sqlite:///database.sqlite3', convert_unicode=True)
6+
db_session = scoped_session(sessionmaker(autocommit=False,
7+
autoflush=False,
8+
bind=engine))
9+
Base = declarative_base()
10+
Base.query = db_session.query_property()
11+
12+
13+
def init_db():
14+
# import all modules here that might define models so that
15+
# they will be registered properly on the metadata. Otherwise
16+
# you will have to import them first before calling init_db()
17+
from models import Department, Employee, Role
18+
Base.metadata.drop_all(bind=engine)
19+
Base.metadata.create_all(bind=engine)
20+
21+
# Create the fixtures
22+
engineering = Department(name='Engineering')
23+
db_session.add(engineering)
24+
hr = Department(name='Human Resources')
25+
db_session.add(hr)
26+
27+
manager = Role(name='manager')
28+
db_session.add(manager)
29+
engineer = Role(name='engineer')
30+
db_session.add(engineer)
31+
32+
peter = Employee(name='Peter', department=engineering, role=engineer)
33+
db_session.add(peter)
34+
roy = Employee(name='Roy', department=engineering, role=engineer)
35+
db_session.add(roy)
36+
tracy = Employee(name='Tracy', department=hr, role=manager)
37+
db_session.add(tracy)
38+
db_session.commit()

examples/nameko_sqlalchemy/models.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
from sqlalchemy import Column, DateTime, ForeignKey, Integer, String, func
2+
from sqlalchemy.orm import backref, relationship
3+
4+
from database import Base
5+
6+
7+
class Department(Base):
8+
__tablename__ = 'department'
9+
id = Column(Integer, primary_key=True)
10+
name = Column(String)
11+
12+
13+
class Role(Base):
14+
__tablename__ = 'roles'
15+
role_id = Column(Integer, primary_key=True)
16+
name = Column(String)
17+
18+
19+
class Employee(Base):
20+
__tablename__ = 'employee'
21+
id = Column(Integer, primary_key=True)
22+
name = Column(String)
23+
# Use default=func.now() to set the default hiring time
24+
# of an Employee to be the current time when an
25+
# Employee record was created
26+
hired_on = Column(DateTime, default=func.now())
27+
department_id = Column(Integer, ForeignKey('department.id'))
28+
role_id = Column(Integer, ForeignKey('roles.role_id'))
29+
# Use cascade='delete,all' to propagate the deletion of a Department onto its Employees
30+
department = relationship(
31+
Department,
32+
backref=backref('employees',
33+
uselist=True,
34+
cascade='delete,all'))
35+
role = relationship(
36+
Role,
37+
backref=backref('roles',
38+
uselist=True,
39+
cascade='delete,all'))
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
graphene[sqlalchemy]
2+
SQLAlchemy==1.0.11
3+
nameko
4+
graphql-server-core

examples/nameko_sqlalchemy/run.sh

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
#!/bin/sh
2+
echo "Starting application service server"
3+
# Run Service
4+
nameko run --config config.yml service

examples/nameko_sqlalchemy/schema.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import graphene
2+
from graphene import relay
3+
from graphene_sqlalchemy import SQLAlchemyConnectionField, SQLAlchemyObjectType
4+
from models import Department as DepartmentModel
5+
from models import Employee as EmployeeModel
6+
from models import Role as RoleModel
7+
8+
9+
class Department(SQLAlchemyObjectType):
10+
11+
class Meta:
12+
model = DepartmentModel
13+
interfaces = (relay.Node, )
14+
15+
16+
class Employee(SQLAlchemyObjectType):
17+
18+
class Meta:
19+
model = EmployeeModel
20+
interfaces = (relay.Node, )
21+
22+
23+
class Role(SQLAlchemyObjectType):
24+
25+
class Meta:
26+
model = RoleModel
27+
interfaces = (relay.Node, )
28+
29+
30+
class Query(graphene.ObjectType):
31+
node = relay.Node.Field()
32+
all_employees = SQLAlchemyConnectionField(Employee)
33+
all_roles = SQLAlchemyConnectionField(Role)
34+
role = graphene.Field(Role)
35+
36+
37+
schema = graphene.Schema(query=Query, types=[Department, Employee, Role])

examples/nameko_sqlalchemy/service.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
#!/usr/bin/env python
2+
from nameko.web.handlers import http
3+
from app import App
4+
5+
6+
class DepartmentService:
7+
name = 'department'
8+
9+
@http('POST', '/graphql')
10+
def query(self, request):
11+
return App().query(request)

0 commit comments

Comments
 (0)