Cynic
Cynic is a GraphQL query builder & data mapper for Rust.
See the README on GitHub for more details.
Overview
To get started with Cynic you'll need a GraphQL schema for the API you wish to query. The examples will be using the star wars API.
Generating a Query DSL
Once you've got your schema installed locally, you'll need to use the
query_dsl
macro to generate a query_dsl for your schema:
This module generates a few things:
- Some structs to represent the Input types the underlying schema. You may need to use these to build mutations or as parameters to queries.
- Definitons of all the Enums in the provided schema. You'll need these if you want to use any enum types.
- Type safe selection set functions. These can be used to build up a query
manually, though it's usually easier to use the
QueryFragment
derive functionality explained below. Hopefully you'll not need to use these directly too often.
Though using macros to generate these is convenient, it does leave a lot of code
to the imagination. You can get a glimpse of the things this defines by running
cargo doc --document-private-items
and having a look in the query_dsl
module
It's not ideal, but at least provides some visibility into the various enum types.
Creating QueryFragments
Now that you have a query_dsl defined, you can start building some queries.
Cynic lets you do this by deriving QueryFragment
for a struct. For example,
if we wanted to know what director title & director a Star Wars film had, we
could define this QueryFragment
:
This Film
struct can now be used as the type of a field on any other
QueryFragment
struct and cynic will know how to turn that into a GraphQL
query, and populate the Film
struct from the response.
For example, if we wanted to know the Director for a particular film:
Here we use the #[cynic_arguments()]
attribute on the film
field to provide a
hard coded film ID to look up. Though useful for demonstration, hard coded
arguments like this aren't much use in reality. For more details on providing
runtime arguments please see below.
Sending Queries
Notice that FilmDirectorQuery
above defines it's graphql_type
as Root
- the root
query type in SWAPI. Whenever you define a QueryFragment
at this level of the
heirarchy it can be used as a query on its own rather than as part of another query.
To send the FilmDirectorQuery
above:
let query = new
let response = new
.post
.json
.send;
let result = query.decode_response.unwrap;
After this code has run, result will be an instance of FilmDirectorQuery
with the film populated appropriately.
Dynamic Query Arguments
The query above was useful for demonstration, but you'll usually want to be able to provide parameters to your query. To do this, you should define a struct that contains all of the parameters you want to provide:
Deriving FragmentArguments
allows this struct to be used as arguments to a
QueryFragment
fragment, whether it represents part of a query or a whole query.
You can now define a query to use these arguments on. For example, to make
FilmDirectorQuery
a bit more dynamic:
By adding the argument_struct
parameter to our QueryFragment
we've made a variable
named args
avaiable for use in the cynic_arguments
attribute. This args
will
be an instance of FilmArguments
and will need to be provided whenever this is used
as a query.
To build a query using this new struct:
let query = new;