We can use different languages to implement a GraphQL server. GraphQL is a strongly typed language and it is really important to learn about the type system. Also, even though you are going to use a single framework in the future for developing your server or client-side application, it is a good idea to learn about the different GraphQL Components like a client, server, schema etc. libraries available.
In this post, we are going to discuss different GraphQL client-server frameworks, type systems, and the validation and execution process of a GraphQL request.
GraphQL Client and Server :
A GraphQL server can be implemented in many programming languages. Many popular client-side frameworks are available to build the client application. But you can also call a GraphQL server using a simple POST request. Mark the xContent-typex as xapplication/jsonx and pass the query as a xqueryx field in a JSON payload. For example :
curl -X POST -H "Content-Type: application/json" -d '{"query": "{ student }"}' http://localhost:8000/graphql
This xcurlx request will return the output as JSON for the query x{ student }x. For testing GraphQL queries during development time, you can use Graphical user interface libraries like GraphiQL and Insomnia.
Without a client framework, a GraphQL application can be built but the main advantage of using a client framework is that they already have many useful inbuilt features like caching, batching, etc. Also, a framework makes it easier to organize the application. You can check this page to learn more about the popular client libraries, server-side frameworks, services, and other useful GraphQL related packages.
GraphQL Schema and Type system:
GraphQL is available in a lot of backend technologies. You can use any one of them to develop a GraphQL server. GraphQL Schema is used to describe the functionalities of a GraphQL server that the client will use to connect. A Schema is defined by various data types. GraphQL is strongly typed and the Schema is defined using the type system. For example,
{ student { name age } }
Suppose this GraphQL query is used to get the xnamex and xagex of a xstudentx object. The client can request for any type of data from the server using different queries. But the main functionality of the server is still unavailable to the client. Schema is used for that. It will define the type operations available for the client, the relationship between different types and kind of data the client will receive. The Schemas are validated and executed when the server receives a query.
GraphQL Schemas are written in their own language called xSchema Definition languagex or xSDLx. It is easy to use human-readable language.
Object types, fields and Scalar types :
Objects are the basic components of a GraphQL schema. It is used to represent what type of objects we are fetching from the server. Each object includes some fields or the properties we want for that object. Each field will resolve based on its xscalar typex. Let me quickly explain to you these concepts with a simple example :
type Student { name : String! age : Int! marks : [Mark] } type Mark{ subject : String! mark : Int! }
In this Schema :
- Student and Mark are both object type. Each object holds the fields that can be included in these objects.
- name, age, marks, subject, and mark are all fields of Student and Mark
- String and Int are built-in scalar types. The x!x sign marks the field as non-nullable. So, if you are querying for xStudentx, the server will return always non-nullable xnamex, xagex and xmarksx.
In the above example, we have seen two scalar types xStringx and xIntx. GraphQL comes with the following default scalar types :
- Int: Signed 32 bit integer
- String : UTF-8 character sequence
- Float: Signed double-precision floating point value
- ID: Unique identifier
- Boolean: true or false boolean value
GraphQL also provides us the option to create custom scalar types like below :
scalar MyType
Arguments and Enumeration type:
The field of a GraphQL object can have zero or more arguments. The GraphQL arguments are named. For example :
type Student{ name : String! getMarks(rollNo : Int!) : Int! }
In this example, xgetMarksx field has one defined argument xrollNox . This is a required argument. We can also mark an argument as xoptionalx and provide one default value for that.
Enumeration type, also known as Enums are used to define a set of constant values like below :
enum Grade { A B C }
i.e. for type xGradex, we can have a type of xAx, xBx or xCx. Different languages deal differently with enums in GraphQL. For example, JavaScript doesnxt support enum. So, enum values are mapped to a set of integers internally in JavaScript. These things are handled internally by GraphQL and we can use enums as String for all languages.
Query and Mutation type :
A query is used to fetch data from a GraphQL server and Mutation is used to modify (create, delete and update) data of a GraphQL server. For defining a query, schema definition language is used. The query and mutation types are similar to any GraphQL object types. For example :
type Query { getStudent: [Student] } type Mutation { addMarks(subjectName: String!, marks: Int!): Subject }
The first example is a xQueryx type and the second example is xMutationx type.
List and Non-null :
Sometimes, the client may require only non-null values from the server. In GraphQL we can mark any type as non-null using the x!x sign. Letxs take a look at the below example :
type Student { name: String! }
Here, we are expecting a xStringx type xnamex from the server. We have also marked it as xnon-nullx by adding a x!x sign to the end. The server will try to find a non-null value for xnamex and if it finds any xnullx value, it will inform the client that something went wrong. We can also use this non-null type modifier with arguments as well. If you use it with an argument, the client will have to deal with it. i.e. if any null value is passed, it will return one validation error.
We can also mark a type modifier as List by wrapping it inside square bracket x[]x . It means the server will return an array of the type. For example x[String]x means an array of String variables.
The list can also be used as an argument and we can also mark a list or its type as xnon-nullx.
[String!] means that the list can be null but it canxt have any null members.
[String]! means that the list canxt be null but it can have null members.
[String!]! means that the list canxt be null and also it canxt have any null members.
Interface, union and input types :
An interface is used to define a set of common fields. It is an abstract type and any other type can implement it. If a type implements an interface, it will have to include the fields defined by that interface. For example :
interface Car { doors: Int! wheels: Int! color: String! }
The above interface defines the common properties of a car. Any other type can implement this interface like below :
type Audi implements Car { doors: Int! wheels: Int! color: String! model: String! }
As you can see, xAudix type has implemented the xCarx interface and it includes all the fields defined in the interface xCarx, but it can also add extra fields that are specific to the type.
A union type is used to represent multiple types that donxt need to have any common fields. For example, if our server can return any xCarx, xBusx or xPlanex type for a specific query, we can define the return type as below :
union returnType = Car | Bus | Plane
We can also use Scalar types to create a union.
In our previous examples, we have seen how to pass a scalar value as an argument. But we can also pass complex objects as an argument in GraphQL. This is useful for mutation. If we are creating a new object, we can pass it as an argument.
The input type is defined with the keyword xinputx . For example,
input Student { name: String! age: Int! address: String! }
It looks similar to the object xtypex.
Validation and execution :
In GraphQL, all requests are validated first before executing them. An invalid request will provide a meaningful message to the user during the compilation time. GraphQL has few predefined validation rules and these rules are checked for each query. The GraphQL service validates a request when it is required. If a request is validated, the service will memorize the request and it will not change if it doesnxt change.
Once a query is validated, it will be executed on a GraphQL server. The server will produce one result JSON based on the request query and returns it. Each field of a GraphQL query is backed by a function called resolver function. When a GraphQL query is executed, the resolver function for each field will execute. The resolver function will check if it is a scalar value or not. If it is not a scalar and if it is an object, its included field resolver functions will execute. The process will continue until a scalar value is reached.
A resolver function of a GraphQL schema accepts four arguments :
- obj: The previous object or the result returned by the previous parent resolver of the execution.
- args: arguments provided to the field in the GraphQL query
- context: This object is shared by all resolvers in a query. It holds important information like currently database access permission, logged in user details, etc.
- info: Holds different information about the execution state of the query and schema details.
Tutorial Index:
- GraphQL Tutorial #1 -Introduction
- GgraphQL Tutorial #2 x Setting Basic Project in GraphQL
- GraphQL Tutorial #3 x GraphQL Components
- GraphQL Tutorial #4 x GraphQL Operations
- GraphQL Tutorial #5 x Introduction to Apollo GraphQL
- GraphQL Tutorial #6 x 51 Most Important GraphQL Interview QxA