- Post History
- Subscribe to RSS Feed
- Mark as New
- Mark as Read
- Bookmark
- Subscribe
- Printer Friendly Page
- Report Inappropriate Content
12-27-2021 11:28 AM - edited 04-24-2023 12:15 AM
What is GraphQL?
GraphQL is an open-source data query and manipulation language for APIs, and a runtime for fulfilling queries with existing data. It's an alternative to standards like REST. It lets clients fetch exactly the data they need which makes API development faster, flexible, and easy to test. It has a single endpoint for all types of requests.
Please read more about GraphQL basics here.
Using GraphQL on Now Platform
Please find the documentation here.
There are 4 basic components while designing GraphQL APIs on Now Platform
- Schema
- Scripted Resolver
- Type Resolver
- Resolver Mapping
Schema
Defines the structure and type of data using GraphQL Schema Definition Language (SDL). It supports Query and Mutation operations along with custom object type, input, union, interface, enum, and default scalar types (Int, Float, String, Boolean, and ID).
Scripted Resolver
Defines the data returned by each field.
These functions are available on the ResolverEnvironment object.
- getArguments(): Returns the arguments of the previous field.
- getSource(): Returns the parent object.
Type Resolver
Resolves interfaces and unions into concrete GraphQL types.
These functions are available on the TypeResolutionEnvironment object.
- getArguments(): Returns the arguments of the previous field.
- getObject(): Returns the object received from data fetcher.
- getTypeName(): Returns the name of the interface or union type.
Resolver Mapping
Maps resolvers to fields in the schema.
Hey, let's build something now
Usecase: Develop a GraphQL API to perform the below operations
- Get Incident Number, Short description, and Category using sys_id
- Close an active Incident using sys_id and add the given Resolution code, Resolution notes, and update the category if given
Solution:
Note: Please go through the documentation to become familiar with the GraphQL basics on the Now Platform
Create a new GraphQL API
- Navigate to System Web Services -> GraphQL -> GraphQL APIs
- Click on 'New' and fill in the below details in order to create a new GraphQL API
-
- Name - Name of the schema
- Schema namespace - The namespace (unique identifier) for the schema in the current application
- Select relevant Security configuration. For this usecase, let's go with only 'Requires authentication
- Click on 'Submit'
Build Schema
- We see two object types Query and Mutation in the schema by default. These objects are the entry point for the operations we want to perform via the API.
- 'Query' type is required for retrieving data.
- 'Mutation' type is required for updating or deleting the data
Let's add the below operation in Query
type Query {
getIncidentDetails(sysId: ID!): GetIncidentDetailsResult!
}
Let's define an Error interface that needs to be implemented by all types of Error responses
interface Error {
errorType: String!
errorMessage: String!
}
Define GetIncidentDetailsResult type
union GetIncidentDetailsResult = GetIncidentDetailsSuccess | GetIncidentDetailsError
Define GetIncidentDetailsSuccess
type GetIncidentDetailsSuccess {
number: String!
shortDescription: String!
category: String
}
Define GetIncidentDetailsError
type GetIncidentDetailsError implements Error {
errorType: String!
errorMessage: String!
}
So, we are done with creating Schema for the getIncidentDetails query.
Here is the complete Schema as shown below
Let's create a new GraphQL Scripted resolver for the getIncidentDetails query named "Get Incident Details Resolver"
(function process( /*ResolverEnvironment*/ env) {
var args = env.getArguments();
var sysId = args.sysId;
var gr = new GlideRecordSecure("incident");
if (gr.get(sysId)) {
return {
number: gr.getValue("number"),
shortDescription: gr.getValue("short_description"),
category: gr.getValue("category")
};
}
return {
errorType: "IncidentRetrievalError",
errorMessage: "Record sys_id is not valid"
};
})(env);
Add a new GraphQL Resolver mapping as shown below. It tells the framework which Resolver script to execute for which query.
Create a new GraphQL Type Resolver to resolve the type of object returned in union GetIncidentDetailsResult
(function process( /*TypeResolutionEnvironment*/ env) {
var obj = env.getObject();
return obj.hasOwnProperty('errorType') ? 'GetIncidentDetailsError' : 'GetIncidentDetailsSuccess';
})(env);
Create a new GraphQL Type Resolver to resolve the type of concrete implementation returned in interface Error
(function process( /*TypeResolutionEnvironment*/ env) {
var obj = env.getObject();
var error;
switch (obj.errorType) {
case "IncidentRetrievalError":
error = "GetIncidentDetailsError";
break;
}
return error;
})(env);
We are done with creating Scripted Resolvers, Type Resolvers, and Resolver mappings for our first query getIncidentDetails
Let's test it out
I am using Insomnia for the demo purpose. Please feel free to use any other tool.
Success:
Error:
Now, we will build our first mutation.
Let's add the below operation in Mutation
type Mutation {
closeIncident(closureDetails: CloseIncidentInput!): CloseIncidentResult!
}
Define CloseIncidentInput type input
input CloseIncidentInput {
sysId: ID!
resolutionCode: String!
resolutionNotes: String!
category: String
}
Define CloseIncidentResult type
union CloseIncidentResult = CloseIncidentSuccess | CloseIncidentError
Define CloseIncidentSuccess
type CloseIncidentSuccess {
number: String!
}
Define CloseIncidentError
type CloseIncidentError implements Error {
errorType: String!
errorMessage: String!
}
So, we are done with creating Schema for the closeIncident mutation.
Here is the complete updated Schema as shown below
Let's create a new GraphQL Scripted resolver for the closeIncident mutation named "Close Incident Resolver"
(function process( /*ResolverEnvironment*/ env) {
var args = env.getArguments();
var sysId = args.closureDetails.sysId;
var resolutionCode = args.closureDetails.resolutionCode;
var resolutionNotes = args.closureDetails.resolutionNotes;
var category = args.closureDetails.category;
var gr = new GlideRecordSecure('incident');
if (gr.get(sysId)) {
gr.setValue('state', 7);
gr.setValue('close_code', resolutionCode);
gr.setValue('close_notes', resolutionNotes);
if (category) {
gr.setValue('category', category);
}
gr.update();
return {
number: gr.getValue("number")
};
}
return {
errorType: "IncidentClosureError",
errorMessage: "Record sys_id is not valid"
};
})(env);
Add a new GraphQL Resolver mapping as shown below
Create a new GraphQL Type Resolver to resolve the type of object returned in union CloseIncidentResult
(function process(/*TypeResolutionEnvironment*/ env) {
var obj = env.getObject();
return obj.hasOwnProperty('errorType') ? 'CloseIncidentError' : 'CloseIncidentSuccess';
})(env);
Update the GraphQL Type Resolver of interface Error
(function process( /*TypeResolutionEnvironment*/ env) {
var obj = env.getObject();
var error;
switch (obj.errorType) {
case "IncidentRetrievalError":
error = "GetIncidentDetailsError";
break;
case "IncidentClosureError":
error = "CloseIncidentError";
break;
}
return error;
})(env);
We are done with creating Scripted Resolvers, Type Resolvers, and Resolver mappings for our first mutation closeIncident
Let's test it out
Success:
Error:
I hope that you enjoyed the article. Please let me know if you have any suggestions or comments.
- 12,114 Views

- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
Following your steps, the schema does not save and errors with Schema:The field type 'getIncidentDetailsResult' is not present when resolving type 'Query' [@6:1].
Some additional context on how the union GetIncidentDetailsResult functions would be helpful. I'm not sure how the two would union unless the idea is on failure there is an empty result set for success to it produces one table or the other.
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
Hi @Mike Perkins,
Thank you for trying it out. It was a typo.
Please follow the updated steps. Also added the final Schema screenshots to make it easy to follow.
union GetIncidentDetailsResult would help here the client to parse responses from the API in a more predictable fashion.
As there might be scenarios when the getIncidentDetails query fails due to an invalid sys_id or some security constraints, we still want to return a structurally valid and meaningful response. It would help the client to understand the root cause of failure and how it might be resolved.
union type of response helps us to return different types of responses based on the processing outcome.
Hope it helps!
Please read more about union types here.
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
@shivam gupta Thanks for writing down and explaining in detail, I am new to graphql and trying to understand more on it I have a few fundamental queries:
1-> When we say it is an alternative to REST, what better it has to offer than REST, or in what situation GraphQL is better than REST, if you can give a simple use case would be really helpful.
2-> What type of authentication/authorization mechanism is supported for graphQL?