Take result from one query / mutation and pipe to another - graphql

I'm wondering if there's a way in GraphiQL that will let me pipe the result from one query / mutation into another query / mutation. Here's an example where the login mutation is used to get a viewer and the viewer would be used to query the addresses for that user. Is this possible with GraphQL / GraphiQL.
mutation {
login(credentials: {
email: "me#me.com",
password: "password123",
passwordConfirmation: "password123"
}) {
viewer
}
}
query {
addresses(viewer:viewer) {
city
}
}

The purpose of the selection set in the mutations is to be able to fetch data that has changed as a result of the mutation. But it also makes it possible to fetch related data, as long as you can access is through the mutation result type.
Let's assume we have following types:
type Address {
city: String
}
type User {
addresses: [Address]
}
If the result (payload) type of the login mutation includes a field viewer of type User that refers to the successfully logged in user, you can query any field of the User in the result of the mutation:
mutation {
login(credentials: {
email: "me#me.com",
password: "password123",
passwordConfirmation: "password123"
}) {
viewer {
addresses {
city
}
}
}
}

Related

Cant Return Array in Graphql Query

I'm pretty new to graphql and I'm working on a project in nodejs where I am trying to return users when a getUsers query is performed. The issue is that when I test this query in graphql studio, I'm getting an error stating: "GraphQLError: Cannot query field \"users\" on type \"User\". I'm really confused as to why I'm having this issue. I've seen a number of examples where people where able to return just an array and didn't have a problem, but every time I've tried this I end up getting a similar error. Due to this, I've only been able to return a value for a query or mutation when I am super specific such as for my user query:
...
const user = await requireAuth(user)
return {
_id: user._id,
username: user.username,
firstName: user.firstName,
email: user.email,
}
Does anyone know why this is happening? I would really appreciate any help or advice. Thank you!
Query getUsers in graphql,
{
getUsers {
users
}
}
Query in user-resolvers.js
getUsers: async(parent, args, context, info) => {
try {
let users = await User.find()
console.log(users)
// console.log(users) shows all of the users in the format found in type Users
return users;
}
catch (error) {
throw error;
}
},
schema.js
export default`
type Users {
_id: ID!
username: String
email: String!
firstName: String
lastName: String
basicInfo: [BasicInfo]!
avatar: String
date: Date
}
type BasicInfo {
birth_date: String!
age: Int!
feet: Int!
inches: Int!
}
...
type Query {
getUsers: [Users]
}
...
schema {
query: Query
mutation: Mutation
}
`;
index.js
import UserResolvers from './user-resolvers.js';
import User from '../../models/User.js';
export default {
Query: {
user: UserResolvers.user,
getUsers: UserResolvers.getUsers,
},
...
};
In the query you specify the fields you want to return and you don't have a field users, you must only specify fields that exist in your schema:
{
getUsers {
id
username
email
...
}
}
More info here

GraphQL mutation takes an array as an input parameter and returns a json String

I'm trying to implement mutation query with an array as a parameter and String as a return type.
Here is my schema file:
input OrganizationInput {
orgId: String!
orgName: String!
}
type Mutations {
importOrganizations(input: [OrganizationInput]): String
}
Here is my mutation:
mutation importOrganizations($orgs: [OrganizationInput]) {
importOrganizations(
input: {
orgId: id,
orgName: name
}
)
}
This code doesn't work, but I don't know how to do it properly.
Maybe someone more experienced in GraphQL could help me?
Do you have any errors that can help?
Anyways your mutation need to return fields, e.g.:
mutation importOrganizations($orgs: [OrganizationInput]) {
importOrganizations(
input: {
orgId: id,
orgName: name
})
{
id
name
}
}

Pass deep prop to shallow input

If I have a query user and it takes uuid but my variables are deep user.uuid can I pass uuid to the user query?
query User($user.uuid: string) {
user (uuid:$user.uuid) {
createdAt
}
}
Query Variables:
{
"user":{
"uuid": "abc"
}
}
No, the current GraphQL spec does not support referencing properties of a variable if that variable is an object. You may pass in object variables, but they may only be used where an input object is expected, for example, given a schema like:
type Mutation {
createUser(input: UserInput!): User!
}
input UserInput {
email: String!
}
we can do
mutation ($input: UserInput!) {
createUser(input: $input) {
email
}
}
However, if the expected input is a scalar:
type Mutation {
createUser(email: String!): User!
}
we must provide the scalar as a separate variable:
mutation ($email: String!) {
createUser(email: $email) {
email
}
}

Enumerating all fields from a GraphQL query

Given a GraphQL schema and resolvers for Apollo Server, and a GraphQL query, is there a way to create a collection of all requested fields (in an Object or a Map) in the resolver function?
For a simple query, it's easy to recreate this collection from the info argument of the resolver.
Given a schema:
type User {
id: Int!
username: String!
roles: [Role!]!
}
type Role {
id: Int!
name: String!
description: String
}
schema {
query: Query
}
type Query {
getUser(id: Int!): User!
}
and a resolver:
Query: {
getUser: (root, args, context, info) => {
console.log(infoParser(info))
return db.Users.findOne({ id: args.id })
}
}
with a simple recursive infoParser function like this:
function infoParser (info) {
const fields = {}
info.fieldNodes.forEach(node => {
parseSelectionSet(node.selectionSet.selections, fields)
})
return fields
}
function parseSelectionSet (selections, fields) {
selections.forEach(selection => {
const name = selection.name.value
fields[name] = selection.selectionSet
? parseSelectionSet(selection.selectionSet.selections, {})
: true
})
return fields
}
The following query results in this log:
{
getUser(id: 1) {
id
username
roles {
name
}
}
}
=> { id: true, username: true, roles: { name: true } }
Things get pretty ugly pretty soon, for example when you use fragments in the query:
fragment UserInfo on User {
id
username
roles {
name
}
}
{
getUser(id: 1) {
...UserInfo
username
roles {
description
}
}
}
GraphQL engine correctly ignores duplicates, (deeply) merges etc. queried fields on execution, but it is not reflected in the info argument. When you add unions and inline fragments it just gets hairier.
Is there a way to construct a collection of all fields requested in a query, taking in account advanced querying capabilities of GraphQL?
Info about the info argument can be found on the Apollo docs site and in the graphql-js Github repo.
I know it has been a while but in case anyone ends up here, there is an npm package called graphql-list-fields by Jake Pusareti that does this. It handles fragments and skip and include directives.
you can also check the code here.

Can an Apollo Mutation return a custom result object?

The result returned from an Apollo mutation is typically a type or a subset of fields from a type, and this is usually great. So my mutation:
const addUserMutation = gql`
mutation createUser($email: String!, $permissions: [CreatePermissionInput]) {
createUser(input: {email: $email, permissions: $permissions}) {
id
created
lastUpdated
uid
email
permissions {
who
...
}
}
}
`
Which is calling:
extend type Mutation {
createUser(input: CreateUserInput!): User
}
Will return the user with the fields listed.
Problem is, I want to know if the user that we just tried to create already existed or not. So how can I edit the response to include this flag? Can you have a mutation return, say, an object like:
{
exists: true,
user: { ... }
}
So I can do this:
this.props.submit({
variables: {
email,
permissions,
},
}).then(({ result }) => {
console.log(result)
// > { exists: true, user: [USER OBJECT] }
})
I get that this will break the auto cache update but sometimes you need the response from an update to tell you more.
Create an additional type for the return result of mutation
type UserPayLoad {
exists:Boolean
user:User
}
extend type Mutation {
createUser(input: CreateUserInput!): UserPayLoad
}
Just try this. This may help you

Resources