Introduction
In this article, we will dive into the details of schema definition in GraphQL. The article will help you understand not just what schema is but also further articles related to graphQL.
If you want to read graphQL articles in sequence, please read,
- GraphQL in .Net: Introduction
- GraphQL in .NET: Practical Usage
- GraphQL in .NET: Pagination
This is the 4th article in the series “GraphQL in .NET”
As you can see from our previous articles’ examples, the main purpose of queries in graphQL is to select any field or fields in any object.
Classic graphQL queries have root : subelement: element of this subelement logic.
{
customers{
name
cards{
id
cvc
}
}
}
As you can see, our root element is anonymous here. The root element is also called the root type. Usually, when making queries in graphQL (read-only), if there is only 1 query in our document, the anonymous type is shown to make it easier to work.
In our next article, when we give detailed information about Queries, we will see that the anonymous types here are actually query types. Inside our root type is the customer's field. This field type is an object, and therefore, other fields are defined within it. In our example, this is just the name field. Also, inside the customer's object is another card's object. This object, in turn, is composed of several other fields.
GraphQL can be implemented using any backend language or framework, where graphQL uses its schema language to define language-independent structure.
Through schemas, we can see which object to query, which fields and objects are contained in this object, and what type they are.
In Banana Cake, the "schema definition" defines the schema of our type.
In the GraphQL scheme, types are divided into 2 main categories:
- Objects
- Scalar types
Each object has at least 1 field. Let's look at the above example again.
Please use our repo to follow the examples.
Let's run the 002_GraphQLWithEFCore project from the repo with the removed attributes:
public class Query
{
//[UsePaging(MaxPageSize = 2, AllowBackwardPagination = true)]
//[UseProjection]
//[UseFiltering]
//[UseSorting]
public IQueryable<Customer> GetCustomers([Service] GraphQLAppDbContext graphqldbcontext)
=> graphqldbcontext.Customers.Include("Cards");
}
So below Query is executable against the graphQL server:
{
customers{
name
cards{
id
cvc
}
}
}
When you run the project and navigate to /graphQL route, you can see "schema definition".
The type definition for this Query is:
type Query {
customers: [Customer!]!
info(message: String!): String!
}
type Customer {
id: Int!
name: String!
email: String!
cards: [Card!]!
}
type Card {
id: Int!
number: String!
cvc: String!
expiryDate: String!
customerId: Int!
customer: Customer!
}
GraphQL has a very simple syntax, but let's simply interpret the above:
The type keyword specifies the type.
- Query, Customer, Card – the name of the type
- customers: internal field for root Type ( here it is Query)
As you can see, customers as a field have a special custom-defined type : [Customer!]!
The [] here indicates that the field is an array.
The exclamation mark ( ! ) here indicates that the field type is not nullable.
The last one is for [Customer!]! We have 2 exclamation marks here. The external exclamation mark defines that array is not nullable; the internal one indicates that this array can’t have a nullable value. So long story short, the full meaning is: “Not nullable array with not nullable values” or “The not nullable array which can’t have nullable values”.
By itself, the customer as a type consists of 3 fields:
- Id – int and not nullable
- Name, email – string ( not nullable)
- Cards – card array – not nullable and can’t contain null values
In the end, you can ask, "So why do we need schemas in graphQL?"
Well, here is the answer:
In GraphQL, a schema is a building block of the system that defines the structure and functionalities of the API. It acts as a contract between the client and the server, outlining what types of data can be requested and how they can be manipulated.
Why do you need it?
- Type validation: The schema specifies the types of data available in the API and how they are related to each other. This allows GraphQL to validate queries against the schema and ensure that only valid requests are executed. It helps catch errors early in the development process and provides clear feedback to the client. GraphQL service uses schema to validate the contract; if it is valid, it calls the related functionalities for fields.
- Documentation: A well-defined schema acts as documentation for the API. It describes the available types, fields, and relationships, making it easier for developers to understand and interact with the API. The schema can be introspected to generate documentation automatically, reducing the effort required to keep it current.
- Query planning and optimization: The GraphQL server can analyze and optimize incoming queries with a schema. It can determine the exact fields and resources needed to fulfill the request, avoiding unnecessary data fetching and reducing response times. The schema provides the server with the necessary information to optimize the execution plan.
- Tooling and ecosystem support: GraphQL has a rich ecosystem of tools and libraries built around it. Many of these tools rely on the schema to provide advanced features such as automatic code generation, static analysis, and IDE support. The schema is the foundation for these tools, enabling developers to benefit from the GraphQL ecosystem.
Summary
Overall, a schema in GraphQL provides a central contract that defines the API's structure, validates queries, optimizes execution, facilitates documentation, supports evolution, and enables a thriving ecosystem of tools and libraries.
Well, that is all for now. This was an introduction to schemas in graphQL, and we’ll continue discussing scheme details in the next articles.