I'm pretty new to Relay so perhaps it's a very stupid error.
I'm trying to make a simple mutation that add a defect to a photo.
Here is my Relay.Mutation object :
AddDefectMutation.js
export default class AddDefectMutation extends Relay.Mutation {
getMutation() {
return Relay.QL`mutation { addDefect }`;
}
getVariables() {
return{
photoId: this.props.photoId,
title: this.props.title
}
}
getFatQuery() {
return Relay.QL`
fragment on AddDefectMutationPayload {
updatedPhoto {
issues
}
}
`
}
getConfigs() {
return [{
type : 'FIELDS_CHANGE',
fieldIDs : {
updatedPhoto : this.props.photoId
}
}]
}
}
And here is the part of the GraphQl schema
const AddDefectMutation = mutationWithClientMutationId({
name: 'AddDefectMutation',
description: 'Add a new defect and return all the defects.',
inputFields: {
photoId: {
description: 'Photo of this defect',
type: new GraphQLNonNull(GraphQLString)
},
title: {
description: 'A short description of the defect',
type: GraphQLString
}
},
outputFields: {
updatedPhoto: {
type: PhotoGraphQLType,
resolve: ({localIdIssue}) => driver.getIssuePhoto(localIdIssue)
}
},
mutateAndGetPayload: ({photoId, title}) =>
driver.addIssue(photoId, title).then(localIdIssue => ({localIdIssue}))
})
const MutationGraphQLType = new GraphQLObjectType({
name: 'Mutation',
fields: () => ({
addDefect: AddDefectMutation
})
})
My problem is that when I make this call :
Relay.Store.commitUpdate(new AddDefectMutation(
{photoId: this.props.pictureId, title: this.props.title}), {
onSuccess: ()=> console.log("Mutation Success !"),
onFailure: transaction => console.error(transaction.getError() || new Error('Mutation failed.'))
})
Relay generate the good mutation query without problem but it doesn't place the variables given in the constructor.
EDIT : Here the fragment of mutation generated by relay
mutation AddDefect($input_0:AddDefectMutationInput!) {
addDefect(input:$input_0) {
...F4,
clientMutationId
}
}
And the problem is that $input_0 is an empty object
The variable title is not passed properly to the mutation constructor. In your Relay.Store.commitUpdate function call, change {photoId: this.props.pictureId, this.props.title}) to
{photoId: this.props.pictureId, title: this.props.title})
Related
I'm using ContentLayer library for import MDX content in my blog.
I've read a several opensource code and I following them, but in my case I don't have "code" property in my "body" object.
while I cloend other opensource project and they works correctly and I saw they have "code" property in their "body" object.
this is my [slug].tsx:
import BlogLayout from '#layouts/blog';
import { useMDXComponent } from 'next-contentlayer/hooks';
import { allBlogs } from '../../.contentlayer/generated';
import type { Blog } from '../../.contentlayer/generated';
type BlogProps = {
blog: Blog;
};
export default function Blog({ blog }: BlogProps) {
console.log(blog.body.code);
const Component = useMDXComponent(blog.body.code);
return (
<BlogLayout blog={blog}>
<Component />
</BlogLayout>
);
}
export const getStaticPaths = async () => {
return {
paths: allBlogs.map(p => ({ params: { slug: p.slug } })),
fallback: false,
};
};
export const getStaticProps = async ({ params }) => {
const blog = allBlogs.find(p => p.slug === params.slug);
return {
props: {
blog,
},
};
};
and this is my contentLayer configuration:
import { defineDocumentType, makeSource } from 'contentlayer/source-files';
import mdxOptions from './config/mdx';
import readingTime from 'reading-time';
export const Blog = defineDocumentType(() => ({
name: 'Blog',
bodyType: 'mdx',
filePathPattern: `blogs/**/*.mdx`,
fields: {
title: { type: 'string', required: true },
publishedAt: { type: 'string', required: true },
description: { type: 'string', required: true },
cover: { type: 'string' },
tag: { type: 'string' },
},
computedFields: {
readingTime: {
type: 'json',
resolve: doc => readingTime(doc.body.raw),
},
slug: {
type: 'string',
resolve: doc => doc._raw.sourceFileName.replace(/\.mdx$/, ''),
},
},
}));
export default makeSource({
contentDirPath: '_posts',
documentTypes: [Blog],
mdx: mdxOptions,
});
In my case "body" object has these objects: { _raw , html }
I don't know what's the problem and why I don't have "code" property in my "body" object
I appreciate all feedback from you.
I found in version 0.1.0 release contains two (2) breaking changes. that one of them is:
đŸ’¥ [Breaking] bodyType will be replaced by contentType.
Background: I'm building a Shopify app using React, NextJS, and GraphQL. The functionality is to add an extra privateMetafield with a value for each selected product.
The problem: I'm trying to create or update (if privateMetafield exists) with Mutation using React-Apollo. I have tried to run the GraphQL mutation in Insomnia (like postman for GraphQL) and it works. But when I add it to my code I don't get the GraphQL to receive the mutation data. Instead, I get this error message:
Unhandled Runtime Error
Error: GraphQL error: Variable $input of type PrivateMetafieldInput! was provided invalid value for privateMetafields (Field is not defined on PrivateMetafieldInput), namespace (Expected value to not be null), key (Expected value to not be null), valueInput (Expected value to not be null)
Insomnia Successful GraphQL test (what it should be like)
edit-products.js
...
import gql from 'graphql-tag';
import { Mutation } from 'react-apollo';
...
const UPDATE_EMISSION = gql`
mutation($input: PrivateMetafieldInput!) {
privateMetafieldUpsert(input: $input) {
privateMetafield {
namespace
key
value
}
}
}
`;
...
class EditEmission extends React.Component {
state = {
emission: '',
id: '',
showToast: false,
};
render() {
const { name, emission, id } = this.state;
return (
<Mutation
mutation={UPDATE_EMISSION}
>
{(handleSubmit, { error, data }) => {
const showError = error && (
<Banner status="critical">{error.message}</Banner>
);
const showToast = data && data.productUpdate && (
<Toast
content="Sucessfully updated"
onDismiss={() => this.setState({ showToast: false })}
/>
);
return (
<Frame>
... <Form>
<TextField
prefix="kg"
value={emission}
onChange={this.handleChange('emission')}
label="Set New Co2 Emission"
type="emission"
/>
...
<PageActions
primaryAction={[
{
content: 'Save',
onAction: () => {
const item = store.get('item');
const id = item.id;
const emissionVariableInput = {
owner: id,
privateMetafields: [
{
namespace: "Emission Co2",
key: "Co2",
valueInput: {
value: emission,
valueType: "INTEGER"
}
}
]
};
console.log(emissionVariableInput)
handleSubmit({
variables: { input: emissionVariableInput },
});
}
}
]}
secondaryActions={[
{
content: 'Remove emission'
}
]}
/>
</Form>
...
</Mutation>
);
}
handleChange = (field) => {
return (value) => this.setState({ [field]: value });
};
}
export default EditEmission;
I get this in the console when I log emissionVariableInput, which looks correct. But why is the data not passed properly to the GraphQL mutation and how do I fix it?
I expect the GraphQL mutation to be successful and create/update a privateMetafield owned by a product.
Thanks in advance!
You have different shapes for input in your examples. In Insomnia you pass:
{
owner: id,
namespace: "Emission Co2",
key: "Co2",
valueInput: {
value: emission,
valueType: "INTEGER"
}
}
While in the code your input looks like:
{
owner: id,
privateMetafields: [{
namespace: "Emission Co2",
key: "Co2",
valueInput: {
value: emission,
valueType: "INTEGER"
}
}]
};
I'm using the code below
Broke
const dataSourceSchema = {
model: {
fields: {
name: { type: 'string' },
description: { type: 'string' }
}
}
};
const gridOptions = {
...
};
class ItemsContainer extends React.Component {
componentDidMount() {
this.props.getItems();
}
render() {
const { items } = this.props;
const dataSource = {
schema: dataSourceSchema,
data: items
}
return (
<Grid {...gridOptions} dataSource={dataSource} />
);
}
}
And I get the following error
Error
But if I used this code that hard codes the dataSource.data then it works.
Works
const gridOptions = {
dataSource: {
data: [{name: 'foo', description: 'bar'}],
schema: {
model: {
fields: {
name: { type: "string" },
description: { type: "string" }
}
}
},
pageSize: 20
},
...
columns: [
"name",
"description"
]
};
class ItemsContainer extends React.Component {
componentDidMount() {
this.props.getItems();
}
render() {
const { items } = this.props;
return (
<Grid {...gridOptions}/>
);
}
}
What am I doing wrong. I was spreading out the dataSource property because it looks like the kendo wrapper is checking it's reference (as it should).
I'm getting started with Relay and GraphCool and have trouble creating the createUser Mutation with Relay.
This is my current code:
import Relay from 'react-relay';
class SignupUserMutation extends Relay.Mutation {
getMutation() {
return Relay.QL`
mutation {
createUser(input: {
authProvider: {email: { email: $email, password: $password }},
clientMutationId: "createuser1"
}) {
clientMutationId
}
}
`;
}
getVariables() {
return {
email: this.props.email,
password: this.props.password
};
}
getFatQuery() {
return Relay.QL`
fragment on CreateUserPayload {
viewer { id }
}
`;
}
getConfigs() {
return [{
type: 'RANGE_ADD',
parentName: 'viewer',
parentID: this.props.viewerId,
connectionName: 'users',
edgeName: 'usereEdge',
rangeBehaviors: {
'': 'append',
},
}];
}
}
export default SignupUserMutation;
I keep getting the error:
Variable '$input_0' expected value of type 'SignupUserInput!' but got: {"email":"fdadsffd#fasdf.at","password":"#fdsad","clientMutationId":"1"}. Reason: Unknown field 'email' is not defined in the input type 'SignupUserInput'. (line 1, column 29):↵mutation SignupUserMutation($input_0:SignupUserInput!) {
What am I doing wrong here?
The code below works when the entire schema is in a single file, but I'm getting the above error when I try to split it into individual files.
I'm importing all the types and functions.
I have to add more details, but I'm not sure what to say. I think it's a sequencing problem since it works in a single file, but not split up.
Thanks a lot.
const UserCreateMutation = mutationWithClientMutationId({
name: 'UserCreate',
inputFields: {
email: {type: new GraphQLNonNull(GraphQLString)},
password: {type: new GraphQLNonNull(GraphQLString)}
},
outputFields: {
viewer: {
type: viewerType,
resolve() {
return viewerGet();
}
},
field: {
type: userType,
resolve(node) {
return node;
}
}
},
async mutateAndGetPayload({email, password}, {db, req}) {
export const viewerType = new GraphQLObjectType({
name: 'Viewer',
fields() {
return {
id: globalIdField('Viewer', ({_id: viewerLocalId}) => {
return viewerLocalId;
}),
_id: {type: GraphQLID},
user: {
type: userType,
resolve(parent, args, {req: {user}}) {
return user || {};
}
},
profile: {
type: profileConnectionType,
args: {
id: {type: GraphQLID},
searchTerm: {type: GraphQLString},
...connectionArgs
},
resolve(parent, {id: profileGlobalId, searchTerm, ...connectionArgs}, {db}) {
const query = (() => {
const q = {};
if (profileGlobalId) {
const {id: profileLocalId} = fromGlobalId(profileGlobalId);
Object.assign(
q,
{_id: new ObjectID(profileLocalId)}
);
}
if (searchTerm) {
Object.assign(
q,
{
$text: {
$search: `\"${searchTerm}\"`
}
}
);
}
return q;
})();
const sort = {_id: -1};
const limit = 0;
return connectionFromPromisedArray(
promisedArrayGet(
query,
sort,
limit,
profileCollectionName,
db
),
connectionArgs
);
}
}
};
},
interfaces: [nodeInterface]
});
class Viewer extends Object {}
export const viewerGet = () => {
return Object.assign(
new Viewer(),
{
_id: 'Viewer'
}
);
};
import { viewerType, userType, viewerGet }
Not sure if this is the problem but sometimes module-loading order is an issue. If it is the problem, you can solve it by making outputFields a thunk, i.e. a function that returns the object instead of a plain object.
outputFields: () => ({
viewer: {
type: viewerType,
resolve() {
return viewerGet();
}
},
field: {
type: userType,
resolve(node) {
return node;
}
}
}),