Getting Started - GraphQL API framework
Resolves interfaces and unions into concrete GraphQL types.
These functions are available on the TypeResolutionEnvironment object.
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
- Schema namespace - The namespace (unique identifier) for the schema in the current application
- 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.
https://www.servicenow.com/community/developer-articles/getting-started-graphql-api-framework/ta-p/2312207