I've configured GraphQL in spring boot application which uses java 17
.
To start application you need gradle bootRun
.
To try GrapqQL
request you can use curl
:
curl -X POST http://localhost:8085/graphql \
-H "Content-Type: application/json" \
-d '{"query":"query {\n bookById(id: \"book-1\"){\n id\n name\n pageCount\n productionDate\n authors {\n id\n firstName\n lastName\n }\n }\n}"}'
The current configuration doesn't use custom type LocalDate
and no date formatting with pattern"dd/MM/yyyy"
.
The GraphQL configuration schema.graphqls
type Query {
bookById(id: ID): Book
}
type Book {
id: ID
name: String
pageCount: Int
authors: [Author]!
productionDate: String
# productionDate: LocalDate
}
type Author {
id: ID
firstName: String
lastName: String
}
requires productionDate: LocalDate
(in the line 10). The custom java
configuration is managed in the ScalarConfiguration.java
following spring-boot,
package com.graphqljava.tutorial.bookDetails;
import graphql.language.StringValue;
import graphql.schema.*;
import org.springframework.boot.autoconfigure.graphql.GraphQlSourceBuilderCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.graphql.execution.RuntimeWiringConfigurer;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
@Configuration(proxyBeanMethods = false)
public class ScalarConfiguration {
private final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd/MM/yyyy");
@Bean
public GraphQLScalarType dateScalar() {
return GraphQLScalarType.newScalar()
.name("LocalDate")
.description("Java 8 LocalDate as scalar.")
.coercing(new Coercing<Object, Object>() {
@Override
public String serialize(final Object dataFetcherResult) {
if (dataFetcherResult instanceof LocalDate) {
return formatter.format((LocalDate) dataFetcherResult);
} else {
throw new CoercingSerializeException("Expected a LocalDate object.");
}
}
@Override
public LocalDate parseValue(final Object input) {
try {
if (input instanceof String) {
return LocalDate.parse((String) input, formatter);
} else {
throw new CoercingParseValueException("Expected a String");
}
} catch (DateTimeParseException e) {
throw new CoercingParseValueException(String.format("Not a valid date: '%s'.", input), e
);
}
}
@Override
public LocalDate parseLiteral(final Object input) {
if (input instanceof StringValue) {
try {
return LocalDate.parse(((StringValue) input).getValue(), formatter);
} catch (DateTimeParseException e) {
throw new CoercingParseLiteralException(e);
}
} else {
throw new CoercingParseLiteralException("Expected a StringValue.");
}
}
}).build();
}
// https://docs.spring.io/spring-graphql/docs/1.1.0-RC1/reference/html/#execution-graphqlsource-runtimewiring-configurer
@Bean
RuntimeWiringConfigurer runtimeWiringConfigurer() {
GraphQLScalarType scalarType = dateScalar();
return wiringBuilder -> wiringBuilder.scalar(scalarType);
}
/*
// https://docs.spring.io/spring-graphql/docs/1.1.0-RC1/reference/html/#execution-graphqlsource
@Bean
public GraphQlSourceBuilderCustomizer sourceBuilderCustomizer() {
GraphQLScalarType scalarType = dateScalar();
return (builder) ->
builder.configureGraphQl(graphQlBuilder ->
graphQlBuilder.executionIdProvider((query, operationName, context) -> null));
}
*/
}
so runtimeWiringConfigurer
loads correctly, but LocalDate
doesn't work in my schema.graphqls
and I'm looking for help and solution with described issue.
LocalDate
.The issue can be resolved declaring correspond scalar type in graphqls
file scalar LocalDate
.
So schema.graphqls
looks like:
scalar LocalDate
type Query {
bookById(id: ID): Book
}
type Book {
id: ID
name: String
pageCount: Int
authors: [Author]!
productionDate: LocalDate
}
type Author {
id: ID
firstName: String
lastName: String
}
The fix is published to the git also.