How to implement Custom Scalar in Graphql-java? - graphql

I am new to graphql. I am trying to implement custom scalar type "Email". but am getting below error. Could you please help me?
by: com.coxautodev.graphql.tools.SchemaClassScannerError: Expected a
user-defined GraphQL scalar type with name 'Email' but found none! at
com.coxautodev.graphql.tools.SchemaClassScanner.validateAndCreateResult(SchemaClassScanner.kt:144)
~[graphql-java-tools-4.3.0.jar:na] at
com.coxautodev.graphql.tools.SchemaClassScanner.scanForClasses(SchemaClassScanner.kt:94)
~[graphql-java-tools-4.3.0.jar:na]
Configurations :
scalar Email
type Greeting {
id: ID!
message: String!
email:Email
}
type Query {
getGreeting(id: ID!): Greeting
}
type Mutation {
newGreeting(message: String!): Greeting!
}
Version info:
springBootVersion = '1.5.8.RELEASE'
com.graphql-java:graphql-java:6.0')
com.graphql-java:graphql-java-tools:4.3.0')
com.graphql-java:graphql-java-servlet:4.7.0')
org.springframework.boot:spring-boot-starter-web')
com.graphql-java:graphql-spring-boot-starter:3.10.0')
com.graphql-java:graphiql-spring-boot-starter:3.10.0')
Please help...

Try this:
#Component
public class ScalarEMail extends GraphQLScalarType {
public ScalarEMail() {
super("Email", "Scalar Email", new Coercing() {
#Override
public Object serialize(Object o) throws CoercingSerializeException {
return ((Email) o).getEmail();
}
#Override
public Object parseValue(Object o) throws CoercingParseValueException {
return serialize(o);
}
#Override
public Object parseLiteral(Object o) throws CoercingParseLiteralException {
return Email.valueOf(((StringValue) o).getValue());
}
});
}
}

Related

Spring, how do I store java.lang.Class type in mongodb

I'm trying to store java.lang.Class in MongoDb using ReactiveCrudRepository, but I got this following errors.
#Document
data class Letter(
...,
val messageType: Class<*>
)
Can't find a codec for class java.lang.Class.
I tried implementing my custom conversions, but it converts other properties that has type String to java.lang.Class too.
#Bean
fun customConversions(): MongoCustomConversions {
val converters = ArrayList<Converter<*, *>>()
converters.add(object: Converter<String, Class<*>> {
override fun convert(source: String): Class<*> {
return Class.forName(source)
}
})
converters.add(object: Converter<Class<*>, String> {
override fun convert(source: Class<*>): String {
return source.name
}
})
return MongoCustomConversions(converters)
}
You could try using Property Converters. See example bellow:
class ReversingValueConverter implements PropertyValueConverter<String, String, ValueConversionContext> {
#Override
public String read(String value, ValueConversionContext context) {
return reverse(value);
}
#Override
public String write(String value, ValueConversionContext context) {
return reverse(value);
}
}
class Person {
#ValueConverter(ReversingValueConverter.class)
String ssn;
}
See Spring Data MongoDB Reference Documentation for more information.

Invalid Syntax error while consuming graphql API

I am also facing some issue while hitting Graphql APIs through postman.
http://testEnvrironment/restcall/getReports
POST body
getReports(id:15){
isApproved
}
}
Entries of sample.graphqls file is
schema{
query: Query
}
type Query{
getReports(id: Long): PublishedReportInternal
}
type PublishedReportInternal{
sourceReport:ObjectRef
isApproved:Boolean
ignoreOutputFormatId:Boolean
}
type ObjectRef{
id : Long
qualifier : String
}
#Override
public ResponseEntity<Object> getReports(String query) {
ExecutionResult execute = graphQLService.getGraphQL().execute(query);
System.out.println("query::"+query);
System.out.println("execute result...."+execute);
return new ResponseEntity<>(execute, HttpStatus.OK);
}
#Service
public class CustomDataFetcher implements DataFetcher<PublishedReportInternal> {
#Inject
PublishRunReportInternalRestService service;
#Override
public PublishedReportInternal get(DataFetchingEnvironment environment) {
System.out.println("Entered into DataFetcher class...");
String reportId=environment.getArgument("id");
System.out.println("reportId is ::"+reportId);
if(!StringUtils.isEmpty(reportId)) {
return service.getReportById(new Long(reportId));
}
else {
return null;
}
}
}
Below is the implementation of GraphQLService
#Service
public class GraphQLService {
#Value("classpath:sample.graphqls")
private Resource schemaResource;
private GraphQL graphQL;
#Inject
private CustomDataFetcher customDataFetcher;
#PostConstruct
private void loadSchema() throws IOException {
// get the schema
File schemaFile = schemaResource.getFile();
System.out.println(schemaFile.getAbsolutePath());
// parse schema
TypeDefinitionRegistry typeRegistry = new SchemaParser().parse(schemaFile);
RuntimeWiring wiring = buildRuntimeWiring();
GraphQLSchema schema = new SchemaGenerator().makeExecutableSchema(typeRegistry, wiring);
graphQL = GraphQL.newGraphQL(schema).build();
}
private RuntimeWiring buildRuntimeWiring() {
return RuntimeWiring.newRuntimeWiring().type("Query", typeWiring -> typeWiring
.dataFetcher("getReports", customDataFetcher)).build();
}
public GraphQL getGraphQL() {
return graphQL;
}
}
Rest endpoint will be
#POST
#Path(value = "/getReports")
#Consumes
(value = MediaType.APPLICATION_JSON)
#Produces
(value = MediaType.APPLICATION_JSON) ResponseEntity<Object> getReports( String query);
Please try to help here as I am stuck completely with this problem.
Following jar has been used by me for this POC
compile files('libs/new/graphiql-spring-boot-starter-5.0.2.jar')
compile files('libs/new/graphql-java-9.2.jar')
compile files('libs/new/graphql-java-servlet-6.1.2.jar')
compile files('libs/new/graphql-java-tools-5.2.4.jar')
compile files('libs/new/graphql-spring-boot-autoconfigure-5.0.2.jar')
compile files('libs/new/graphql-spring-boot-starter-5.0.2.jar')
compile files('libs/new/java-dataloader-2.0.2.jar')
compile files('libs/new/antlr4-runtime-4.7.1.jar')
compile files('libs/new/reactive-streams-1.0.3.jar')
Above code snippet contains all the information which I have used to perform this POC, but while performing this POC I am consistently getting "Invalid Syntax" error. Please help in resolving this issue.
Regards
Kushagra

how to change value after controller in spring RESTful

I want change data after #RestController class in Spring
I need to change the fields data based on the specified language.
example:
enum:
public enum Gender {
WOMAN, MAN, OTHER
}
the controller:
#RequestMapping(value = "/get/{id}", method = RequestMethod.GET)
public User get(#PathVariable Long id) throws Exception {
log.debug("Entering get( id={} )", id);
User user = null;
try {
user = UserService.get(id);
} catch (Exception e) {
log.debug("Error occurred in get().", e);
throw e;
}
return user;
}
this output:
{
fisrtName: 'john',
lastName: 'doe',
gender: 'man'
}
change to this output:
{
fisrtName: 'john',
lastName: 'doe',
gender: 'homme'
}
I assume user.gender is a enum. Then you could add a custom Serializer and Deserializer to your JSON Mapper (hopefully Jackson).
#JsonComponent
public class TranslatedGenderJsonComponent {
public static class TranslatedGenderSerializer extends StdSerializer<Gender> {
public TranslatedGenderSerializer () {
super(Gender.class);
}
public void serialize(
Gender gender, JsonGenerator generator, SerializerProvider provider)
throws IOException, JsonProcessingException {
String translatedGender = myTranslateFunction(gender);
generator.writeString(translatedGender );
}
}
public static class TranslatedGenderDeserializer extends StdDeserializer<Gender> {
public TranslatedGenderDeserializer () {
super(Gender.class);
}
public Gender deserialize(JsonParser jp, DeserializationContext ctxt)
throws IOException, JsonProcessingException {
JsonToken currentToken = jp.getCurrentToken();
if (currentToken.equals(JsonToken.VALUE_STRING)) {
String text jp.getText().trim();
Gender gender = myInverseTranslateFunction(text);
return gender;
} else if (currentToken.equals(JsonToken.VALUE_NULL)) {
return getNullValue();
} else {
throw ctxt.mappingException(Gender.class);
}
}
}
}
This code is not tested, it is just written in the browser! (I am quite unsure with the deserializer/parser code.) But I hope it will guide you to a solution.
I changed code:
the controller:
#Autowired
GlobalMassengerAdvice globalMassenger;
#RequestMapping(value = "/get/{id}", method = RequestMethod.GET)
public User get(#PathVariable Long id) throws Exception {
log.debug("Entering get( id={} )", id);
User user = null;
try {
user = userService.get(id);
String value = globalMassenger.getMessage(user.getGender().name());
user.setGender( value );
} catch (Exception e) {
log.debug("Error occurred in get().", e);
throw e;
}
return user;
}
I add new Class (GlobalMassengerAdvice):
#ControllerAdvice
public class GlobalMassengerAdvice {
#Autowired
private MessageSource messageSource;
public String getMessage(final String messageKey, final Object... messageParameters) {
Locale locale = LocaleContextHolder.getLocale();
String result = null;
try {
result = messageSource.getMessage(messageKey, messageParameters, locale);
} catch (NoSuchMessageException e) {
result = messageKey;
}
return result;
}
}

HotChocolate GraphQL Configure not being called

I have a Query:
public class Query : ObjectType
{
protected override void Configure(IObjectTypeDescriptor<Query> descriptor)
{
Console.WriteLine("Hit Configure");
}
public IQueryable<DataStory> GetDataStories([Service]MicipContext context)
{
return context.DataStories;
}
}
And in Startup.cs:
public void ConfigureServices(IServiceCollection services)
{
services.AddGraphQL(sp =>
{
var schema = SchemaBuilder.New()
.AddDocumentFromString(this.ReadSchema())
.BindResolver<Query>(c => c.To<Query>())
.AddServices(sp)
.Create();
return schema;
}
}
And my schema graphql:
type Query {
dataStories: [DataStory!]!
}
type DataStory {
id: Int!
title: String!
}
When I call the query with:
query GetDataStories {
dataStories {
title
}
}
The resolver returns correctly but my configure method is never called. What am I doing wrong? Shouldn't Configure be called at some point?
Figured out that Hot Chocolate has not added support for pagination/sort/filter on schema first projects. We are doing schema first so we have to implement it ourselves.

Map Java Object

I want to create a service in order to populate dropdown from database. I tried this:
Merchant Class:
export class Merchant {
constructor(
public id: string,
public name: string,
public state_raw: string,
public users: string,
) {}
}
Merchant Service:
getList(): Observable<Merchant> {
return this.http.get<Merchant>(environment.api.urls.merchants.base, {});
}
Rest Api impl:
#GetMapping
public ResponseEntity<?> get() {
return merchantRepository
.findAll()
.map(mapper::toDTO)
.map(ResponseEntity::ok)
.orElseGet(() -> notFound().build());
}
SQL query:
#Override
public Iterable<Merchants> findAll() {
String hql = "select e from " + Merchants.class.getName() + " e";
TypedQuery<Merchants> query = entityManager.createQuery(hql, Merchants.class);
List<Merchants> merchants = query.getResultList();
return merchants;
}
But I get this error:
The method map(mapper::toDTO) is undefined for the type Iterable<Merchants>
How should I implement properly this mapping for the response?
Seems like you meant to stream the entities.
#GetMapping
public ResponseEntity<?> get() {
return StreamSupport.stream(merchantRepository.findAll().spliterator(), false)
.map(mapper::toDTO)
.map(ResponseEntity::ok)
.findFirst()
.orElseGet(() -> notFound().build());
}

Resources