Hello guys I have the following problem:
wherever I try to post a comment I get the following error:
ClientError: input:3: Field "post" is not defined by type CommentCreateInput.
: {"response":{"errors":[{"message":"input:3: Field \"post\" is not defined by type CommentCreateInput.\n"}],"data":null,"extensions":{"requestId":"cl3uwxntaa8r70cll4db25q72"},"status":400,"headers":{}},"request":{"query":"\n mutation CreateComment($name: String!, $email: String!, $comment: String!, $slug: String!) {\n createComment(data: {name: $name, email: $email, comment: $comment, post: {connect: {slug: $slug}}}) { id }\n }\n ","variables":{"name":"Roberto","email":"robert.rivera#outlook.com","comment":"a","slug":"react-testing"}}}
at /home/xue/Documents/Programacion/blog-nodejs/node_modules/graphql-request/dist/index.js:356:31
at step (/home/xue/Documents/Programacion/blog-nodejs/node_modules/graphql-request/dist/index.js:63:23)
at Object.next (/home/xue/Documents/Programacion/blog-nodejs/node_modules/graphql-request/dist/index.js:44:53)
at fulfilled (/home/xue/Documents/Programacion/blog-nodejs/node_modules/graphql-request/dist/index.js:35:58)
at processTicksAndRejections (internal/process/task_queues.js:97:5) {
response: {
}
API resolved without sending a response for /api/comments, this may result in stalled requests.
this is my code so far:
pages/api/comments.js
import { GraphQLClient, gql } from 'graphql-request';
const graphqlAPI = process.env.NEXT_PUBLIC_GRAPHCMS_ENDPOINT
const graphcmsToken = process.env.XUE_TOKEN
// export a default function for API route to work
export default async function asynchandler(req, res) {
console.log({graphcmsToken})
const graphQLClient = new GraphQLClient((graphqlAPI), {
headers: {
authorization: `Bearer ${graphcmsToken}`,
},
})
const query = gql`
mutation CreateComment($name: String!, $email: String!, $comment: String!, $slug: String!) {
createComment(data: {name: $name, email: $email, comment: $comment, post: {connect: {slug: $slug}}}) { id }
}
`
try {
const result = await graphQLClient.request(query, req.body)
return res.status(200).send(result)
} catch (error) {
console.log(error)
}
}
-- this my commentform.jsx
components/commentForm.jsx
import React, { useState, useEffect } from 'react';
import { submitComment } from '../services';
const CommentsForm = ({ slug }) => {
const [error, setError] = useState(false);
const [localStorage, setLocalStorage] = useState(null);
const [showSuccessMessage, setShowSuccessMessage] = useState(false);
const [formData, setFormData] = useState({ name: null, email: null, comment: null, storeData: false });
useEffect(() => {
setLocalStorage(window.localStorage);
const initalFormData = {
name: window.localStorage.getItem('name'),
email: window.localStorage.getItem('email'),
storeData: window.localStorage.getItem('name') || window.localStorage.getItem('email'),
};
setFormData(initalFormData);
}, []);
const onInputChange = (e) => {
const { target } = e;
if (target.type === 'checkbox') {
setFormData((prevState) => ({
...prevState,
[target.name]: target.checked,
}));
} else {
setFormData((prevState) => ({
...prevState,
[target.name]: target.value,
}));
}
};
const handlePostSubmission = () => {
setError(false);
const { name, email, comment, storeData } = formData;
if (!name || !email || !comment) {
setError(true);
return;
}
const commentObj = {
name,
email,
comment,
slug,
};
if (storeData) {
window.localStorage.setItem('name', name);
window.localStorage.setItem('email', email);
} else {
window.localStorage.removeItem('name');
window.localStorage.removeItem('email');
}
submitComment(commentObj)
.then((res) => {
if (res.createComment) {
if (!storeData) {
formData.name = '';
formData.email = '';
}
formData.comment = '';
setFormData((prevState) => ({
...prevState,
...formData,
}));
setShowSuccessMessage(true);
setTimeout(() => {
setShowSuccessMessage(false);
}, 3000);
}
});
};
return (
);
};
export default CommentsForm;
I don't know how to get this working and sorry for my bad english. Let me know if you need more info
edit:
this is my schema I don't know if im missing something
import { request, gql } from 'graphql-request';
const graphqlAPI = process.env.NEXT_PUBLIC_GRAPHCMS_ENDPOINT;
export const getPosts = async () => {
const query = gql`
query MyQuery {
postsConnection {
edges {
cursor
node {
author {
bio
name
id
photo {
url
}
}
createdAt
slug
title
excerpt
featuredImage {
url
}
categories {
name
slug
}
}
}
}
}
`;
const result = await request(graphqlAPI, query);
return result.postsConnection.edges;
}
export const getRecentPosts = async () => {
const query = gql`
query getPostDetails() {
posts(
orderBy: createdAt_ASC
last: 3
) {
title
featuredImage {
url
}
createdAt
slug
}
}
`;
const result = await request(graphqlAPI, query);
return result.posts;
}
export const getSimilarPosts = async ( categories, slug ) => {
const query = gql`
query GetPostDetails($slug: String!, $categories: [String!]) {
posts(
where: { slug_not: $slug, AND: { categories_some: {slug_in: $categories} } }
last: 3
) {
title
featuredImage {
url
}
createdAt
slug
}
}
`
const result = await request(graphqlAPI, query, { categories, slug });
return result.posts
}
export const getCategories = async () => {
const query = gql`
query GetCategories {
categories {
name
slug
}
}
`
const result = await request(graphqlAPI, query)
return result.categories
}
export const getPostDetails = async (slug) => {
const query = gql`
query GetPostDetails($slug : String!) {
post(where: {slug: $slug}) {
title
excerpt
featuredImage {
url
}
author{
name
bio
photo {
url
}
}
createdAt
slug
content {
raw
}
categories {
name
slug
}
}
}
`;
const result = await request(graphqlAPI, query, { slug })
return result.post
}
export const submitComment = async (obj) => {
const result = await fetch('/api/comments', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(obj),
})
return result.json()
}
I assume you are using graphcms. Go to the graphcms dashboard and set up a relationship between the Post and Comment identities.
If you check well in the Schema>Post section at the end there should be a relationship with the comment entity.
graphCMS is complaining that you are trying to assign a comment to a post; when the "Post" entity has no reference to "Comment"
The Relation in graphCMS is called a Reference. From the "Post" entity assign a reference to "Comment"
Related
I'm using ReactJS to build a blog app. I can use axios get, put, delete but NOT POST. Every time I post a new blog, it gives me server responded with a status of 500 (Internal Server Error).
I have been struggle with this issue for a week and couldn't figure out the reason. Thank you very much for your help! Let me know if you need additional information.
Here are my codes:
API
import axios from 'axios'
const baseUrl = `/api/blogs`
let token = null
const setToken = newToken => {
token = `bearer ${newToken}`
}
const getAll = () => {
const request = axios.get(baseUrl)
return request.then(response => response.data)
}
const create = async newBlog => {
const config = {headers: { Authorization: token }}
const response = await axios.post(baseUrl, newBlog, config)
return response.data
}
const update = async (id, newObject) => {
const request = axios.put(`${baseUrl}/${id}`, newObject)
const response = await request
return response.data
}
const remove= async (id) => {
const config = {headers: { Authorization: token }}
const request = axios.delete(`${baseUrl}/${id}`, config)
const response = await request
return response.data
}
const exportedObject = { getAll, create, update, setToken, remove }
export default exportedObject
Frontend App.js
import React, { useState, useEffect, useRef } from 'react'
import blogService from './services/blogs'
import loginService from './services/login'
import Blog from './components/Blog'
import LoginForm from './components/LoginForm'
import BlogForm from './components/BlogForm'
import Togglable from './components/Togglable'
import Notification from './components/Notification'
import axios from 'axios'
const App = () => {
const [blogs, setBlogs] = useState([])
const [username, setUsername] = useState('')
const [password, setPassword] = useState('')
const [user, setUser] = useState(null)
const [loginVisible, setLoginVisible] = useState(false)
const [notificationText, setNotificationText] = useState("")
const [notificationStyle, setNotificationStyle] = useState("notification")
const [Toggle, setToggle] = useState(false)
const BlogFormRef = useRef()
useEffect(() => {
const Data = async () => {
const initialBlogs = await blogService.getAll()
setBlogs( initialBlogs )
}
Data()
}, [])
useEffect(() => {
const loggedUserJSON = window.localStorage.getItem('loggedBlogUser')
if (loggedUserJSON) {
const user = JSON.parse(loggedUserJSON)
setUser(user)
blogService.setToken(user.token)
}
}, [])
const addBlog = async (blogObject) => {
BlogFormRef.current.toggleVisibility()
if (blogObject.title !== '' && blogObject.author !== '' && blogObject.url !== '') {
const newBlog = await blogService.create(blogObject)
setBlogs(blogs.concat(newBlog))
setNotificationStyle('notification')
setNotificationText(`A new blog ${blogObject.title} by ${blogObject.author} is added`)
setToggle(!Toggle)
setTimeout(() => {
setToggle(false)
}, 5000)
setBlogs('')
console.log(blogObject)
document.location.reload()
} else {
setNotificationStyle('Warning')
setNotificationText('You must fill all fields to create a blog')
setToggle(!Toggle)
setTimeout(() => {
setToggle(false)
}, 5000)
}
}
Backend
const blogsRouter = require('express').Router()
const Blog = require('../models/blog')
const User = require('../models/user')
const jwt = require('jsonwebtoken')
const middleware = require("../utils/middleware")
blogsRouter.get('/', async (request, response) => {
const blogs = await Blog.find({}).populate('user', { username: 1, name: 1 })
response.json(blogs)
})
blogsRouter.get('/:id', (request, response) => {
Blog.findById(request.params.id)
.then(blog => {
if (blog) {
response.json(blog)
} else {
response.status(404).end()
}
})
})
blogsRouter.post('/', middleware.userExtractor, async (request, response) => {
const body = request.body
const user = request.user
const decodedToken = jwt.verify(request.token, process.env.SECRET)
if (!decodedToken.id){
return response.status(401).json({error: 'token missing or invalid'})
}
if(body.title === undefined){
return response.status(400).send({
error: 'title is missing'
})
}
else if(body.author === undefined){
return response.status(400).send({
error: 'author is missing'
})
}
else if(body.url === undefined){
return response.status(400).send({
error: 'url is missing'
})
}
else{
const blog = new Blog({
title: body.title,
author: body.author,
url: body.url,
likes: body.likes,
user: user.id
})
const savedBlog = await blog.save()
//console.log(savedBlog)
//console.log(user)
user.blogs = user.blogs.concat(savedBlog.id)
await user.save()
const populatedBlog = await savedBlog.populate('user', { username: 1, name: 1 }).execPopulate()
response.status(200).json(populatedBlog.toJSON())
}
})
blogsRouter.delete('/:id', middleware.userExtractor, async (request, response) => {
const blog = await Blog.findByIdAndRemove(request.params.id)
const user = request.user
const decodedToken = jwt.verify(request.token, process.env.SECRET)
if(! request.token || !decodedToken.id){
return response.status(401).json({error:'token is missing or invalid'})
}
else if(blog.user.toString() === user.id.toString()){
await Blog.findByIdAndRemove(request.params.id)
response.status(204).end()
}
else{
return response.status(401).json({error:'cannot process deletion'})
}
})
blogsRouter.put('/:id', async (request, response) => {
const body = request.body
const blog = {
title: body.title,
author:body.author,
url: body.url,
likes: body.likes
}
await Blog.findByIdAndUpdate(request.params.id, blog, { new: true })
.then(updatedBlog => {
response.json(updatedBlog)
})
})
module.exports = blogsRouter
Mongoose
const mongoose = require('mongoose')
const blogSchema = new mongoose.Schema({
title: {type:String,
required: true},
author:{type:String,
required: true},
url: {type:String,
required: true},
likes: {type:Number,
default: 0},
user: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User'}
})
blogSchema.set('toJSON', {
transform: (document, returnedObject) => {
returnedObject.id = returnedObject._id.toString()
delete returnedObject._id
delete returnedObject.__v
}
})
const Blog = mongoose.model('Blog', blogSchema)
module.exports = Blog
Additional information: terminate output, the info is actually POST just cannot render in the front
terminal output
I want to return the oNewest posts to oldest.
This is my query:
export const getPosts = async () => {
const query = gql `
query MyQuery {
postsConnection {
edges {
cursor
node {
author {
bio
name
id
photo {
url
}
}
createdAt
slug
title
excerpt
featuredImage {
url
}
categories {
name
slug
}
}
}
}
}
`;
const result = await request(graphqlAPI, query);
return result.postsConnection.edges;
};
You can use the following syntax:
postsConnection (sort: "createdAt:desc") {
Full example:
export const getPosts = async () => {
const query = gql `
query MyQuery {
postsConnection (sort: "createdAt:desc") {
edges {
cursor
node {
author {
bio
name
id
photo {
url
}
}
createdAt
slug
title
excerpt
featuredImage {
url
}
categories {
name
slug
}
}
}
}
}
`;
const result = await request(graphqlAPI, query);
return result.postsConnection.edges;
};
My code looks like this:
interface MutationProps {
username: string;
Mutation: any;
}
export const UseCustomMutation: React.FC<MutationProps> | any = (username: any, Mutation: DocumentNode ) => {
const [functionForDoingAction, { data, loading, error }] = useMutation(
Mutation,
{
variables: {
username,
},
}
);
useEffect(() => {
// fn trigger for change data
functionForDoingAction({
variables: {
username: username,
},
});
console.log(JSON.stringify(data));
console.log(JSON.stringify(error, null, 2));
}, []);
if (loading) return "loading...";
if (error) return `Submission error! ${error.message}`;
return data;
};
export const DisplayUser = () => {
const GET_USER = gql`
mutation GetUser($username: String!) {
getUser(username: $username) {
pfp
username
password
age
CurrentLive
ismod
description
fullname
}
}
`;
const { username }: { username: any } = useParams();
const MyData = UseCustomMutation(username, GET_USER);
console.log(JSON.stringify(MyData));
I wanna a access MyData.pfp but it gives me this error:
TypeError: Cannot read property 'pfp' of undefined
if it matters when i go on e.g. localhost:3000/user/dakepake variable MyData looks like this:
UserProfile.tsx:39 {"getUser":{"pfp":""https://i.pinimg.com/564x/65/25/a0/6525a08f1df98a2e3a545fe2ace4be47.jpg"","username":""dakepake"","password":""mohikanac10"","age":14,"CurrentLive":"""","ismod":false,"description":""this user dont have a bio yet"","fullname":""damjan alimpic"","__typename":"GetUserResponse"}}
How can I fix this?
i fixed this on my own , i just replaced MyData.pfp whit MyData.getUser.pfp and now its working
I want store a new group as an object into the groups entity in the store. Everything works perfectly but the new group is stored as an object not as a string. I am using Mockoon to mock an API and the data type is set to be application/json. Can someone explain to me what might be the possible cause of this behavior? I am quite new on using redux so some input would be really appreciated too.
Thank you
const dispatch = useDispatch();
const initialGroupState = {
id: null,
name: "",
description: "",
members: []
}
const [group, setGroup] = useState(initialGroupState)
const [submitted, setSubmitted] = useState(false);
const handleInputChange = event => {
const { name, value } = event.target;
setGroup({ ...group, [name]: value });
};
const saveGroup = (e) => {
e.preventDefault();
const {name, description} = group;
dispatch(createGroup(name, description))
.then(data => {
setGroup({
id: Math.floor(Math.random() * 10000),
name: data.name,
description: data.description,
});
setSubmitted(true);
})
.catch(e => {
console.log(e);
});
}
const newGroup = () => {
setSubmitted(false);
};
My reducer:
const initialState = []
function groupsReducer(groups = initialState, action) {
const { type, payload } = action;
console.log([...groups]);
switch (type) {
case CREATE_GROUP:
return [...groups, payload];
case RETRIEVE_GROUPS:
return payload;
default:
return groups;
}
};
My actions:
export const createGroup = (name, description) => async (dispatch) => {
try {
const res = await GroupDataService.create({ name, description });
dispatch({
type: CREATE_GROUP,
payload: res.data,
});
console.log(res.data)
return Promise.resolve(res.data);
} catch (err) {
console.log(err)
return Promise.reject(err);
}
};
I'm having a hard time with GraphQL today. Probably encountered every single error possible.
I want to be able to subscribe to websockets in my component so I wrote some code to do this. Subscription works fine and it seems like it work, but the problem I have is how to get the updated values that come from the subscription inside my component?.
const FIELD_QUE = gql`
query fieldChanged($fieldName: String!, $projectId: Int!) {
fieldChanged(fieldName: $fieldName, projectId: $projectId) {
usersEmail
value
projectId
}
}
`;
const FIELD_MUT = gql`
mutation ChangeFieldMutation($fieldName: String!, $projectId: Int!, $value: String!, $usersEmail: String!) {
changeField(fieldName: $fieldName, projectId: $projectId, value: $value, usersEmail: $usersEmail) {
projectId
value
usersEmail
}
}
`;
const withMutation = graphql(FIELD_MUT, {
props: ({ ownProps, mutate }) => ({
changeField: ({ fieldName, value, projectId, usersEmail }) => {
mutate({
variables: { fieldName, value, projectId, usersEmail },
});
},
}),
});
const FIELD_SUB = gql`
subscription onFieldChanged($projectId: Int!){
fieldChanged(projectId: $projectId){
projectId
value
usersEmail
}
}
`;
const withSubscription = graphql(FIELD_QUE, {
name: 'fieldChanged',
options: () => ({
variables: {
projectId: 1,
fieldName: 'description',
},
}),
props: props => ({
subscribeToFieldChange: (params) => {
return props.fieldChanged.subscribeToMore({
document: FIELD_SUB,
variables: {
projectId: params.projectId,
fieldName: params.fieldName,
},
updateQuery: (prev, { subscriptionData }) => {
if (!subscriptionData.data) return prev;
const newValue = subscriptionData.data;
const result = { ...prev, ...newValue };
return result;
},
});
},
}),
});
All I get is this: