Getting Started

Our first query

Let's create our first query with graphql-ppx. In this case we will write a query to fetch the current user. We can create a query with the following code.

[%graphql {|
query UserQuery {
user {
id
name
}
}
|}];

This is quite similar to how we could define a query in JavaScript. Depending on the client, in JavaScript we usually do something like this:

let query = gql`
query UserQuery {
user {
id
name
}
}
`;

However, the ReasonML code does much more. It will not only create a query that you can pass to the client. It will also generate the types of the data that we get back from the GraphQL server.

The shape of the data that we get back from the server has the type UserQuery.Raw.t. This represents the data exactly like the response type. The type that is being generated by graphql-ppx is:

module Raw = {
type t_user = {
id: string,
name: Js.Nullable.t(string)
};
type t = {
user: t_user
};
}

So once we successfully get data back from the server it is of type Js.Json.t. To work with it we can typecast it into UserQuery.Raw.t.

let typedData = UserQuery.unsafe_fromJson(data)

UserQuery.unsafe_fromJson is a helper function that will cast a Js.Json.t to the GraphQL Raw type. In JavaScript this will not generate any code, it will just tell the compiler to cast it into the Raw type. With GraphQL we know that if we get a response that this conforms to the shape of our query. This allows us to convert the generic Js.Json.t to richer and more specific type. To get the user's id, we can get it like we are used to in ReasonML:

let userName = typedData.user.id

As it is a normal ReasonML value now, we can do everything we want with it, like for instance pattern matching.

let userName = switch(user) {
| {user: {id}} => id
}

Parsing data

However it's not perfect. In this example it would be nice if the user's name could be converted to a more idiomatic ReasonML data structure like an option type. This is exactly what parse does.

let parsedData = UserQuery.parse(typedData)

With parse the data is converted into idiomatic ReasonML data types. In this case the name is converted from Js.Nullable.t(string) to simply option(string). This means we can write the following code:

let name = switch(parsedData) {
| {user: {name: Some(name)}} => name
/* the user's name is null */
| _ => "Anonymous"
}

Also in some cases the JSON data can not be directly represented by a ReasonML type. For instance in case of a union, ReasonML doesn't allow arrays to contain values with different types, so it cannot be directly mapped. In those cases the raw type will be an opaque type1. When the raw result is parsed it is converted to a list of a variant.

Usually you will not be working with the raw type. This is an implementation detail that is normally only used inside of the GraphQL client. In most cases the parsed result will be what you get back from the library.

Fragments

Using a client

An opaque type is essentially a value that you can't access directly. So the value is opaque to the user