I’ve created another article on GraphQL with TypeScript, if you want to check it out, click here.
One of the favorite features of GraphQL, a characteristic missing in RESTful architectures, is strong-typed validation. By default, GraphQL validates every request against the schema, which works as a gatekeeper, meaning that if the request does not pass the validation, no actions are going to be taken by the server, saving CPU time (especially important in serverless infrastructures), also letting the client knows quicker there’s an issue with their request.
And this is crucial. As you may know, GraphQL can trigger several queries towards multiple data points (other end-points, databases, flat files, or even another GraphQL service) in a single request so, having this filter at the door will prevent unnecessary overhead.
At the same time, GraphQL’s strong typed traits will make your IDE’s IntelliSense smarter, which in turn will help you develop faster and potentially with fewer bugs.
Let’s go over GraphQL’s types and schemas by creating a small project in Python and Flask web framework (implementing graphene and SQLAlchemy). For a simple database, we are going to use Sqlite3.
The Power of Object-Relational Mapping 🗺
While ORM is not required in order to use GraphQL, it is definitely worth looking into it. There are many opinions on this subject, ranging from ORMs are not necessary or that they do not add value to the exchange of messages between client and server, to others who think that they are precious to maintain integrity between the data source and the implementation.
Tools like the ones mentioned above (Prisma, SQLAlchemy) allows to abstract the data sources to a point where they can provide a common schema that can be both used on the back-end as in the front-end.
Creating a demo project with GraphQL on Python 🐍
To start, we’ll need the following packages installed (requirements.txt):
The structure of our project is quite simple: at the root, we will have main.py. Also, in the root, we will have a package called Books (books/). Add a __init__.py file inside the Books package.
Database Models 🗄
The first items that we are going to add to the Books package are the Models. In the “books/models/” directory we will create three files: books.py, characters.py, and genres.py.
Here, you’ll notice, three classes are created. Genres, Books, Characters. Essentially, these are our ORM mappings with SQLAlchemy to what eventually will become our SQLite database. However, another advantage of these classes, is that we can use them as references for the GraphQL structure.
Creating the Type definitions 📚
The previously mentioned linking definitions will be done in a one to one mapping to the ORM files created in the last step. For that, we will rely on graphene’s library. You’ll need to create a “books/types/” directory. In it, we’ll add the same files to map what we have in the model's directory: books.py, characters.py, and genres.py.
These classes extend the SQLAlchemyObjectType, which will be reflected in the GraphQL queries.
Database seed 🌱
In order to have some initial data in our database, we could create a migrations file, however, this being such a simple database, we are just going to create a file that inserts a few rows. This file will also be created in the Books package directory under “books/database”. We’ll call it database.py. Additionally, base.py and db_sessions.py will be created to provide a database session and other utilities used across your application.
These scripts are pretty straight forward. Main takeaways are the creation of the database file `Books/database.sqlite3` on line 4 of base.py. Then another script adds a few genre, book, and character rows to our initial database on init_db.py.
GraphQL Schema 📐
The main entry point for GraphQL to our data is the Schema. This file will have a reference to the Query object, the Mutation object and a reference of the Types used.
The files to be created in the “books/schema” directory are schema.py, query.py, and mutation.py.
Two properties (Fields) are found in the query.py file mapped to two resolvers. For example, books_by_genre defines a graphene list, the first parameter (Books) represents the type of elements this resolver will return, the second will be the argument that will be received by the resolver (name). The actual resolver method is matched by its name with the prefix “resolve_”. So, the resolver for “books_by_genre” will be resolve_books_by_genre. This method, by the way, illustrates a join of two tables from SQLite (Books and Genres).
Notice that we are using a utility called “input_to_dictionary”. This is a method you’ll create in the directory “books/utils” in the file input_to_dictionary.py as follows:
Finally, we’ll wrap our app using Flask.
Using Flask to expose our GraphQL end-point 🌏
In order to be able to access our GraphQL end-point, we will use Flask web framework, which is a very lightweight library that will allow the service to be exposed publicly. For the purpose of this demo, we won’t be covering security and everything that comes with it. If you want to expand further into how Flask works and how to implement a secure end-point you can check out the documentation here.
The main entry for your package is going to be app.py (also inside the Books package):
In here, you’ll be adding the route of “/graphql” to map the GraphiQL app, by default running on your localhost, port 5000.
Finally, the entry point for our full app will be main.py, at the root directory:
Two actions are going to be run here, the first one will reset the SQLite database, and the second one will actually run the Books package. Of course, this is done this way due to this being a demo; you don’t want to have this pattern, as it will reset your database every time you run your application.
As you run python main.py, you’ll bring up the Flask web framework. Your console will return an output similar to this:
After running the app, you’ll notice the `database.sqlite3` file created inside the database directory in the Books package.
And then, if you navigate there using a browser:
This interface is called GraphiQL (pronounced “Graphical”), where you can run your GraphQL queries. Let’s try to find all books that match the “Fantasy” genre.
You can even merge the result types, for instance, ask for the characters included in these books, by adding the characters edge:
You can use your mutations also through this same interface. In this case, we only have one mutation (createBook), and you’ll access it like this:
After this, the next subjects you are going to want to look into are Data Loaders which will help you simplify your requests and use batching to with Promises and finally security and access tokens with GraphQL.
What’s Next and Further Reading
More subjects that you can explore:
GraphQL ORM with TypeScript implementing Apollo Server(Express) and SQLite
Simple step by step of how to create a basic GraphQL end-point with TypeScript and Apollo Server with SQLite as a…
SOAP, RESTful, GraphQL: selecting the right communication standard
Make an informed decision considering the best features and disadvantages of each before choosing
Dockerize your Next.JS application
Learn to use Docker for packaging your Next.JS app for testing or deployment for staging or production
Is Behavior-Driven Development right for your Project?
An approach for Product/Software development that involves the whole team and focuses on the behavior of the user