Post validation failed: title: Path `title` is required.", in graphql - graphql

I trying to add mutation in graphql-yoga but every time I try to mutate the I get error saying
Post validation failed: title: Path title is required.",
I have no idea why.
Here is my code
resolver
Mutation: {
createPost: async(root, args, ctx) => {
console.log(args)
try {
const post = new Post({
title: args.title,
description: args.description,
content: args.content
});
const result = await post.save();
console.log(result);
return result
}catch(err) {
throw err
}
}
}
schema
input postInput{
title: String!
description: String!
content: String!
}
type Mutation {
createPost(input: postInput): Post!
}
This works fine if I remove the input type and directly do like this
type Mutation {
createPost(title: String!,description: String!,content: String!): Post!
}
log result
{ input:
[Object: null prototype] {
title: 'with input',
description: 'this is de',
content: 'this is conte' } }
Here Why am I getting [Object: null prototype]?

You have to send your data in your resolver like this if you give input type like this on schema:
const post = new Post({
title: args.input.title,
description: args.input.description,
content: args.input.content
});
It means, in args, we need a parameter called input which is of type Post.
And while giving the datas on graphql gui send data like this:
mutation {
createPost(input:{
title: 'with input',
description: 'this is de',
content: 'this is conte'}) {
//return your id or others
}
}

Related

Creating two types of data at once in a single resolver (Graphql + Prisma)

When a user creates a data of type Post, I need the graphql server to automatically create a data of type Commit as well. The type Commit connects to type User and type Post. Here is the graphql pattern for type User, type Post, and type Commit:
type User {
id: ID!
username: String!
commits: [Commit!]!
}
type Post {
id: ID!
title: String!
content: String
commits: [Commit!]!
}
type Commit {
id: ID!
user: User!
post: Post!
}
So I made a createPost mutation. The createPost mutation must do two jobs at once: creating the Post, and then creating the Commit. The Commit data should connect to the newly created Post data. Below is the resolver that I have came up with until now:
Mutation: {
createPost: async (_, args) => {
const {user, title, content} = args;
await prisma.createPost({
title,
content
});
const postId = await prisma.post({title}).id();
await prisma.createCommit({
user: {connect: {id: user.id}},
post: {connect: {id: postId }}
});
const newPost = await prisma.post({id:postId});
return newPost;
}
}
Is this an effective way? Or is there a better way to do this?
I think this would work as well:
Mutation: {
createPost: async (_, args) => {
const {user, title, content} = args;
const post = await prisma.createPost({
title,
content
});
await prisma.createCommit({
user: {connect: {id: user.id}},
post: {connect: {id: post.id }}
});
return post;
}
}
Prisma returns the record created so you don't need to query for it again.

Post data to a graphql server with request-promise

I'm using the request-promise library to make http request to a graphql server. To achieve a query, I'm doing this:
const query = `
{
user(id:"123173361311") {
_id
name
email
}
}
`
const options = {
uri: "http://localhost:5000/graphql",
qs: { query },
json: true
}
return await request(options)
The above code is working fine. However I'm confused about how to go about a mutation since I need to specify both the actual mutation and the inputData like this:
// Input
{
name: "lomse"
email: "lomse#lomse.com"
}
const mutation = `
mutation addUser($input: AddUserInput!){
addUser(input: $input) {
_id
name
email
}
}
`
const option = {
uri: "http://localhost:5000/graphql",
formData: {mutation},
json: true,
// how to pass the actual data input
}
request.post(option)
Or is it that the request-promise library isn't designed for this use case?
Use body, not formData. Your body should consist of three properties:
query: The GraphQL document you're sending. Even if the operation is a mutation, the property is still named query.
variables: A map of your variable values serialized as a JSON object. Only required if your operation utilized variables.
operationName: Specifies which operation to execute. Only required if your document included multiple operations.
request.post({
uri : '...',
json: true,
body: {
query: 'mutation { ... }',
variables: {
input: {
name: '...',
email: '...',
},
},
},
})
The graphql-request library seems to do what I needed the request-promise library to do.
import { request } from 'graphql-request'
const variables = {
name: "lomse",
email: "lomse#lomse.com"
}
const mutation = `
mutation addUser($input: AddUserInput!){
addUser(input: $input) {
_id
name
email
}
}
`
response = await request(uri, mutation, {input: variables})

How to configure endpoint and custom graphql query in React-Admin

I'm setting up a react-admin app, that needs to connect with a Hasura Service using a graphql provider. To do so, I need to pass for the provider the endpoint "/v1/graphql" and the query with the selects subfields. Like this:
query MyQuery {
account_customers {
customer_id
email
given_name
}
}
I tried to use the Hasura Provider (https://github.com/hasura/ra-data-hasura/) but the requisitions are going to "/v1/query", and I couldn't found how to change it. Also couldn't figure out how to send my custom query with the subfields.
I also tried to use ra-data-graphql-simple provider, to override a query
to get the resource with the subfields.
/providers/myProvider.js
import buildGraphQLProvider, { buildQuery } from 'ra-data-graphql-simple';
import gql from 'graphql-tag';
const myBuildQuery = introspection => (fetchType, resource, params) => {
const builtQuery = buildQuery(introspection)(fetchType, resource, params);
if (resource === 'account_customers' && fetchType === 'GET_LIST') {
return {
// Use the default query variables and parseResponse
...builtQuery,
// Override the query
query: gql`
query ($id: ID!) {
account_customers {
customer_id
email
name
}
}`,
};
}
return builtQuery;
}
export default buildGraphQLProvider({ buildQuery: myBuildQuery })
App.js
import buildGraphQLProvider from './providers/myProvider.js';
class App extends Component {
constructor() {
super();
this.state = { dataProvider: null };
}
componentDidMount() {
buildGraphQLProvider({ clientOptions: { uri: 'http://localhost:8080/v1/graphql' }})
.then(dataProvider => this.setState({ dataProvider }));
}
render() {
const { dataProvider } = this.state;
return (
<div className="App">
<Admin dataProvider={dataProvider} >
<Resource name="account_customers" list={ListGuesser} />
</Admin>
</div>
);
}
}
export default App;
But I'm getting the error:
"Unknown resource account_customers. Make sure it has been declared on your server side schema. Known resources are "
I have had a similar issue.
The react-admin data provider you're using expects a certain shape of the GraphQL API, so it can get all items, create an item, update an item etc.
I have solved it by making sure that my schema complies with this:
type Query {
Post(id: ID!): Post
allPosts(page: Int, perPage: Int, sortField: String, sortOrder: String, filter: PostFilter): [Post]
_allPostsMeta(page: Int, perPage: Int, sortField: String, sortOrder: String, filter: PostFilter): ListMetadata
}
type Mutation {
createPost(
title: String!
views: Int!
user_id: ID!
): Post
updatePost(
id: ID!
title: String!
views: Int!
user_id: ID!
): Post
deletePost(id: ID!): Post
}
type Post {
id: ID!
title: String!
views: Int!
user_id: ID!
User: User
Comments: [Comment]
}
input PostFilter {
q: String
id: ID
title: String
views: Int
views_lt: Int
views_lte: Int
views_gt: Int
views_gte: Int
user_id: ID
}
type ListMetadata {
count: Int!
}
So in your case, you would need these endpoints (and change the naming in your backend):
AccountCustomer
allAccountCustomers
_allAccountCustomersMeta
updateAccountCustomer
createAccountCustomer
deleteAccountCustomer
etc...

how do I shape my graphql backend response?

I am querying my graphql backend and need the response to have a flatten shape,
my query:
gql`
{
questions {
edges {
id
title
author: user {
email
}
}
}
}
`
my response:
'5d3eafb7889a135ff8cd950c': {
id: '5d3eafb7889a135ff8cd950c',
title: 's',
author: {
email: 'dggdfgdgfd#gmail.com',
__typename: 'User'
},
__typename: 'Question'
},
problem is with author, I need as a string instead of an object:
id: '5d3eafb7889a135ff8cd950c',
title: 's',
author: 'dggdfgdgfd#gmail.com' // <===
`
You have two options:
1) After getting the data from the GraphQL server, transform the data as you need to fit your needs. A Javascript implementation might be:
function flattenGqlResponse (response) {
return Object.keys(response).map((question) => {
return {
id: response[question].id,
title: response[question].title,
author: response[question].author.email
}
}
);
}
2) Flatten the structure in your GraphQL Resolver on your GraphQL Server. Likely, you do not want to pursue this route based on what I see about your schema, unless your User object only has one field, that is email

I am querying for the author with particular '_id' but it displaying the all authors [Graphql]

I have defined Author as below:
const Author = new GraphQLObjectType({
name: 'Author',
description: 'Represent the type of an author of a blog post or a comment',
fields: () => ({
_id: {type: GraphQLString},
name: {type: GraphQLString},
posts: {type: Post}
})
});
I have defined my Query as below
const Query = new GraphQLObjectType({
name: "Root_Query",
fields: {
authors: {
type: new GraphQLList(Author),
args: {_id: { type: GraphQLString },name:{type: GraphQLString}},
resolve: function(rootValue, args, info) {
let fields = {};
let fieldASTs = info.fieldASTs;
fieldASTs[0].selectionSet.selections.map(function(selection) {
fields[selection.name.value] = 1;
});
return authorsCollection.find({}, fields).toArray();
}
}
Now when I query for author with particular id by using the query given below
{
authors(_id: "57c5794a92aef65040c4e0e6"){
_id
name
}
}
Instead of displaying author with _id 57c5794a92aef65040c4e0e6 .It is displaying all the authors _id and name. How can I solve the problem??
The problem is with the following DB code, which fetches all authors because of empty query {}:
return authorsCollection.find({}, fields).toArray()
Add _id to your query:
// import {ObjectID} from 'mongodb';
const authorId = ObjectID.createFromHexString(args._id);
return authorsCollection.find({_id: authorId}, fields).toArray()
You have to

Resources