How to handle List<Map<String, Object>> return type from query resolver in .graphqls - spring-boot

I have a graphql implementation, below is my .graphqls file
schema {
query: Query
}
type Product {
id: Int!
name: String!
description: String!
productTypes: [ProductType]!
}
type City {
id: Int!
name: String!
}
type ProductType {
id: Int!
type: String!
product: Int
}
type Query {
products: [Product]!
cities: [City]!
productTypes: [ProductType]!
}
This is my query resolver code
public class Query implements GraphQLQueryResolver {
#Autowired
ProductRespository productRespository;
#Autowired
EntityManager em;
#Autowired
CityRepository cityRepository;
#Autowired
ProductTypeRepository productTypeRepository;
public List<Map<String, Object>> products() {
javax.persistence.Query q = em.createQuery("select new
map(p.name as productName, p.id as productId) from Product p");
List<Map<String, Object>> list = q.getResultList();
return list;
}
public Iterable<City> cities() {
return cityRepository.findAll();
}
}
when I am running the application I am getting below error
Type java.util.Map cannot be
mapped to a GraphQL type! Since GraphQL-Java deals with erased types at
runtime, only non-parameterized classes can represent a GraphQL type.
This allows for reverse-lookup by java class in interfaces and union
types
So how I can handle this kind of return type in Query Section of .graphqls
Thanks in Advance

Related

How to map nested object query in Spring graphql

Using org.springframework.boot:spring-boot-starter-graphql and WebMvc, I would like to handle, in the #Controller, nested fields.
Schema:
type Movie {
name: String
actor: Actor
}
type Actor {
name: String
homeAddress: Address
officeAddress: Address
}
type Address {
street: String
city: String
}
query:
query {
movie(name: "xyz") {
name
actor {
name
homeAddress {
street
city
}
}
}
}
The #Controller handles the first field with:
#QueryMapping
public Movie movie(#Argument name) {...}
2nd with schemaMapping:
#SchemaMapping(type=“Movie”, field=“actor”)
public Actor actor(Movie movie) {...}
But how to handle the third level field (address)?
#SchemaMapping(typeName=“Actor”, field=“homeAddress”)
public Address homeAddress(Actor actor) {...}
this doesn't work

How to implement query filters and sorting using Graphql SPQR?

How to implement query filters and sorting using Graphql SPQR?
I'm looking for a solution with Graphql SPQR for schema which looks something like this.
schema {
query: Query
mutation: Mutation
}
enumSortOrder {
ASC
DESC
}
type Article {
id: String
name: String
createdByUserId: String
createdOn: String
lastUpdatedOn: String
}
type Feedback {
id: String
feedbackText: String
articleId: String
createdByUserId: String
createdOn: String
lastUpdatedOn: String
}
type Query {
getAllArticles(pageNumber: Int!, pageSize : Int!, sortOrder: SortOrder!, sortBy: String!): [Article]
getFeedBacksForArticle(articleId: String!): [Feedback]
}
type Mutation {
createArticle(name: String!, createdByUserId: String!): Article
createNewFeedback(feedbackText: String!, articleId: String!, createdByUserId: String!): Feedback
}
GraphQL SPQR relies on a code-first approach. You need to create your java classes and resolver and annotate them properly:
public enum SortOrder {
#GraphQLEnumValue(name = "ASC") ASC,
#GraphQLEnumValue(name = "DESC") DESC
}
public class Article {
//Article implementation here
}
public class Feedback {
//Feedback implementation here
}
public class GraphQLResolver {
#GraphQLQuery(name = "getAllArticles", description = "Search articles")
public List<Article> getAllArticles(
#NotNull #GraphQLArgument(name = "pageNumber") int pageNumber,
#NotNull #GraphQLArgument(name = "pageSize") int pageSize,
#NotNull #GraphQLArgument(name = "sortOrder") SortOrder sortOrder,
#NotNull #GraphQLArgument(name = "sortBy") String sortBy) {
//Query implementation here
}
//implement other queries and mutation
}
Follow the readme at https://github.com/leangen/graphql-spqr to expose your graphql resolver.

How to use another variable name or How to flatten entity in JPA Projection for nested object

I'm making an api for querying nested entity with Spring Data JPA Projection.
My Code
The Entity:
#Entity
class User {
#Id
var userId: String
var name: String
var age: Int
#OneToOne
#JoinColumn(name = "userId")
var address: Address
}
#Entity
class Address {
var userId: String
var street: String
var city: String
var country: String
}
The Repository:
interface UserView {
val name: String
val address: AddressView
interface AddressView {
val city: String
val country: String
}
}
#Repository
interface UserRepository : JPARepository<User, String> {
fun findAll(): List<UserView>
}
Expected Response
{
"name": "example",
"city": "example-city",
"country": "example-country"
}
My code produces
{
"name": "example",
"address": {
"city": "example-city",
"country": "example-country"
}
}
I Tried
I tried another view to flatten object:
interface UserView {
val name: String
val addressCity: String
val addressCountry: String
}
But this case, the variable naming is too complicate.
I want to solve this problem with projection. How can I solve this problem?
In JPA, you can do this using #NamedNativeQuery only:
#NamedNativeQuery(
name = "getUser",
query = "SELECT u.name, a.city, a.country FROM User u and Address a where a.userId = u.id ", resultClass=UserView .class)
#Entity
class User {
...
}
For Reference hibernate-named-query
Try this:
data class UserView(name: String, city: String, country: String)
#Repository
interface UserRepository : JPARepository<User, String> {
#Query(value = "select new your.pkg.UserView(u.name, u.address.city, u.address.country) from User u")
fun findAllFlat(): List<UserView>
}
You can use #Value and combine more fields or even access the fields of objects.
From the spring-data-rest documentation:
You can create a projection that combines the two data fields in the preceding example together, as follows:
#Projection(name = "virtual", types = { Person.class })
public interface VirtualProjection {
#Value("#{target.firstName} #{target.lastName}")
String getFullName();
}
Spring’s #Value annotation lets you plug in a SpEL expression that takes the target object and splices together its firstName and lastName attributes to render a read-only fullName.
Flattening also works for me:
#Value("#{target.document.title}")
String getDocumentTitle();

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());
}

How to implement Custom Scalar in Graphql-java?

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());
}
});
}
}

Resources