After a mutation I can't seem to receive the pubSub data on my react front end
I have the following Graphql schema:
type SSiD {
id: ID!
name: String
status: String
hidden: Boolean
}
type Subscription {
SSiDAdded: SSiD
}
On my apolloServer after the mudation I send the pubSub data like this
const data = result.dataValues
data.__typename = 'SSiD'
console.log(data)
context.pubsub.publish('SSiDAdded', data)
That console.log will output:
{ id: 2208,
name: 'FooBar',
hidden: true,
status: 'broadcasting',
updatedAt: 2016-10-27T22:07:09.119Z,
createdAt: 2016-10-27T22:07:09.119Z,
__typename: 'SSiD' }
And finally on my react front end I have the following:
const query = gql`
subscription ssidList{
SSiDAdded{
id
name
hidden
}
}
`
this.subscriptionObserver = this.props.client.subscribe({
query
})
.subscribe({
next (data) {
console.log('The subscription data', data)
},
error (err) {
console.error('Error subscription', err)
}
})
}
On the console.log above subscription data is always null.
Am I wrapping the response wrong or something like that?
Here a couple things to check. On my schema, it has some syntax I'm not seeing in yours at the moment. See the : instant_message after the query strings?
const typeDefinitions = [`
type instant_message {
id: Int
fromID: String
toID: String
msgText: String
}
type Query {
instant_message(id: Int, fromID: String, toID: String, msgText: String): [instant_message]
}
type Mutation {
createIM(
fromID: String!
toID: String!
msgText: String!
): instant_message
}
type Subscription {
# Subscription fires on every comment added
IMAdded(id: Int, fromID: String!, toID: String!): instant_message
}
schema {
query: Query,
mutation: Mutation
subscription: Subscription
}
`];
I've got some different syntax on the client as well:
subscribe(fromID, toID, updateQueryViaSubscription) {
const SUBSCRIPTION_QUERY = gql`
subscription getIMsViaSubscription($fromID: String!, $toID: String!){
IMAdded(fromID:$fromID, toID: $toID){
id,
fromID,
toID,
msgText
}
}
`;
this.subscriptionObserver = this.props.client.subscribe({
query: SUBSCRIPTION_QUERY,
variables: { fromID: this.fromID, toID: this.toID },
}).subscribe({
next(data) {
const newMsag = data.IMAdded;
updateQueryViaSubscription((previousResult) => {
// if it's our own mutation, we might get the subscription result
// after the mutation result.
// if (isDuplicateIM(newComment, previousResult.entry.comments)) {
// return previousResult;
// }
// update returns a new "immutable" list with the new comment
// added to the front.
return update(
previousResult,
{
instant_message: {
$push: [newMsag],
},
}
);
});
},
error(err) {
console.error('err', err); },
});
}
Please check that and let me know if the updated code gets rid of that error yet.
UPDATE: Per our discussion on Slack, you found that you needed your executableSchema to be like this:
const executableSchema = makeExecutableSchema({
typeDefs: typeDefinitions,
resolvers: Resolvers,
connectors: Connectors,
logger: console,
});
export default executableSchema;
Here's the resolver I'm using:
Subscription: {
IMAdded(IMThatWasAdded) {
var ret = IMThatWasAdded;
return ret;
}
}
Related
I'm getting a warning:
Cache data may be lost when replacing the parts field of a Query object.
To address this problem (which is not a bug in Apollo Client), define a custom merge function for the Query.parts field, so InMemoryCache can safely merge these objects:
existing: [{"__ref":"Part:53"},{"__ref":"Part:55"},{"__ref":"Part:56"},{"__ref":"Part:57"},{"__ref":"Part:58"}]
incoming: [{"__ref":"Part:53"},{"__ref":"Part:55"},{"__ref":"Part:56"},{"__ref":"Part:57"}]
Now here is my Part type:
type Part {
id: ID!
created_at: DateTime!
updated_at: DateTime!
partName: String
partDescription: String
partQuantity: Long
usePercentage: Boolean
partPercentage: Float
type: String
published_at: DateTime
products(sort: String, limit: Int, start: Int, where: JSON): [Product]
partImage(sort: String, limit: Int, start: Int, where: JSON): [UploadFile]
stockevents(sort: String, limit: Int, start: Int, where: JSON): [Stockevent]
}
This warning triggers after I remove one part using mutation to delete a single part. Here it is:
const [partDelete] = useMutation(DELETE_PART, {
update(cache, { data }) {
const newData = Object.values(data)
const refresh = newData.map(name => name.part)
const refined = refresh.map(item => item.id)
cache.evict({
id: cache.identify({
id: refined.id
})
})
cache.writeQuery({
query: GET_PARTS
})
},
refetchQueries: [
{ query: GET_PARTS }
]
})
I am passing payload in a separate function and everything works but I keep getting this cache warning so I want to deal with it now.
I've went with updating InMemoryCache in my index.js but it still doesn't work:
export const client = new ApolloClient({
link,
cache: new InMemoryCache({
typePolicies: {
Part: {
merge(existing = [], incoming = []) {
return [...existing, ...incoming];
}
}
}
})
});
I've also tried to return only ...incoming but nothing different happens.
Thanks in advance, cheers!
The issue was in the structure of InMemoryCache config. After I changed it to this it worked:
export const client = new ApolloClient({
link,
cache: new InMemoryCache({
typePolicies: {
Query: {
Part: {
parts: {
fields: {
merge(existing, incoming) {
return incoming;
}
}
}
}
}
}
})
});
I have also removed update option from the mutation that includes evict and modify.
when you see this warning:
To address this problem (which is not a bug in Apollo Client), define a custom merge function for the Query.your_query_name field, so InMemoryCache can safely merge these objects:
try this for shorten:
const client = new ApolloClient({
uri: "your_API_link",
cache: new InMemoryCache({
typePolicies: {
Query: {
fields: {
your_Query_Name: {
merge: (existing = [], incoming) => {
return incoming;
},
},
},
},
},
}),
});
Graphql schema:
type SDKConfig #model
#key(name: "byPublisher", fields: ["publisher_id", "id"]){
id: ID!
publisher_id: ID!
facebook_app_id: String
adjust_app_token: String
}
type GameConfig #model
#auth(rules: [
{allow: owner},
{allow: groups, groupsField: "groups"}]){
id: ID!
game_name: String!
bundle_identifier: String!
sdkConfigs: [SDKConfig] #connection(keyName: "byPublisher", fields: ["id"])
groups: [String]
}
Mutations:
export const createGameConfig = /* GraphQL */ `
mutation CreateGameConfig(
$input: CreateGameConfigInput!
$condition: ModelGameConfigConditionInput
) {
createGameConfig(input: $input, condition: $condition) {
id
game_name
bundle_identifier
sdkConfigs {
items {
id
publisher_id
facebook_app_id
adjust_app_token
createdAt
updatedAt
}
nextToken
}
groups
createdAt
updatedAt
owner
}
}
`;
React function:
async function createGame() {
try {
const newgame = {
"game_name": "deneme",
"bundle_identifier": "com.magiclab.deneme",
sdkConfigs: [
{ "publisher_id": 5,
"facebook_app_id": "fb12313",
"adjust_app_token": "adjusttoken123123",
}
]
}
await API.graphql(graphqlOperation(createGameConfig, {input: newgame}))
} catch (err) {
console.log('error creating game sdk config:', err)
}
}
Error message:
"The variables input contains a field name 'sdkConfigs' that is not defined for input object type 'CreateGameConfigInput' "
I want to create an array of objects within the object. How to fix input object for graphql ?
You should run two different mutations, one for creating the GameConfig and anorther one for create the SDKConfig it will be something like this
async function createGame() {
try {
const newgame = {
game_name: 'deneme',
bundle_identifier: 'com.magiclab.deneme',
};
const sdk = {
publisher_id: null,
facebook_app_id: 'fb12313',
adjust_app_token: 'adjusttoken123123',
};
const {
data: {
createGameConfig: { id: publisher_id },
},
} = await API.graphql(
graphqlOperation(createGameConfig, { input: newgame })
);
sdk.publisher_id = publisher_id;
await API.graphql(graphqlOperation(createSDKConfig, { input: sdk }));
} catch (err) {
console.log('error creating game sdk config:', err);
}
}
then you will use the id return by the first mutation as an input for the second mutation, this identifier will bound these two entries and when you query any gameConfig it will pull in an array any SDKConfig that their publisher_id matches with the gameConfig.
You could expand these information in this section of the official documentation https://docs.amplify.aws/cli/graphql-transformer/directives#belongs-to
I am trying to setup relations between types and wrote a resolver to run a mutation that create the list values but getting the below error
here is my mutation file
async createList(parent, args, ctx, info) {
const list = await ctx.db.mutation.createList(
{
data: {
project: {
connect: {
id: args.projectId
}
},
...args
}
},
info
);
return list;
}
and here is my datamodel
type Board {
id: ID! #id
title: String!
createdAt: DateTime! #createdAt
updatedAt: DateTime! #updatedAt
lists: [List]!
}
type List {
id: ID! #id
title: String!
createdAt: DateTime! #createdAt
updatedAt: DateTime! #updatedAt
project: Board!
}
and my schema is
type Mutation {
createList(title: String!, projectId: ID!): List!
}
and the generated prisma file
type Mutation {
createList(data: ListCreateInput!): List!
}
input ListCreateInput {
id: ID
title: String!
project: BoardCreateOneWithoutListsInput!
}
I expected this mutation to run and create the values but got this error instead
Error: Variable "$_v0_data" got invalid value { project: { connect: [Object] }, title: "to do", projectId: "cjyey7947hh6x0b36m231qhbc" }; Field "projectId" is not defined by type ListCreateInput. Did you mean project?
at new CombinedError (/Users/gabroun/Documents/Sites/react-kanban/server/node_modules/graphql-tools/dist/stitching/errors.js:82:28)
at Object.checkResultAndHandleErrors (/Users/gabroun/Documents/Sites/react-kanban/server/node_modules/graphql-tools/dist/stitching/errors.js:98:15)
at CheckResultAndHandleErrors.transformResult (/Users/gabroun/Documents/Sites/react-kanban/server/node_modules/graphql-tools/dist/transforms/CheckResultAndHandleErrors.js:9:25)
at /Users/gabroun/Documents/Sites/react-kanban/server/node_modules/graphql-tools/dist/transforms/transforms.js:18:54
at Array.reduce (<anonymous>)
at applyResultTransforms (/Users/gabroun/Documents/Sites/react-kanban/server/node_modules/graphql-tools/dist/transforms/transforms.js:17:23)
at /Users/gabroun/Documents/Sites/react-kanban/server/node_modules/graphql-tools/dist/stitching/delegateToSchema.js:97:50
at step (/Users/gabroun/Documents/Sites/react-kanban/server/node_modules/graphql-tools/dist/stitching/delegateToSchema.js:31:23)
at Object.next (/Users/gabroun/Documents/Sites/react-kanban/server/node_modules/graphql-tools/dist/stitching/delegateToSchema.js:12:53)
at fulfilled (/Users/gabroun/Documents/Sites/react-kanban/server/node_modules/graphql-tools/dist/stitching/delegateToSchema.js:3:58)
Consider using the following code
async function createList(parent, { title, projectId }, ctx, info) {
const list = await ctx.db.mutation.createList(
{
data: {
project: {
connect: {
id: projectId,
},
},
title,
},
},
info,
)
return list
}
The reason for getting the error is because ...args is used, so all the attributes in args will be passed to data as follows
data:{
project:{...},
title:'',
projectId:'',
}
ListCreateInput only needs title and project. The extra projectId becomes accidentally causing an error.
I am having an issue with getting my resolver function to work properly.
Here is my resolver function:
const resolvers = {
Query: {
info: () => `This is the API of a Hackernews Clone`,
// 2
feed: () => links,
},
// 3
Mutation: {
// 2
post: (parent, args) => {
const link = {
id: `link-${idCount++}`,
description: args.description,
url: args.url,
}
links.push(link)
return link
},
deleteLink: (parent, args) => {
const id = args.id
//delete links[id1]
return id
}
}
}
Here is my schema:
type Query {
info: String!
feed: [Link!]!
}
type Mutation {
post(url: String!, description: String!): Link!
deleteLink(id: ID!): Link
}
type Link {
id: ID!
description: String!
url: String!
}
When I use this block to run my deleteLink resolver:
mutation {
deleteLink(
id: "link-1"
){
id
}
}
I get an error like this one:
{
"data": {
"deleteLink": null
},
"errors": [
{
"message": "Cannot return null for non-nullable field Link.id.",
"locations": [
{
"line": 3,
"column": 5
}
],
"path": [
"deleteLink",
"id"
]
}
]
}
Please let me know what I am doing wrong. I am not sure why i get the error: cannot return null for non-nullable field Link.id. Is this a result of the wrong way to query the mutation or is this a result of a bad resolver function?
According to your schema, your deleteLink mutation returns a Link object type and a Link returns id, description, url as required fields.
In your resolver, you are only returning a id and null for all the rest.
The best approach in my opinion would be to change your mutation return type into a String or ID type. When you delete a record, you can't (should not) return the same record, but should return a status/id message.
Something like:
type Mutation {
post(url: String!, description: String!): Link!
deleteLink(id: ID!): String! // Or ID! if you want to return the input id
}
I am making a blog service using express and apollo-express along with mongodb (mongoose).
I made some mutation queries, but I have no success with obtaining the args of a mutation query.
Now I am asking for how I should structure my mutation query in order to make the thing work. thanks.
error:
"message": "Blog validation failed: title: Path title is required., slug: Path slug is required."
the query:
mutation ($input: BlogInput) {
newBlog(input: $input) {
title
slug
}
}
the query variables:
{
"input": {
"title": "ABC",
"slug": "abc"
}
}
part of my graphql schema:
type Blog {
id: ID!
title: String!
slug: String!
description: String
users: [User]!
posts: [Post]!
}
input BlogInput {
title: String!
slug: String!
description: String
}
extend type Mutation {
newBlog(input: BlogInput): Blog
}
part of my resolvers:
import Blog from './blog.model'
export const blogs = async () => {
const data = await Blog.find().exec()
return data
}
export const newBlog = async (_, args) => {
const data = await Blog.create({ title: args.title, slug: args.slug })
return data
}
part of my database schema (mongoose):
import mongoose from 'mongoose'
const Schema = mongoose.Schema
const blogSchema = Schema({
title: {
type: String,
required: true
},
slug: {
type: String,
required: true,
unique: true
},
description: {
type: String
},
users: {
type: [Schema.Types.ObjectId],
ref: 'User'
},
posts: {
type: [Schema.Types.ObjectId],
ref: 'Post'
}
})
export default mongoose.model('Blog', blogSchema)
You've defined your newBlog mutation to accept a single argument named input. From what I can tell, you're correctly passing that argument to the mutation using a variable. Your resolver receives a map of the arguments passed to the field being resolved. That means you can access individual properties of the input object like this:
export const newBlog = async (_, args) => {
const data = await Blog.create({ title: args.input.title, slug: args.input.slug })
return data
}
Note, you may want to make input non-nullable (i.e. set the type to BlogInput!), otherwise your resolver will need to handle the possibility of args.input returning undefined.