#StackBounty: #graphql #typeorm #typegraphql Typegraphql+TypeORM: save / update an array of entities

Bounty: 50

I have a graphql server and a role table, and I would like to save multiple roles within one mutation.

I searched a lot but found nothing.

How can I do something like:

mutation {
  addRoles (roles: [
    {
      name: "role1",
      description: "role 1"
    },
    {
      name: "role2",
      description: "role 2"
    },
    ...
  ])
}

In other words, how to implement addRoles and updateRoles resolver?

Is a for loop the only option? Is it possible to save all roles in one DB call?

The role model:

@Entity("role")
@ObjectType()
export class Role extends BaseEntity {
  @Field((type) => Number)
  @PrimaryGeneratedColumn()
  readonly id!: number;

  @Field()
  @Column({ length: 64 })
  name!: string;

  @Field({ nullable: true })
  @Column({ length: 512, nullable: true })
  description!: string;
}

And add and update resolver:

@Resolver((of) => Role)
export class RoleResolver {

  @Mutation((returns) => Boolean)
  async addRole(
    @Arg("role") role: AddRoleInput
  ): Promise<Boolean> {
    const roleExists = await Role.count({ name: role.name });
    if (roleExists > 0)
      throw new Error(`Role with name "${role.name}" already exists!`);

    const newRole = Role.create(role);
    await newRole.save();
    return true;
  }

  @Mutation((returns) => Boolean)
  async updateRole(
    @Arg("role") role: UpdateRoleInput
  ): Promise<Boolean> {
    const oldRole = await Role.findOneOrFail(role.id);
    Object.assign(oldRole, role);
    await oldRole.save();
    return true;
  }
}

And AddRoleInput and UpdateRoleInput


@InputType({ description: "New Role Argument" })
export class AddRoleInput implements Partial<Role> {
  @Field()
  name!: string;

  @Field({ nullable: true })
  description?: string;
}

@InputType({ description: "Update Role Argument" })
export class UpdateRoleInput implements Partial<Role> {
  @Field()
  id!: number;

  @Field()
  name!: string;

  @Field({ nullable: true })
  description?: string;
}


Get this bounty!!!

#StackBounty: #graphql GraphQL & Using a nested subscribe function

Bounty: 50

I am writing a graphql subscriptions server. If I write a query it is no problem to have resolvers nested one within the other, so the query would look something like this:

query {
  messages {
    privateMessage {
      id
      message
      userId
    }
  }
}

So first the messages resolver is executed, then the privateMessage resolver is executed.
I would like to know if the same structure is achievable for subscriptions so it would look like this:

subscription {
  messages {
    privateMessage {
      id
      message
      userId
    }
  }
}

EDIT:

This is the current root subscription schema I have:

const RootSubscriptions = new GraphQLObjectType({
  name: 'RootSubscriptions',
  fields: {
    privateMessage: {
      type: PrivateMessage.type,
      resolve: PrivateMessage.resolve,
      subscribe: PrivateMessage.subscribe,
    },
    flaggedMessage: {
      type: FlaggedMessage.type,
      resolve: FlaggedMessage.resolve,
      subscribe: FlaggedMessage.subscribe,
    },
    teamMessage: {
      type: TeamMessage.type,
      resolve: TeamMessage.resolve,
      subscribe: TeamMessage.subscribe,
    },
  },
})

I would like it to look like this:

const RootSubscriptions = new GraphQLObjectType({
  name: 'RootSubscriptions',
  fields: {
    messages: {
      type: new GraphQLObjectType({
        name: 'MessagesSubType',
        fields: {
          privateMessage: {
            type: PrivateMessage.type,
            resolve: PrivateMessage.resolve,
            subscribe: PrivateMessage.subscribe,
          },
          flaggedMessage: {
            type: FlaggedMessage.type,
            resolve: FlaggedMessage.resolve,
            subscribe: FlaggedMessage.subscribe,
          },
          teamMessage: {
            type: TeamMessage.type,
            resolve: TeamMessage.resolve,
            subscribe: TeamMessage.subscribe,
          },
        }
      })
    }
  },
})

EDIT END

Problem is that I get the messages subscribe function to run but not the privateMessage subscribe function to run. Would love to know if it is possible and how to achieve it.
Since I’m writing it with node.js, I would appreciate an example in js, but any pointer to a solution would be helpful.
Thanks in advance!


Get this bounty!!!

#StackBounty: #graphql #amazon-dynamodb #react-apollo #aws-amplify #aws-appsync How does AppSync subscriptions handle resolver exceptio…

Bounty: 50

I’ve noticed that throwing an exception in my subscription response mapping template results in the subscription not reaching the client.

I am building a chat feature and need to ensure new messages are delivered to client devices consistently. What happens if there is throttling exception (as a result of not provisioning enough RCU for example)? The client will be unaware that a new message unsuccessfully attempted to reach them.

Is there a way to retry the subscription, or at least inform the client so that they can pull new messages after a backoff period?


Get this bounty!!!

#StackBounty: #javascript #graphql #github-api Get results from different arrays in one Promise.All with Github GraphQL API

Bounty: 50

I’m making a custom source plugin for Gatsby, that will get markdown files from a GitHub repository. The repository has individual files (blobs) and folders (trees), which in their turn also contain files. I need to get all files (including files inside folders) in one Promise.all, but I can’t figure out how to do that. I’ve managed to get individual files from the repository and I have a function which returns an array of files from the trees. But I don’t know how to combine them.

Here is my code. GraphQL queries to get repository, trees and files information:

const repositoryQuery = `
{
  viewer {
    repository(name: "repository-name") {
      object(expression: "master:") {
        ... on Tree {
          entries {
            name
            oid
            type
          }
        }
      }
    }
  }
}
`

const treeQuery = `
  query getTree($id: GitObjectID!) {
    viewer {
      repository(name: "repository-name") {
        object(oid: $id) {
          ... on Tree {
            entries {
              name
              oid
              type
            }
          }
        }
      }
    }
  }
`

const fileQuery = `
  query getFile($id: GitObjectID!) {
    viewer {
      repository(name: "repository-name") {
        object(oid: $id) {
          ... on Blob {
            text
          }
        }
      }
    }
  }
` 

And the functions themselves:

const data = await client.request(repositoryQuery)

const getTree = async entry => {
  const data = await client.request(treeQuery, { id: entry.oid })
  const array = await data.viewer.repository.object.entries
  return array
}

const getFile = async entry => {
  const data = await client.request(fileQuery, { id: entry.oid })
  const result = await data.viewer.repository.object
  return result
}

const files = await Promise.all(
  data.viewer.repository.object.entries
    .filter(entry => entry.type !== "tree")
    .map(entry => {
      return (
        getFile(entry)
        .then(file => {
          return {
            data: file.text
          }
        })
      )
    }
  )
)

files.forEach(file =>
  createNode({...})
)

How can I update const files so that it will:

  1. Run getFile(), if entry.type !== "tree"
  2. If entry.type is tree, get an array of files inside the tree with getTree() and then run getFile() for each file.
  3. Combine all results in one array, so that I can apply to them createNode.

I would really appreciate your help.


Get this bounty!!!

#StackBounty: #javascript #reactjs #react-native #graphql #formik Button Disables After Running Query Once

Bounty: 50

I have a screen where the user inputs a phone number. I run a graphql query loadUsers according to the input and then display the search results via the showUsersfunction. It works fine on the first time. I get the results. However, after that, when the results are conditionally rendered, the search button becomes disabled. So if I want to type in a different phone number and hit the search button again, I can’t do this. Unless I exit the screen and then come back. How can I fix this?

Here’s what my code looks like:

export const AddContactTry: React.FunctionComponent = () => {
  const initialValues: FormValues = {
    phoneNumber: '',
  };

  const [isSubmitted, setIsSubmitted] = useState(false);
  const [userData, setUserData] = useState<UsersLazyQueryHookResult>('');
  const navigation = useNavigation();
  const validationSchema = phoneNumberValidationSchema;

  const [
    createUserRelationMutation,
    {
      data: addingContactData,
      loading: addingContactLoading,
      error: addingContactError,
      called: isMutationCalled,
    },
  ] = useCreateUserRelationMutation({
    onCompleted: () => {
      Alert.alert('Contact Added');
    },
  });

  const showUsers = React.useCallback(
    (data: UsersLazyQueryHookResult) => {
      if (data) {
        return (
          <View style={styles.users}>
            {data.users.nodes.map(
              (item: { firstName: string; lastName: string; id: number }) => {
                const userName = item.firstName
                  .concat(' ')
                  .concat(item.lastName);
                return (
                  <View style={styles.item} key={item.id}>
                    <Thumbnail
                      style={styles.thumbnail}
                      source={{
                        uri:
                          'https://cdn4.iconfinder.com/data/icons/avatars-xmas-giveaway/128/afro_woman_female_person-512.png',
                      }}></Thumbnail>
                    <Text style={styles.userName}>{userName}</Text>
                    <View style={styles.addButtonContainer}>
                      <Button
                        rounded
                        style={styles.addButton}
                        onPress={() => {
                          addContact(Number(item.id));
                          setIsSubmitted(false);
                          setUserData(null);
                        }}>
                        <Icon
                          name="plus"
                          size={moderateScale(20)}
                          color="black"
                        />
                      </Button>
                    </View>
                  </View>
                );
              },
            )}
          </View>
        );
      }
    },
    [createUserRelationMutation, userData],
  );

  const addContact = React.useCallback(
    (id: Number) => {
      console.log('Whats the Id', id);
      createUserRelationMutation({
        variables: {
          input: { relatedUserId: id, type: RelationType.Contact, userId: 30 },
        },
      });
    },
    [createUserRelationMutation],
  );

  const getContactId = React.useCallback(
    (data: UsersLazyQueryHookResult) => {
      if (data) {
        if (data.users.nodes.length == 0) {
          Alert.alert('No User Found');
        } else {
          setUserData(data);
        }
      }
    },
    [addContact],
  );

  const [loadUsers] = useUsersLazyQuery({
    onCompleted: getContactId,
    onError: _onLoadUserError,
  });

  const handleSubmitForm = React.useCallback(
    (values: FormValues, helpers: FormikHelpers<FormValues>) => {
      setIsSubmitted(true);
      const plusSign = '+';
      const newPhoneNumber = plusSign.concat(values.phoneNumber);
      loadUsers({
        variables: {
          where: { phoneNumber: newPhoneNumber },
        },
      });
      values.phoneNumber = '';
    },
    [loadUsers],
  );

  return (
    <SafeAreaView>
      <View style={styles.container}>
        <View style={styles.searchTopContainer}>
          <View style={styles.searchTopTextContainer}>
          </View>
          <View>
            <Formik
              initialValues={initialValues}
              onSubmit={handleSubmitForm}
              validationSchema={validationSchema}
              >
              {({ handleChange, handleBlur, handleSubmit, values, isValid, dirty }) => (
                <View style={styles.searchFieldContainer}>
                  <View style={styles.form}>
                    <FieldInput style={styles.fieldInput}
                      handleChange={handleChange}
                      handleBlur={handleBlur}
                      value={values.phoneNumber}
                      fieldType="phoneNumber"
                      icon="phone"
                      placeholderText="49152901820"
                    />
                    <ErrorMessage
                      name="phoneNumber"
                      render={(msg) => (
                        <Text style={styles.errorText}>{msg}</Text>
                      )}
                    />
                  </View>
                  <View style={styles.buttonContainer}>
                  <Text>Abbrechen</Text>
                </Button>
                <Button
                  block
                  success
                  disabled={!isValid || !dirty}
                  onPress={handleSubmit}
                  style={styles.button}>
                  <Text>Speichern</Text>
                </Button>
                  </View>
                </View>
              )}
            </Formik>
          </View>
          {isSubmitted && showUsers(userData)}
        </View>
      </View>
    </SafeAreaView>
  );
};

Edit:

As suggested in comments, I tried using useFormik instead of but couldn’t make that work.

export const AddContactTry: React.FunctionComponent = () => {
  const { values, handleChange, handleSubmit, dirty, handleBlur, isValid}= useFormik({
    initialValues: {
      phoneNumber: '',
    },
    onSubmit: values => {
      handleSubmitForm(values);
    },
  });

  const [isSubmitted, setIsSubmitted] = useState(false);
  const [userData, setUserData] = useState<UsersLazyQueryHookResult>('');
  const navigation = useNavigation();
  const validationSchema = phoneNumberValidationSchema;

  const [
    createUserRelationMutation,
    {
      data: addingContactData,
      loading: addingContactLoading,
      error: addingContactError,
      called: isMutationCalled,
    },
  ] = useCreateUserRelationMutation({
    onCompleted: () => {
      Alert.alert('Contact Added');
    },
  });

  const showUsers = React.useCallback(
    (data: UsersLazyQueryHookResult) => {
      if (data) {
        return (
          <View style={styles.users}>
            {data.users.nodes.map(
              (item: { firstName: string; lastName: string; id: number }) => {
                const userName = item.firstName
                  .concat(' ')
                  .concat(item.lastName);
                return (
                  <View style={styles.item} key={item.id}>
                    <Thumbnail
                      style={styles.thumbnail}
                      source={{
                        uri:
                          'https://cdn4.iconfinder.com/data/icons/avatars-xmas-giveaway/128/afro_woman_female_person-512.png',
                      }}></Thumbnail>
                    <Text style={styles.userName}>{userName}</Text>
                    <View style={styles.addButtonContainer}>
                      <Button
                        rounded
                        style={styles.addButton}
                        onPress={() => {
                          addContact(Number(item.id));
                          setIsSubmitted(false);
                          setUserData(null);
                        }}>
                        <Icon
                          name="plus"
                          size={moderateScale(20)}
                          color="black"
                        />
                      </Button>
                    </View>
                  </View>
                );
              },
            )}
          </View>
        );
      }
    },
    [createUserRelationMutation, userData],
  );

  const addContact = React.useCallback(
    (id: Number) => {
      console.log('Whats the Id', id);
      createUserRelationMutation({
        variables: {
          input: { relatedUserId: id, type: RelationType.Contact, userId: 30 },
        },
      });
    },
    [createUserRelationMutation],
  );

  const getContactId = React.useCallback(
    (data: UsersLazyQueryHookResult) => {
      if (data) {
        if (data.users.nodes.length == 0) {
          Alert.alert('No User Found');
        } else {
          setUserData(data);
        }
      }
    },
    [addContact],
  );

  const [loadUsers] = useUsersLazyQuery({
    onCompleted: getContactId,
    onError: _onLoadUserError,
  });

  const handleSubmitForm = React.useCallback(
    (values: FormValues) => {
      setIsSubmitted(true);
      const plusSign = '+';
      const newPhoneNumber = plusSign.concat(values.phoneNumber);
      console.log('Submitted');
      loadUsers({
        variables: {
          where: { phoneNumber: newPhoneNumber },
        },
      });
      values.phoneNumber = '';
    },
    [loadUsers],
  );

return (
    <SafeAreaView>
      <View style={styles.container}>
        <View style={styles.searchTopContainer}>
          <View style={styles.searchTopTextContainer}>
          </View>
          <View>
                <View style={styles.searchFieldContainer}>
                  <View style={styles.form}>
                    {/* <FieldInput style={styles.fieldInput}
                      handleChange={handleChange}
                      handleBlur={Formik.handleBlur}
                      value={Formik.values.phoneNumber}
                      fieldType="phoneNumber"
                      icon="phone"
                      placeholderText="49152901820"
                    /> */}
                     <Input style={styles.fieldInput}
                      onChangeText={handleChange('phoneNumber') as (text: string) => void}
                      onBlur={handleBlur('phoneNumber') as (event: any) => void}
                      value={values.phoneNumber}
                      //name="phoneNumber"
                      //fieldType="phoneNumber"
                      //icon="phone"
                      placeholder="49152901820"
                    />
                    <ErrorMessage
                      name="phoneNumber"
                      render={(msg) => (
                        <Text style={styles.errorText}>{msg}</Text>
                      )}
                    />
                  </View>
                  <View style={styles.buttonContainer}>
                <Button
                  block
                  success
                  disabled={!isValid || !dirty}
                  onPress={handleSubmit}
                  style={styles.button}>
                  <Text>Speichern</Text>
                </Button>
                  </View>
                </View>
          </View>
          {isSubmitted && showUsers(userData)}
        </View>
      </View>
    </SafeAreaView>
  );
};


Get this bounty!!!

#StackBounty: #node.js #memory-leaks #graphql #apollo-server How can I debug a memory leak on my Apollo GraphQL server?

Bounty: 200

I have a graphql server with multiple endpoints. It is basically just a CRUD app, so I’m honestly not sure why there’s a memory leak. The only potentially leaky endpoint I have is one that uploads pics to S3.

I’ve been looking around and have tried taking heap snapshots and comparing them but I’m not even sure which endpoint is the culprit. This is the flow I’ve been following:

  1. Start the server with the --inspect flag: nodemon --inspect --exec babel-node src/index.js
  2. Take a heap snapshot before I do anything
  3. Start my front end app and hit the endpoint I think has the memory leak (the one where I upload a photo)
  4. Take a heap snapshot again and compare the two

Is this the correct flow for finding a memory leak? Is there a better way of doing this without having to guess which endpoint it is coming from? Are there perhaps tools I can use online that can help me find the source of the memory leak in production without having to guess like this? Perhaps something like Datadog or something?

Update: From Heroku’s metrics, it looks like the memory usage increases every time a request is made?

enter image description here

But my src/index.js file doesn’t do anything special:

import { ApolloServer, gql } from "apollo-server";
import { connectDb, models } from "./models";

import schema from "./schema";
import resolvers from "./resolvers";
import contexts from "./contexts";

const server = new ApolloServer({
  typeDefs: schema,
  resolvers,
  context: async ({ req, connection }) => {
    console.log(req.body.query);
    console.log(req.body.variables);

    const { getCurrentUser } = contexts;

    const currentUser = await getCurrentUser(req);
    return { models, currentUser };
  },
});

connectDb().then(async () => {
  server.listen({ port: process.env.PORT || 4000 }).then(({ url }) => {
    console.log(`🚀  Server ready at ${url}`);
  });
});


Get this bounty!!!

#StackBounty: #graphql #apollo #react-apollo #apollo-client #vue-apollo How to catch and modify apollo response globally?

Bounty: 50

Is there a way to catch and modify response globally on the fly? I can do this for one query like below, but I want to do it for all queries.

apollo: {
    post: {
        query: Post,
        update(data) {
            return data.map(item => Object.assign(item, {foo: 'bar'})
        }
    }
}

It’s simplified for this question, but under the hood I’d like to apply a constructor (class) to all objects…

I’m using nuxt-apollo. I searched for a way to do that in clientConfig or elsewhere so the solution may be related to apollo…

Thanks for your advice!

edit:
OK, I found to do that with apollo-link, but I can’t modify response. Here the code:

const constructorMiddleware = new ApolloLink((operation, forward) => {
    return forward(operation).map(response => {
      Object.keys(response.data).map(key => {
        if (!Array.isArray(response.data[key])) return;
        const newResponse = response.data[key].map(item => {
          return item.__typename === 'post'
            ? Object.assign(item, { foo: 'bar' })
            : item
        })
        console.log(newResponse)
        response.data[key] = newResponse
      })
      return response
    })
  })

I can see foo: bar in the newResponse, but the graphql returning by nuxt-apollo doesn’t contains this newResponse, only original.
Do ApolloLink override response? Does apollo cache change this?

edit 2:
I tried to chain links and the newResponse of the constructorMiddleware is well in the next link. So the problem seems come from nuxt-apollo, or more vue-apollo…


Get this bounty!!!

#StackBounty: #javascript #reactjs #graphql #react-apollo #react-adopt React-apollo update not reloading after mutation if I transform …

Bounty: 100

I have wrapped for both Query and Mutations so I can globally handle the repeat actions that need to happen with each Query, Mutation. In the query I transform the data so I don’t need to worry about all the nodes, edges, etc

I am using react-adopt to wrap all my query and mutations components into one render prop back on the view layer.

Works – Page will re-render once a mutation has taken place

<ApolloQuery>

export const ApolloQuery = ({
  query: query,
  render,
}) => {
  return (
    <Query query={query}>
      {({ data }) => {
        return (
          <Fragment>
               render(data)
          </Fragment>
        )
      }}
    </Query>
  )
}

A Component

export default externalProps => {
  return (
    <QueryContainer {...externalProps}>
      {({ someQueryData, aMutation }) => { //react-adopt render props
        const { nestedData } = new apolloClass(someQueryData).start()
        return (
          <Grid container spacing={16}>
            {nestedData.map((ticket, index) => (
               {...Mutation button in here}
            ))}
         </Grid>
        )
      }}
    </QueryContainer>
  )
}

Does not work – Page does not re-render but cache is updated with correct records

<ApolloQuery>

    <Query query={query}>
      {({ data }) => {
        const transformedData = new apolloClass(data).start() //move transform into render
        return (
          <Fragment>
               render(transformedData)
          </Fragment>
        )
      }}
    </Query>

A Component

export default externalProps => {
  return (
    <QueryContainer {...externalProps}>
      {({ someQueryData: { nestedData }, aMutation }) => {
        return (
          <Grid container spacing={16}>
            {nestedData.map((ticket, index) => (
               {...Mutation button in here}
            ))}
         </Grid>
        )
      }}
    </QueryContainer>
  )
}

So now, the page will not update after a mutation if I move the apolloClass to transform before the render of the query


Get this bounty!!!

#StackBounty: #graphql #apollo-client #nestjs #apollo-server ApolloGraphQL: Non web socket subscriptions?

Bounty: 50

We have an app that implements essentially this guide exactly:

https://www.apollographql.com/docs/apollo-server/features/subscriptions/

It’s been great. We’ve had great success and the app has been doing great.

What we have started running into though, is that various large corporations block their internal staff’s web sockets. They return a 403 when we try to upgrade to the web sockets.

I’ve been googling around and just don’t see much for anything in the Apollo community for non web socket subscriptions. Everything guide/article/example is based on web sockets.

Ideally i’d use something like socket.io, that falls back to long polling is a solution I was thinking. But everyone only uses the subscriptions-transport-ws library (we use it). I found a dated lib called subscriptions-transport-sse, but hesitant to try it and my server setup would need a lot of refactoring. We use nestjs and the Apollo GraphQL module.

Has anyone else solved how to fallback to a different transport? I’m really trying to avoid writing my own, but looks like the choices are that or switch to another framework that has it built in?

Thanks.


Get this bounty!!!

#StackBounty: #graphql #apollo-server #express-graphql #graphql-tools Handle graphql schema stitching error in child query

Bounty: 50

I am new to graphql and want to understand the concept here. I have this graphql schema (stitched using graphic-tools). Not all cars have registration. So if I query for 5 cars and one car doesn’t have a registration (no id to link between cars and registration), my whole query fails.

How do I handle this and return null for that 1 car and return registration details for the other 4?

{
  Vehicles {
    Cars {
      id
      registration {
        id
      }
    }
  }
}


Get this bounty!!!