Hi there! In this post we’ll cover some basics concepts to start describing your app data using the GraphQL Schema. But before we dive any further into detail, let’s find out more about GraphQL's origin, motivation and the problems it's conceived to solve.
GraphQL Origins
Before diving into the GraphQL Schema, let's review briefly how GraphQL was originated and what's about. If you want to skip this section, you can go directly to the schema section
A Bit Of History
GraphQL was created at Facebook (Meta) back in 2012, when they were rebuilding their mobile application. When they transitioned to a native app, they needed to build an API for their news feed from scratch.
After considering many alternatives -including REST- they decided to start a new project, that later would become GraphQL.
We were frustrated with the differences between the data we wanted to use in our apps and the server queries they required. We don’t think of data in terms of resource URLs, secondary keys, or join tables; we think about it in terms of a graph of objects and the models we ultimately use in our apps like NSObjects or JSON
GraphQL was designed to reduce the code needed to prepare and process the data needed both in the frontend and the backend, to bring data-fetching closer to the perspective of product owners and developers.
GraphQL was our opportunity to rethink mobile app data-fetching from the perspective of product designers and developers. It moved the focus of development to the client apps, where designers and developers spend their time and attention.
Three years later the project was open-sourced. Now maintained by a large community of companies and individuals from all over the world.
Today, GraphQL is used in production by lots of different companies such as Airbnb, GitHub, Shopify or Coursera - to name a few.
So, What Exactly is GraphQL?
GraphQL is both a query language and a server-side runtime to fulfill those queries using a type system (schema) you define for your data.
It's an alternative to REST designed to make APIs fast and flexible, providing a complete description of the data, allowing the clients to request exactly what they need.
At its core, a GraphQL query is just a string that is sent to a server to be interpreted and fulfilled, which then returns JSON back to the client.
The GraphQL server exposes a single endpoint and responds with just the data the client asked for.
As we can see the shape of the query closely resembles the response, but how can we know what data and fields can we query for?
GraphQL Schema Definition Language (SDL)
GraphQL is agnostic to the data sources or programming language, in fact there are many implementations in different languages.
Instead GraphQL has its own type system that’s used to define the schema of an API. The syntax for writing schemas is called Schema Definition Language (SDL).
The schema is used to define a collection of types and the relationships between them, but it’s not responsible for defining how the data it's stored or where it comes from.
Queries, Mutations and Subscriptions
In GraphQL there're 3 special object types already predefined for us, that will act as the entry point to our schema and app.
-
Query
are used for fetching data from our server. -
Mutation
used for requesting data modifications. -
Subscription
used for notifying your client in real time about changes to back-end data.
type Query {
albums: [Album!]!
}
As we can see in the example, our albums
query will return a list of Album
. But what is an Album
?
Object Types
Objects and fields are the nuts-and-bolts of any GraphQL Schema. Following with our previous example, lets now define our Album
object.
type Album {
id: ID!
title: String
author: Author!
photos: [Photo]
}
Let’s stop for a second and review what we have here:
-
Album
is an Object Type which contain fields. -
title
is a field of ourAlbum
. - Its value
String
, is a built-in Scalar Type and represent the typetitle
will resolve to. - Note that we also have 2 other fields,
author
andphoto
that point to 2 other object types. -
Author
is another object type which we will define in a moment. - And
[Photo]
a List Type and represent an array of objects.
Adding an exclamation mark at the end of field types like String!
or Author!
means that the field is non-nullable and that you can always expect to receive a value when the field is queried.
It's possible to make nested lists [[Matrix]]
and make list non-nullable using exclamation marks like [Photo!]!
.
In order to complete our schema, let's define next our Photo
and Author
types.
type Photo {
id: ID!
title: String
url: String!
thumbnailUrl: String!
album: Album
}
type Author {
id: ID!
name: String!
email: String
albums: [Album]
}
Scalar Types
Scalar types represent concrete data. In the GraphQL SDL we have 5 built-in scalar types:
-
Int
: A signed 32‐bit integer. -
Float
: A signed double-precision floating-point value. -
String
: A UTF‐8 character sequence. -
Boolean
: true or false. -
ID
: The ID scalar type represents a unique dentifier. It will be serialized as a string and be used by client libraries for caching.
Besides these basic types, most GraphQL libraries will allow you to define custom types, such as Date
or Json
.
Enumeration Types
Enumeration types are a special kind of scalars that are restricted to a particular set of allowed values.
For example, we could express some measure units using an enum instead of the generic scalar String
.
enum Unit {
INCHES
CENTIMETERS
}
type Distance {
unit: Unit!
amount: Float!
}
Enums values are normally expressed using all-caps. They are very useful to validate arguments, keep data values consistent and communicate through our type system that a field will always be one of a finite set of values.
Note that the implementation of GraphQL enums are specific to the language in which our service is implemented.
Arguments and Input Objects
Every field on a GraphQL object can have zero or any number of arguments.
type Query {
albums(ids: [ID]): [Album!]!
}
Arguments in GraphQL are passed by name. In this case, we just added ids
to our albums
field. They can be either required or optional.
It's possible define a default value that will be used when the value of that argument is not explicitly passed.
When we want our arguments to be complex objects we need to use the input type.
input PaginationInput {
limit: Int = 10
offset: Int = 0
}
type Query {
albums(ids: [ID], pagination: PaginationInput): [Album!]!
}
Also be aware that inputs, unlike object types, can't have arguments in their fields and can be made only of scalar types and other input types.
Please note that the snippet above is an incomplete example of how to implement the pagination of a query and it's only used to illustrate the use of inputs.
Unions and Interfaces
Unions and interfaces are both abstract types that allow a field to have multiple object types.
Let's explore them with an example. Let's create 2 different types of books first.
type TextBook {
id: ID!
brand: String!
price: Float
}
type NoteBook {
id: ID!
brand: String!
price: Float
}
Now let's create a quey that returns either one or the other depending on the id
we pass to it.
union Book = TextBook | NoteBook
type Query {
book(id: ID!): Book
}
Note that members of a union type need to be concrete object types. It's not possible to create a union type out of interfaces or other unions.
Now let's explore how to express the same but this time using interfaces.
interface Book {
id: ID!
brand: String!
price: Float
}
type TextBook implements Book {
id: ID!
brand: String!
price: Float
}
type NoteBook implements Book {
id: ID!
brand: String!
price: Float
}
type Query {
book(id: ID!): Book
}
As we can see an interface declares a set of fields that multiple objects must include to implement it.
Wrapping it up
Thank you for making it all the way here, to the end of this post. Today we have explored the building blocks of the GraphQL schema and hopefully after reading this post you're now better prepared to create your own GraphQL service.
As we've seen the GraphQL schema is one of the main elements of the GraphQL spec, enabling some advantages compared to other data fetching making possible to have a hierarchical, declarative and strongly-typed backend API.
If you want to start playing around with GraphQL queries without having to write your own service, I'd recommend you using the Github GraphQL Explorer.
And that's it for now! Please let me know in the comments what do you think about this post and about GraphQL? Would you like to know more about directives, fragments, resolvers and dataloaders? If so, leave a comment below. Thank you so much for reading!
References
https://engineering.fb.com/2015/09/14/core-data/graphql-a-data-query-language/
https://spec.graphql.org/October2021/
https://www.redhat.com/en/topics/api/what-is-graphql
https://www.prisma.io/blog/graphql-sdl-schema-definition-language-6755bcb9ce51
https://www.digitalocean.com/community/tutorials/graphql-graphql-sdl
https://www.apollographql.com/docs/react/data/subscriptions/
https://blog.logrocket.com/what-you-need-to-know-about-graphql-enums/
https://daily.dev/blog/pagination-in-graphql
https://www.optisolbusiness.com/insight/top-5-advantages-of-graphql
https://apiacademy.co/2022/05/key-use-cases-for-graphql-apis/
Top comments (6)
This. is. awesome. Thank you!
Thanks!
Super helpful Article , easy to understand for those who don't have much knowledge about GraphQL and it's schema.Thanks a lot!!!
Thank you @arshiasaleem98 for reading and for your nice comments
Good job, thanks for sharing
Thanks @saeedrz96, glad you liked it