How to expose graphql field with different name - graphql

I am exploring GraphQL and would like to know if there is any way of renaming the response field for example i have a POJO with these field
class POJO {
Long id;
String name;
}
GraphQL query:
type POJO {
id: Long
name: String
}
My response is something like this
{
"POJO" {
"id": 123,
"name": "abc"
}
}
Can i rename the name field to something like userName so that my response is below
{
"POJO" {
"id": 123,
"userName": "abc"
}
}

You can use GraphQL Aliases to modify individual keys in the JSON response.
If this is your original query
query {
POJO {
id
name
}
}
you can introduce a GraphQL alias userName for the field name like so:
query {
POJO {
id
userName: name
}
}
You can also use GraphQL aliases to use the same query or mutation field multiple times in the same GraphQL operation. This get's especially interesting when using field parameters:
query {
first: POJO(first: 1) {
id
name
}
second: POJO(first: 1, skip: 1) {
id
name
}
}

The question is: how are you creating the schema in the first place? There's no intrinsic connection between Java and GraphQL types - they are completely unrelated unless you correlate them. So you can name the fields any way you want in the schema, and make a resolver (DataFetcher) that gets the value from anywhere (thus any POJO field too).
If you're using a tool to generate the schema from Java types (graphql-java-annotations, graphql-spqr etc), then use that tool's facilities to drive the mapping. Both the mentioned tools allow customizing the mapping via annotations. GraphQL-SPQR enables the same via external configuration as well.
If you clarify your question further, I'll be able to give a more precise answer.

Looks like GraphQLName annotation can help.
Example from documentation :
"Additionally, #GraphQLName can be used to override field name. You can use #GraphQLDescription to set a description."
These can also be used for field parameters:
public String field(#GraphQLName("val") String value) {
return value;
}

I know this question is very old but following code is used for renaming the field:
public class ProductReviewType: ObjectGraphType<ProductReview>
{
public ProductReviewType()
{
Field(x => x.ProductReviewId, type: typeof(IdGraphType)).Description("some desc here");
Field(x => x.ProductId).Description("some desc here");
Field("reviewername", x => x.ReviewerName).Description("some desc here");
Field("reviewdate",x => x.ReviewDate).Description("some desc here");
Field("emailaddress", x => x.EmailAddress).Description("some desc here");
Field("rating", x => x.Rating).Description("some desc here");
Field("comments",x => x.Comments).Description("some desc here");
Field("modifieddate", x => x.ModifiedDate).Description("some desc here");
}
}
In the above code, modifieddate would be the field name for property "ModifiedDate".

Related

How to pass object type argument in query in GraphQL?

I got this type of query
query {
searchRandom (param : MyObjectClass){
city
}
}
How may I set param with the type of MyObjectClass and pass it in the query? To be able to test here?
Use the following query.
query getData($param: MyObjectClass){
searchRandom(param: $param)
city
}
And then go to query variables tab in Graphiql and pass the variable data like this. You have not mention the data types included in MyObjectClass. So use this as an example:
{
"param": {"country": "England", "population": "High" }
}
Then the data should be returned as expected.
--- Additionally ---
If you are running the server, make sure you have set the followings.
You need to create a input object in the GraphQL schema.
input MyObjectClass {
country: String
population: String
}
Then in the resolver you have to pass the object as the argument. (Assuming you are using JavaScript)
const resolvers = {
Query: {
searchRandom: (parent, { param }) => {
var query_data = param
...//your code
return city_name;
},
},
I am not sure whether this addresses your question or not. I hope this answer helps though.

Nested field resolvers in GraphQL

The goal is to use NestJS to implement a GraphQL schema using the code-first approach.
Let's say I have a Pet type in my GraphQL schema with two fields, name and age. If those two pieces of information come from different sources of truth (and I don't always want to fetch both), I could implement a PetResolver class with resolvers for each field:
#Resolver(() => Pet)
export class PetResolver {
#Query(() => Pet)
pet(): Pet {
return {};
}
#ResolveField()
name(): Promise<string> {
return Promise.resolve('Spot');
}
#ResolveField(() => Int)
age(): Promise<number> {
return Promise.resolve(2);
}
}
which could be used like this:
query GetPet {
pet {
name
}
}
This works and would ensure that the value of each field is only fetched when requested, but what if I wanted to have a pet field on my User type that I could query like this:
query GetUserWithPet {
currentUser {
email
pet {
name
}
}
}
Applying the same principle, I could create a UserResolver class like this:
#Resolver(() => User)
export class UserResolver {
#Query(() => User)
#UseGuards(AuthCognitoGuard)
currentUser(#CurrentUser() user: IdTokenPayload): User {
return {
id: user.sub,
email: user.email,
};
}
#ResolveField()
pet(#Parent() user: User): Promise<Pet> {
return petService.getPetForUserId(user.id);
}
}
but then the PetService implementation would have to be aware of which fields were requested if it only wanted to fetch relevant data.
A) Is there a way to use PetResolver within UserResolver to make use of the individual field resolution logic?
B) If not, what is the best way to determine which fields were requested in the query using NestJS code-first conventions?
C) Is this the "wrong" way to think about GraphQL queries? Do best practices dictate that I keep the separate resolver and use a query like this:
query GetUserWithPet {
currentUser {
email
}
pet {
name
}
}
User should contain some petIds [array] value (internal, DB stored field/column) ...
... making possible to resolve pets: [Pet] prop/relation - list of Pet ...
... like starshipIDs explained in https://graphql.org/learn/execution/
Notice: pets service is asked about records using pet ids.
... but of course pet can contain some ownerId (only or explicitely visible, DB stored field/column) making possible to resolve owner: User prop [reverse] relation - this way you can:
query PetWithOwner {
pet (id: "someID") {
id
name
owner {
id
email
# more pets?
pets {
id
name
# you can loop it ;)
owner {
id
email
pet.owner field resolver can return only { id: ownerId } object (partial response) ... server will try to resolve 'missing' (required by query) email prop using User (owner is User type) type resolver, passing id as an arg (check/console.log parent and args resolver args). You don't have to do it [the same] 'manually' inside pet.owner field resolver.
Query required fields ...
... [selection set] can be read from info object - 4th resolver arg - read docs/tutorial for details

Get complete GraphQL response using POST without specify field name in request [duplicate]

Assume you have a GraphQL type and it includes many fields.
How to query all the fields without writing down a long query that includes the names of all the fields?
For example, If I have these fields :
public function fields()
{
return [
'id' => [
'type' => Type::nonNull(Type::string()),
'description' => 'The id of the user'
],
'username' => [
'type' => Type::string(),
'description' => 'The email of user'
],
'count' => [
'type' => Type::int(),
'description' => 'login count for the user'
]
];
}
To query all the fields usually the query is something like this:
FetchUsers{users(id:"2"){id,username,count}}
But I want a way to have the same results without writing all the fields, something like this:
FetchUsers{users(id:"2"){*}}
//or
FetchUsers{users(id:"2")}
Is there a way to do this in GraphQL ??
I'm using Folkloreatelier/laravel-graphql library.
Unfortunately what you'd like to do is not possible. GraphQL requires you to be explicit about specifying which fields you would like returned from your query.
Yes, you can do this using introspection. Make a GraphQL query like (for type UserType)
{
__type(name:"UserType") {
fields {
name
description
}
}
}
and you'll get a response like (actual field names will depend on your actual schema/type definition)
{
"data": {
"__type": {
"fields": [
{
"name": "id",
"description": ""
},
{
"name": "username",
"description": "Required. 150 characters or fewer. Letters, digits, and #/./+/-/_ only."
},
{
"name": "firstName",
"description": ""
},
{
"name": "lastName",
"description": ""
},
{
"name": "email",
"description": ""
},
( etc. etc. ...)
]
}
}
}
You can then read this list of fields in your client and dynamically build a second GraphQL query to get the values of these fields.
This relies on you knowing the name of the type that you want to get the fields for -- if you don't know the type, you could get all the types and fields together using introspection like
{
__schema {
types {
name
fields {
name
description
}
}
}
}
NOTE: This is the over-the-wire GraphQL data -- you're on your own to figure out how to read and write with your actual client. Your GraphQL javascript library may already employ introspection in some capacity. For example, the apollo codegen command uses introspection to generate types.
2022 Update
Since this answer was originally written, it is now a recommended security practice to TURN OFF introspection in production. Reference: Why you should disable GraphQL introspection in production.
For an environment where introspection is off in production, you could use it in development as a way to assist in creating a static query that was used in production; you wouldn't actually be able to create a query dynamically in production.
I guess the only way to do this is by utilizing reusable fragments:
fragment UserFragment on Users {
id
username
count
}
FetchUsers {
users(id: "2") {
...UserFragment
}
}
I faced this same issue when I needed to load location data that I had serialized into the database from the google places API. Generally I would want the whole thing so it works with maps but I didn't want to have to specify all of the fields every time.
I was working in Ruby so I can't give you the PHP implementation but the principle should be the same.
I defined a custom scalar type called JSON which just returns a literal JSON object.
The ruby implementation was like so (using graphql-ruby)
module Graph
module Types
JsonType = GraphQL::ScalarType.define do
name "JSON"
coerce_input -> (x) { x }
coerce_result -> (x) { x }
end
end
end
Then I used it for our objects like so
field :location, Types::JsonType
I would use this very sparingly though, using it only where you know you always need the whole JSON object (as I did in my case). Otherwise it is defeating the object of GraphQL more generally speaking.
GraphQL query format was designed in order to allow:
Both query and result shape be exactly the same.
The server knows exactly the requested fields, thus the client downloads only essential data.
However, according to GraphQL documentation, you may create fragments in order to make selection sets more reusable:
# Only most used selection properties
fragment UserDetails on User {
id,
username
}
Then you could query all user details by:
FetchUsers {
users() {
...UserDetails
}
}
You can also add additional fields alongside your fragment:
FetchUserById($id: ID!) {
users(id: $id) {
...UserDetails
count
}
}
Package graphql-type-json supports custom-scalars type JSON.
Use it can show all the field of your json objects.
Here is the link of the example in ApolloGraphql Server.
https://www.apollographql.com/docs/apollo-server/schema/scalars-enums/#custom-scalars

Do a full query simply in GraphQL [duplicate]

Assume you have a GraphQL type and it includes many fields.
How to query all the fields without writing down a long query that includes the names of all the fields?
For example, If I have these fields :
public function fields()
{
return [
'id' => [
'type' => Type::nonNull(Type::string()),
'description' => 'The id of the user'
],
'username' => [
'type' => Type::string(),
'description' => 'The email of user'
],
'count' => [
'type' => Type::int(),
'description' => 'login count for the user'
]
];
}
To query all the fields usually the query is something like this:
FetchUsers{users(id:"2"){id,username,count}}
But I want a way to have the same results without writing all the fields, something like this:
FetchUsers{users(id:"2"){*}}
//or
FetchUsers{users(id:"2")}
Is there a way to do this in GraphQL ??
I'm using Folkloreatelier/laravel-graphql library.
Unfortunately what you'd like to do is not possible. GraphQL requires you to be explicit about specifying which fields you would like returned from your query.
Yes, you can do this using introspection. Make a GraphQL query like (for type UserType)
{
__type(name:"UserType") {
fields {
name
description
}
}
}
and you'll get a response like (actual field names will depend on your actual schema/type definition)
{
"data": {
"__type": {
"fields": [
{
"name": "id",
"description": ""
},
{
"name": "username",
"description": "Required. 150 characters or fewer. Letters, digits, and #/./+/-/_ only."
},
{
"name": "firstName",
"description": ""
},
{
"name": "lastName",
"description": ""
},
{
"name": "email",
"description": ""
},
( etc. etc. ...)
]
}
}
}
You can then read this list of fields in your client and dynamically build a second GraphQL query to get the values of these fields.
This relies on you knowing the name of the type that you want to get the fields for -- if you don't know the type, you could get all the types and fields together using introspection like
{
__schema {
types {
name
fields {
name
description
}
}
}
}
NOTE: This is the over-the-wire GraphQL data -- you're on your own to figure out how to read and write with your actual client. Your GraphQL javascript library may already employ introspection in some capacity. For example, the apollo codegen command uses introspection to generate types.
2022 Update
Since this answer was originally written, it is now a recommended security practice to TURN OFF introspection in production. Reference: Why you should disable GraphQL introspection in production.
For an environment where introspection is off in production, you could use it in development as a way to assist in creating a static query that was used in production; you wouldn't actually be able to create a query dynamically in production.
I guess the only way to do this is by utilizing reusable fragments:
fragment UserFragment on Users {
id
username
count
}
FetchUsers {
users(id: "2") {
...UserFragment
}
}
I faced this same issue when I needed to load location data that I had serialized into the database from the google places API. Generally I would want the whole thing so it works with maps but I didn't want to have to specify all of the fields every time.
I was working in Ruby so I can't give you the PHP implementation but the principle should be the same.
I defined a custom scalar type called JSON which just returns a literal JSON object.
The ruby implementation was like so (using graphql-ruby)
module Graph
module Types
JsonType = GraphQL::ScalarType.define do
name "JSON"
coerce_input -> (x) { x }
coerce_result -> (x) { x }
end
end
end
Then I used it for our objects like so
field :location, Types::JsonType
I would use this very sparingly though, using it only where you know you always need the whole JSON object (as I did in my case). Otherwise it is defeating the object of GraphQL more generally speaking.
GraphQL query format was designed in order to allow:
Both query and result shape be exactly the same.
The server knows exactly the requested fields, thus the client downloads only essential data.
However, according to GraphQL documentation, you may create fragments in order to make selection sets more reusable:
# Only most used selection properties
fragment UserDetails on User {
id,
username
}
Then you could query all user details by:
FetchUsers {
users() {
...UserDetails
}
}
You can also add additional fields alongside your fragment:
FetchUserById($id: ID!) {
users(id: $id) {
...UserDetails
count
}
}
Package graphql-type-json supports custom-scalars type JSON.
Use it can show all the field of your json objects.
Here is the link of the example in ApolloGraphql Server.
https://www.apollographql.com/docs/apollo-server/schema/scalars-enums/#custom-scalars

Graphql object ( or JSON) as filter argument

Is it possible to have a JSON object as filed in filter arguments. Something like:
Query{
building(location:{lon,lat}){
name,...
}
}
I need to pass location, and I would like to pass it as js object ( to apollo client) or as stringified JSON.
You can use input types to achieve that. You need to edit your schema
type Query {
building(location: Location): Building
}
input Location {
lon: String
lat: String
}
Then you can post your query like this
query {
building(location: {lon:"100.332680",lat:"5.416393"}) {
name,...
}
}

Resources