Graphql API mutation endpoint - incoming query data is shown empty always - graphql

#Mutation((returns) => StyleOperationHead)
async saveStyleOperationHead(
#Args('styleOperationHeadData')
styleOperationHeadData: StyleOperationHeadInputDto,
): Promise<StyleOperationHead> {
console.log(styleOperationHeadData)
return {
operationId: 1,
style: 'HSF222005A',
color: 'RED',
structureType: 1,
baseTemplateId: 1,
numberOfJobGroups: 3,
totalSmv: 54,
};
}
I have the above mutation written in a resolver class in my graphql project.
I use the below query to call the above endpoint
# Write your query or mutation here
mutation {
saveStyleOperationHead(styleOperationHeadData: {
style: "HSF222005A"
color: "RED"
structureType: 1
baseTemplateId: 1
numberOfJobGroups: 3
totalSmv: 54
}
) {
operationId
style
color
structureType
baseTemplateId
numberOfJobGroups
totalSmv
}
}
Issue here is fields in the incoming request(query) always is empty.
In the console log I have put I get this empty output-> StyleOperationHeadInputDto {}
I have checked my models and dtos , there are no discrepancies there wrt the request.
Can anyone tell me what I am doing wrong here ?

Related

Graphql: How can I solve the N + N problem?

After having implemented dataloader in the respective resolvers to solve the N+1 problem, I also need to be able to solve the N+N problem.
I need a decently efficient data loading mechanism to get a relation like this:
{
persons (active: true) {
id,
given_name,
projects (active: true) {
id,
title,
}
}
}
I've created a naive implementation for this, returning
{
persons: [
{
id: 1,
given_name: 'Mike'
projects: [
{
id: 1,
title: 'API'
},
{
id: 2,
title: 'Frontend'
}
]
}
{
id: 2,
given_name: 'Eddie'
projects: [
{
id: 2,
title: 'Frontend'
},
{
id: 3,
title: 'Testing'
}
]
}
]
}
In SQL the underlying structure would be represented by a many many to many relationship.
Is there a similiar tool like dataloader for solving this or can this maybe even be solved with dataloader itself?
The expectation with GraphQL is that the trip to the database is generally the fastest thing you can do, so you just add a resolver to Person.projects that makes a call to the database. You can still use dataLoaders for that.
const resolvers = {
Query: {
persons(parent, args, context) {
// 1st call to database
return someUsersService.list()
},
},
Person: {
projects(parent, args, context) {
// this should be a dataLoader behind the scenes.
// Makes second call to database
return projectsService.loadByUserId(parent.id)
}
}
}
Just remember that now your dataLoader is expecting to return an Array of objects in each slot instead of a single object.

Graphql type resolver by id

I'm trying to get familiar with Graphql by building a server with the following schema:
type Game
{
id: ID!
players: [Player!]!
winner: Player
...
}
type Player {
id: ID!
game: Game!
...
}
type Query {
getGame(id: ID!): Game
getPlayer(id: ID!): Player
}
And map to the following data:
const games = {
1: {
id: 1,
players: [2, 3],
winner: undefined
}
};
const players = {
2: {
id: 2,
game: 1
},
3: {
id: 3,
game: 1
},
};
While writing the resolvers, I noticed a lot of boilerplate code - I had to write conceptually the same field resolver for every object member which holds a foreign key.
const typedefs = {
Query: {
getGame: (_, {id}) => games[id],
getPlayer: (_, {id}) => players[id]
},
Game: {
winner: (game) => players[game.winner],
players: (game) => game.players.map(id => players[id])
},
Player: {
game: (player) => games[player.id]
}
}
Is there a way to create a type resolver by ID?
for example, a Player field or query would always be resolved by (id) => players[id],
and a game field or query would always be resolved by (id) => games[id].
I saw that this is achievable using AWS-Amplify's #model directive, but I'm wondering if there is a more standard way I'm missing rather than implementing my own directive.
Is this a feature of any current Graphql implementation? I couldn't find anything that resembles it in apollo-graphql's documentation (or in graphql-js's).
Thanks.
There is no way of changing the default resolver. Apollo-GraphQL just passes the resolver map to graphql-tools and graphql-tools uses graphql-js. graphql-js implements the default resolver here and uses it here.
Maybe you could try using ES2015 Proxy to provide a default implementation for resolvers in the object instead. But even if you override your default resolver, you break all the places where you used the actual default resolver.

Updating Apollo Cache Without Variables

Originally, I make a GraphQL call as follows:
query getItems($filter_ids: [Int!], $filter: item_records_bool_exp) {
items(order_by: { negative: asc, parent: asc }, where: { level: { _in: [2, 3] } }) {
i18n {
value
}
id
parent
negative
}
filters(where: { category: { _eq: "PLAN" } }) {
id
value
}
}
Now, when I insert a new item, I update the cache using update function in the mutation options, and I'm supposed to use readQuery/readFragment and writeQuery/writeFragment to interact with the Apollo Cache as described here.
My question is, my readQuery calls always fail if I do not provide the exact same variables that I had previous provided to the original GraphQL query. Is there a way around this? In other words, can I just read objects from the cache by their ID irrespective of the original query that was used to fetch these objects?

Apollo Server Stitching - Get parent of parent in resolver

I have a questions based on https://www.apollographql.com/docs/graphql-tools/schema-stitching/
Let's say I have the following schemas (Note that it's built for an example, it makes no sense to have it structured this way)
//First schema
type User {
id
cars: [Car]!
}
type Car {
id
name: String
model: String
}
//Second schema
type Color {
id
name: String
rgb: String
opacity: Int
}
//Defined in Apollo Server
extend type Car {
color: Color
}
And the following resolver for
resolvers: {
Car: {
color: {
fragment: '... on Car { id }',
resolve(parent, args, context, info) {
return delegateToSchema({
schema: secondSchema,
operation: 'query',
fieldName: 'colorByUserAndCarId',
args: {
id: parent.id,
userId: ?
},
context,
info,
});
},
},
},
}
How can I get the userId, which is on type User and not Car?
While I was searching for an answer to this, I thought of some solutions, but I can't figure out how to make any of them work..
Make the type Color part of Car, so I would have every color's field in car directly, so I guess I would have the resolver based on User instead.. ?
Changing the fragment for '... on User', while being on type Car, but so far that doesn't work.
Adding the userId to the type Car by extending it, but I can't find how to get the userId anyway
Changing the schema and types from the root is not an option, all modifications need to be made within Apollo Server.
Writing the question and potential solutions helped me understanding better how it works and how this could be achieved.
I can add a resolver for "car" the same way I did for "color" and by the time I get in my car resolver, the object value for "car" is already there.. the parent value would look like { id: x, car: {...}}, id being the userId, so I can just do this in my car resolver
let myCar = parent.car;
myCar.userId = parent.id;
return myCar;
When I'll be in my color resolver, I'll be able to do parent.userId.

graphql - Refer to other fields in mutation

I want to create 2 related objects, e.g. 1 Location and 1 Place where Place has a reference to Location like so:
type Location {
id: String
name: String
}
type Place {
id: String
locationId: String
}
Is it possible to do this with 1 mutation request? Currently I'm doing this with 2 separate mutation requests like below:
mutation ($locationName: String!) {
insert_Location(objects: {name: $locationName}) {
returning {
id
}
}
}
//in another request, use the id returned from the request above
mutation ($locationId: String!) {
insert_Place(objects: {locationId: $locationId}) {
returning {
id
}
}
}
I'm aware it's possible to have multiple fields in a mutation so I could create 2 Locations in 1 mutation request like below.
mutation ($locationName: String!) {
location1: insert_Location(objects: {name: $locationName}) {
returning {
id
}
}
location2: insert_Location(objects: {name: $locationName}) {
returning {
id
}
}
}
However if I wanted to do this to create 1 Location and 1 Place, is there a way to retrieve the created Location Id and pass it to the 2nd field to create the Place?
For future reference:
As #Xetera pointed out, because the 2 types have a foreign key relationship you can do a nested insert mutation where hasura would handle setting the foreign key value. In my case it would look something like:
mutation ($locationName: String!) {
insert_Place(
objects: {
Location: {data: {name: $locationName}}, //hasura will create Location and assign the id to Place.locationId
}
) {
returning {
id
}
}
}
Docs here for further reading: https://hasura.io/docs/1.0/graphql/manual/mutations/insert.html#insert-an-object-along-with-its-related-objects-through-relationships

Resources