GraphQL Notes - (Express-GraphQL)
GraphQL is an open source server-side technology which was developed by Facebook to optimize RESTful API calls. The word graph in GraphQL comes from the fact that the best way to represent data in the real world is with a graph-like data structure. GraphQL is not specific to any backend or frontend framework, technical stack, or database. It can be used in any frontend environment, on any backend platform, and with any database engine.
The REST is just a specification that tells how communication should happen between browser and server, while GraphQL is also a specification with actual piece of code running on top of the server.
It was mainly developed the following 2 types of problems :
- Over-Fetching : Fetching too much data, meaning there is data in the response you don't use,this transfr of extra data increases network bandwidth.
- Under-Fetching : Under-fetching is not having enough data with a call to an endpoint, forcing you to call a second endpoint. This is a significant problem, especially for mobile applications, because mobile devices usually have processing, memory, and network constraints.
GraphQL is a syntax that describes how to ask for data, and is generally used to load data from a server to a client. GraphQL has three main characteristics:
- It lets the client specify exactly what data it needs.
- It makes it easier to aggregate data from multiple sources.
- It uses a type system to describe data.
To solve the multiple round-trip problem, GraphQL makes the responding server work as a single endpoint. Basically, GraphQL takes the custom endpoint idea to an extreme and makes the whole server a single smart endpoint that can reply to all data requests.
NOTE : Unlike REST API where we create different endpoints for different resources,when using Graphql we just have single endpoint to acess the resources. We can perform HTTP methods like GET, POST, PUT etc on this endpoint. GraphQL lets you ask for what you want in a single query, saving network bandwidth.
The GraphQL is basically a specification which defines how to exchange data effectively. There are many tools available which implement this specification and let us add GraphQL to our system. There are 2 components in any GraphQL system :
1] GraphQL Server - A server-side implementation of the GraphQL spec. In other words, a GraphQL server exposes your data as a GraphQL API that your client applications can query for data. To build a GraphQL server you can use tools like Express-graphql, Apollo-server etc.
2] GraphQL Client - It is code that makes a POST request to a GraphQL Server. You can use a pre-built GraphQL client (Eg- Relay,Apollo-client etc) or just use HTTP GET/POST to exchange data from the GraphQL server.
---------------------------------------------------------------------------------------------------------------
How GraphQL works ?
GraphQL is all about seeing your data as a graph, and then querying that graph. It allows you to precisely define the schema of the data you are making available, then gives you a powerful query interface to navigate, traverse, and discover what you need.
On the backend, GraphQL provides a structure for servers to describe the data to be exposed in their APIs. This structure is what we call a "schema" in the GraphQL world. An API consumer can then use the GraphQL language to construct a text request representing their exact data needs.
Every GraphQL server has 2 core components :
- Schema
- Resolver Functions
1] Schema
The schema is a model of the data that can be fetched through the GraphQL server. It defines what queries clients are allowed to make, what types of data can be fetched from the API. It is also known as "Type definations". A schema defines a collection of types and the relationships between those types.The main components of a schema definition are the types and their fields.
To create a GraphQL API, you need a typed schema. A GraphQL schema contains fields that have types. Those types can be primitive or custom. Everything in the GraphQL schema requires a type. This type system is what makes a GraphQL service predictable and discoverable.
NOTE : If you have a GraphQL query, you know exactly how to use its response in the UI because the query will have the same structure as response. You do not need to inspect the response to know how to use it, and you do not need any documentation about the API. See the below Image for example which shows the query and its response.
The Schema only describes what data the clients can fetch,but it still does'nt have a way to generate or populate these data fields. This is where the 'Resolver' functions come in.
2] Resolver Functions
A resolver is a function that's responsible for populating the data for a single field in your schema. Whenever a client queries for a particular field, the resolver for that field fetches the requested data from the appropriate data source.
NOTE : Every field in your schema must have one resolver function.
GraphQL resolve functions can contain arbitrary code, which means a GraphQL server can to talk to any kind of backend, even other GraphQL servers. For example, the 'title' type field could be stored in a SQL database, while Posts are stored in MongoDB, or even handled by a microservice.
Perhaps the greatest feature of GraphQL is that it hides all of the backend complexity from clients. No matter how many backends your app uses, all the client will see is a single GraphQL endpoint.
NOTE : Together with the help of schema and resolver functions,the client just need to specify which fields it needs and the GraphQL server will execute their resolver functions to populate those fields and send their values as response.
There many various tools that we can use to Implement GraphQL API's :
- Javascript - (Express-GraphQL, GraphQL.js) or (Apollo-server, Apollo-client)
- Python - Graphene
---------------------------------------------------------------------------------------------------------------
Schema Definition Language (SDL)
GraphQL has its own language to write GraphQL Schemas called Schema Definition Language (SDL). A GraphQL Schema Definition is the most concise way to specify a GraphQL schema. The syntax is well-defined and are part of the official GraphQL specification. When you are building a GraphQL API, you'll be using SDL to define the schema.
The main components of a schema are the 'object types' and their 'fields'. Each field has a return type of its own. A field's type can be scalar (such as an Int or a String), or it can be another object type. We declare a type using the "type" keyword, followed by the name of the type, then opening brackets to hold its contained fields.
NOTE : Each field returns data of the type specified. A field's return type can be a (scalar, object, list, enum, union, or interface). The schema only specifies what the field will return,the actual logic to return the data is managed by resolver functions.
Unlike Javascript objects (which look very similar), fields are not separated by commas. By default, it's valid for any field in your schema to return null instead of its specified type, we can indicate whether each field value is nullable or non-nullable. If a field should never be null, we add an exclamation mark after its type. If your server attempts to return null for a non-nullable field, an error is thrown.
Supported Data Types
Below are the data types supported by GraphQL, every type definition in a GraphQL schema belongs to one of the following :
- Scalar
- Object
- Input
- Enum
1] Scalar Type
Scalar types are like built-in Primitive types in any programming language. In GraphQL, we also have these types which we call Scalars :
Int : A signed 32‐bit integerFloat : A signed double-precision floating-point valueString : A UTF‐8 character sequenceBoolean : true or false
These primitive types cover the majority of use cases. For more specific use cases, you can create custom scalar types.
2] Object Type
Most of the types you define in a GraphQL schema are object types.Each object holds a set of key-value pair, where keys are called as fields, and each field defines the types of data they return, which can be Scalar or another Object. Two object types can include each other as fields as shown below.
(Read about Queries & Mutations before reading the below types)
3] Input Type
Input types are special object types that allow you to provide hierarchical data as arguments to query/mutation fields (as opposed to providing only flat scalar arguments). An input type's definition is similar to an object type's, but it uses the input keyword.
NOTE : Input types can't have fields that are other objects, only basic scalar types, list types, and other input types. These are mostly used with mutations to accept objects as arguments.
4] Enum Type
Enum is a special type of object which we can use to store a pre-defined set of values. These are mostly used with queries/mutation fields,enums are most useful in situations where the user must pick from a prescribed list of options.
NOTE : If the given field value is not present inside the Enum,then GraphQL throws an error.
Example] In below example we restrict the values of query field to Enum.
The query sent from the client and the response returned by the server.
---------------------------------------------------------------------------------------------------------------
GraphQL Operations
When we create a GraphQL server, we perform all operations by interacting with a single endpoint. The following are operations that we can perform on GraphQL API :
- Queries
- Mutations
When you need to read data with GraphQL, you use queries; and when you need to modify data, you use mutations.These types are the same as a regular object type, but they are special because they define the entry point of every GraphQL query. These are also called "Root operations".
NOTE : If queries are the GraphQL equivalent to GET calls in REST, then mutations represent the state-changing methods in REST (like POST ,DELETE, PUT, PATCH, etc).
1] GraphQL Queries
A query is a GraphQL Operation that allows you to retrieve specific data from the server. When a client wants to fetch data from the GraphQL server it'll send a query to the server,then based on query the server will generate a response.
GraphQL queries help to reduce over fetching of data. Unlike a Restful API, GraphQL allows a user to restrict fields that should be fetched from the server. This means smaller queries and lesser traffic over the network; which in turn reduces the response time.
NOTE : The shape of your query sent from client to the server will be the same as the result returned by the server,hence clients only get what they asked for.
In GraphQL you create a query using the "Query" keyword. The Query type is a special object type that defines entry points for read operations. Each field of the Query type object defines the name and return type of a different entry point.
Example] In below example we create schema containing query endpoints and their resolvers,later we combine them together.
To fetch the data from the server the client sends a query to server. You can change add/remove the fields to tell the server what you need in the response. You send the query as POST request or use a GraphQL client library.
NOTE : In your entire schema there can only be one root Query type object. You add all your endpoints/fields inside it to expose your API. If you create another then you'll get error.
Passing field arguments
In a system like REST, you can only pass a single set of arguments - the query parameters and URL segments in your request. But in GraphQL, every field and nested object can get its own set of arguments, making GraphQL a complete replacement for making multiple API fetches.
Example] In below example we create schema containing query endpoints,each accepting a set of arguments.
The query sent from the client and the response returned by the server.
2] GraphQL Mutations
In REST, any request might end up causing some side-effects on the server, but by convention it's suggested that one doesn't use GET requests to modify data. GraphQL is similar - technically any query could be implemented to cause a data write. However, it's useful to establish a convention that any operations that cause writes should be sent explicitly via a mutation.
In GraphQL you create a mutation using the "Mutation" keyword. A mutation can contain multiple fields, just like a query. Its kind of similar to a POST method in Rest API's.
NOTE : While query fields are executed in parallel, mutation fields run in series, one after the other.
Example] In below example we create schema containing query & mutation endpoints,each accepting a set of arguments.
The query sent from the client and the response returned by the server.
Mutations with Input Objects (Useful : 1] Click)
In most cases using the scalar type as arguments for mutations works fine,but sometimes you may need to pass large number of arguments to a mutation or may need to pass same arguments to multiple mutations. In such cases we can use the built-in "Input Type" objects.
Input types are special object types that allow you to provide hierarchical data as arguments to fields (as opposed to providing only flat scalar arguments).
NOTE : Input types can't have fields that are other objects, only basic scalar types, list types, and other input types. On client-side to pass a Input type as argument inside the query provide the data written as if it's a JSON object.
Example] In below example we create schema containing mutation field with input type object as argument.
The query sent from the client and the response returned by the server.
---------------------------------------------------------------------------------------------------------------
GraphiQL Operation Name
GraphQL provides a browser based interactive interface to execute our queries,it is called "GraphiQL".
NOTE : When you provide more than one mutation/query side-by-side in GraphiQL,if they dont have operation names they wont be executed.
When they have operation names they can be listed when you click the play / run button and thy will be executed sucessfully.
---------------------------------------------------------------------------------------------------------------
GraphQL Fragments
A GraphQL fragment is a piece of logic that can be shared between multiple queries and mutations. Sometimes you may want to reuse some fields in multiple queries or mutations,that is where we can use fragments. Fragments let you construct sets of fields, and then include them in queries where you need to.
fragment Name on TypeName {
field1
field2
field3
}A fragment consists of three unique components :
- Name : This is the unique name of the fragment (each fragment can have its own name)
- TypeName : The type of object the fragment is going to be used on. This indicates which nested object, from the GraphQL schema, this fragment is created on
- Body : The last part is the body of the fragment. The body of the fragment defines the fields that will be queried for.
NOTE : Every fragment includes a subset of the fields that belong to its associated type. Once you have created a fragment you can use the spread operator ("...") to include all the fragment fields whereevery you want.
In the below example, the Person type must declare firstName and lastName fields for the NameParts fragment to be valid.
Example] In below example we create a fragment of fields to reuse in different queries on the client side.
The query sent from the client and the response returned by the server.
---------------------------------------------------------------------------------------------------------------
GraphQL Caching (Useful : 1] Click)
Just like HTTP requests, we can also cache the queries against their responses in GraphQL, so that if the client sends a similar query again,its value will be fetched from the cache and not the GraphQL server.
NOTE : The express-graphql module does'nt support caching, you can use the Apollo GraphQL library instead.
---------------------------------------------------------------------------------------------------------------







Comments
Post a Comment