I'm implementing query layer on database by using GraphQl
and spring boot project to perform CRUD operation on sql database. In GraphQL schema i mentioned some fields to be mandatory and when those fields are not mentioned in query it is returning ValidationError
error message in default format with 200
status code.
Error :
{
"data": null,
"errors": [
{
value=StringValue{value='1235'}}]}}]}' is missing required fields '[book_type]' @ 'create_book'",
"locations": [
{
"line": 3,
"column": 23,
"sourceName": null
}
],
"description": "argument 'insert' with value value=StringValue{value='1235'}}]}}]}' is missing required fields '[book_type]'",
"validationErrorType": "WrongType",
"queryPath": [
"create_book"
],
"errorType": "ValidationError",
"path": null,
"extensions": null
}
],
"dataPresent": false,
"extensions": null
}
And here is my code with layer architecture pattern
Controller :
@Autowired
private GraphQLServer graphQlServer;
@PostMapping("test")
public ResponseEntity<Object> graphQl(@RequestBody String body){
ExecutionResult response = graphQlServer.execute(body);
return ResponseEntity.ok(response);
}
Service :
@Service
public class GraphQLServer {
@Autowired
private GraphQL graphQl;
public ExecutionResult execute(String query) {
return graphQl.execute(query);
}
}
Config :
@Bean
public GraphQL loadSchema() throws IOException {
File schemaFile = schemaResource.getFile();
TypeDefinitionRegistry typeRegistry = new SchemaParser().parse(schemaFile);
RuntimeWiring wiring = buildRuntimeWiring();
GraphQLSchema schema = new SchemaGenerator().makeExecutableSchema(typeRegistry, wiring);
return GraphQL.newGraphQL(schema).build();
}
private RuntimeWiring buildRuntimeWiring() {
return RuntimeWiring.newRuntimeWiring()
.type("Mutation", mutationWiring -> mutationWiring.dataFetcher("create_book", bookDataFetcher))
.build();
}
BookDataFetcher :
@Override
public Map<String, Object> get(DataFetchingEnvironment environment) {
//return data from db by getting Map properties from environment
}
The above code is working as expected but my question here is How to customize the error message? In the error message i would like to mention the status 400
since it is bad request from client
First of all , you should call toSpecification()
on ExecutionResult
to make sure the response obeys the GraphQL Specification.
By default , there is only one ExecutionResult
's implementation provided by graphql-java which is ExecutionResultImpl
, so you can cast ExecutionResult
to it in order to use its transform()
to update its state.
ExecutionResultImpl
internally contains all errors detected by the graphql-java. All of them are in the subclass of GraphQLError
which mean you have to cast it to the specific sub-class during customization.
In your case , the subclass is ValidationError
and the codes look something like :
@PostMapping("test")
public ResponseEntity<Object> graphQl(@RequestBody String body){
ExecutionResult response = graphQlServer.execute(body);
ExecutionResultImpl responseImpl = (ExecutionResultImpl) response;
List<GraphQLError> customizedErrors = Lists.newArrayList();
for (GraphQLError gqlError : responseImpl.getErrors()) {
//Do your error custmosation here....
GraphQLError customizedError = gqlError;
if (gqlError instanceof ValidationError) {
ValidationError error = (ValidationError) gqlError;
customizedError = new ValidationError(error.getValidationErrorType(), error.getLocations(),
"Customizing some error message blablabla....");
}
customizedErrors.add(customizedError);
}
Map<String, Object> specResponse = responseImpl.transform(b->b.errors(customizedErrors)).toSpecification();
return ResponseEntity.ok(specResponse);
}