This is a simple project demonstrating the implementation of a GraphQL server in Python using:
The objective is to demonstrate how these different libraries can be integrated.
The primary feature offered by this demo are:
- SQLAlchemy ORM against a local SQLite database. The ORM is super simple but showcases a many-to-many relationship between
authors
andbooks
via anauthor_books
association table. - Falcon resources to serve both GraphQL and GraphiQL.
The Falcon resources are slightly modified versions of the ones under https://github.com/alecrasmussen/falcon-graphql-server so all credits to Alec Rasmussen.
- Basic GraphQL schema automatically derived from the SQLAlchemy ORM via Graphene and Graphene-SQLAlchemy.
- API setup via Falcon with the whole thing served via Gunicorn.
All instructions and commands below are meant to be run from the root dir of this repo.
You are strongly encouraged to use a virtualenv here but I can be assed writing down the instructions for that.
Install all requirements through:
pip install -r requirements.txt
The sample SQLite database has been committed in this repo but can easily be rebuilt through:
python -m demo.orm
at which point it will create a demo.db
in the root of this repo.
The sample data are defined under
data.py
while they're ingested with the code under themain
sentinel inorm.py
. Feel free to tinker.
The Gunicorn is configured via the gunicorn_config.py
module and binds by default to localhost:5432/
. You can change all gunicorn configuration options under the aforementioned module.
The server can be run through:
gunicorn -c gunicorn_config.py "demo.demo:main()"
The server exposes two endpoints:
/graphql
: The standard GraphQL endpoint which can receive the queries directly (accessible by default under http://localhost:5432/graphql)./graphiql
: The GraphiQL interface (accessible by default under http://localhost:5432/graphiql).
Here's a couple example queries you can either run directly in GraphiQL or by performing POST requests against the GraphQL server.
Query:
query getAuthor{
author(authorId: 1) {
nameFirst,
nameLast
}
}
Response:
{
"data": {
"author": {
"nameFirst": "Robert",
"nameLast": "Jordan"
}
}
}
query getAuthor{
author(nameFirst: "Robert") {
nameFirst,
nameLast
}
}
Response:
{
"data": {
"author": {
"nameFirst": "Robert",
"nameLast": "Jordan"
}
}
}
Query:
query getAuthor{
author(nameFirst: "Brandon") {
nameFirst,
nameLast,
books {
title,
year
}
}
}
Response:
{
"data": {
"author": {
"nameFirst": "Brandon",
"nameLast": "Sanderson",
"books": [
{
"title": "The Gathering Storm",
"year": 2009
},
{
"title": "Towers of Midnight",
"year": 2010
},
{
"title": "A Memory of Light",
"year": 2013
}
]
}
}
}
Query:
query getBooks{
books(year: 1990) {
title,
year
}
}
Response:
{
"data": {
"books": [
{
"title": "The Eye of the World",
"year": 1990
},
{
"title": "The Great Hunt",
"year": 1990
}
]
}
}
Query:
query getBooks{
books(title: "A Memory of Light") {
title,
year,
authors {
nameFirst,
nameLast
}
}
}
Response:
{
"data": {
"books": [
{
"title": "A Memory of Light",
"year": 2013,
"authors": [
{
"nameFirst": "Robert",
"nameLast": "Jordan"
},
{
"nameFirst": "Brandon",
"nameLast": "Sanderson"
}
]
}
]
}
}
Query:
query getCountBooksByCoverArtist{
stats {
countBooksByCoverArtist {
coverArtist,
countBooks
}
}
}
Response:
{
"data": {
"stats": {
"countBooksByCoverArtist": [
{
"coverArtist": null,
"countBooks": 1
},
{
"coverArtist": "Darrell K. Sweet",
"countBooks": 12
},
{
"coverArtist": "Michael Whelan",
"countBooks": 1
}
]
}
}
}
Query:
mutation createAuthor{
createAuthor(author: {
nameFirst: "First Name",
nameLast: "Last Name"
}) {
author {
authorId
nameFirst
nameLast
}
}
}
Response:
{
"data": {
"createAuthor": {
"author": {
"authorId": "3",
"nameFirst": "First Name",
"nameLast": "Last Name"
}
}
}
}