Cannot delete a Mongo document using mutation with Apollo Client - graphql

I am having trouble deleting a MongoDB document using Apollo Client. I don't think my query syntax is the cause because I tested the query in Graphiql and it works fine. This is the error I am getting:
Unhandled Runtime Error
Error: Response not successful: Received status code 500
Call Stack
new ApolloError
node_modules/#apollo/client/errors/index.js (26:0)
Object.error
node_modules/#apollo/client/core/QueryManager.js (127:0)
notifySubscription
node_modules/zen-observable/lib/Observable.js (140:0)
onNotify
node_modules/zen-observable/lib/Observable.js (179:0)
SubscriptionObserver.error
node_modules/zen-observable/lib/Observable.js (240:0)
eval
node_modules/#apollo/client/utilities/observables/iteration.js (4:48)
Array.forEach
<anonymous>
iterateObserversSafely
node_modules/#apollo/client/utilities/observables/iteration.js (4:0)
Object.error
node_modules/#apollo/client/utilities/observables/Concast.js (35:42)
notifySubscription
node_modules/zen-observable/lib/Observable.js (140:0)
onNotify
node_modules/zen-observable/lib/Observable.js (179:0)
SubscriptionObserver.error
node_modules/zen-observable/lib/Observable.js (240:0)
eval
node_modules/#apollo/client/link/http/createHttpLink.js (110:0)
This is my code for the back end:
const CompanyType = new GraphQLObjectType({
name: 'Company',
fields: () => ({
_id: { type: GraphQLString },
name: { type: GraphQLString },
description: { type: GraphQLString },
users: {
type: new GraphQLList(UserType),
resolve(parentValue, args) {
return User.findUsers(parentValue._id);
},
},
}),
});
const mutation = new GraphQLObjectType({
name: 'Mutation',
fields: {
deleteCompany: {
type: CompanyType,
args: { _id: { type: new GraphQLNonNull(GraphQLString) } },
resolve(parentValue, { _id }) {
return Company.remove({ _id }).catch((err) => console.log(err));
},
},
},
});
This is my code for my React frontend
import React from 'react';
import { gql, useMutation } from '#apollo/client';
const DELETE_COMPANY = gql`
mutation DeleteCompany($id: String!) {
deleteCompany(_id: $id) {
_id
}
}
`;
const CompanyList = () => {
const { loading: loadingList, error: errorList, data: dataList } = useQuery(
COMPANY_LIST
);
const [
deleteCompany,
{ loading: loadingDelete, error: errorDelete, data: dataDelete },
] = useMutation(DELETE_COMPANY);
const renderCompanies = () =>
dataList.companies.map((company) => (
<li key={company._id}>
{company.name}
<button
onClick={() => {
deleteCompany({ variables: { _id: company._id } });
}}
>
delete
</button>
</li>
));
return (
<div>
{loadingList || loadingDelete ? <h1>Loading...</h1> : renderCompanies()}
</div>
);
};

Related

How do I build a custom graphql query with support for Mongodb aggregations in Strapi?

I tried building a custom graphql query with Strapi as per below:
module.exports = {
definition: `
type flatOnts {
site_name: String
unit_no: String
firstname: String
lastName: String
description: String
isp_name: String
serial_number: String
status: Boolean
}
`,
query: `
flattenOntObj: [flatOnts]
`,
type: {},
resolver: {
Query: {
flattenOntObj: {
description: "Return a flat ont object",
resolverOf: "application::onts.onts.aggregate",
resolver: async (obj, options, ctx) => {
const res = await strapi.api.onts.services.onts.aggregate([
{
$lookup: {
from: "onts",
localField: "ont",
foreignField: "_id",
as: "ont_details",
},
},
{
$replaceRoot: {
newRoot: {
$mergeObjects: [
{
$arrayElemAt: ["$ont_details", 0],
},
"$$ROOT",
],
},
},
},
]);
console.log(res);
},
},
},
},
};
However, upon running this in the Graphql playground, I am presented with the "forbidden" error.
Any ideas or pointers?
Appreciate any assistance.
Nevermind, I got it right. I missed a section on the Strapi documentation that explains it: https://strapi.io/documentation/3.0.0-beta.x/concepts/queries.html#custom-queries
In the folder: api/model/services/model.js (my case: api/onts/services/ont.js)
module.exports = {
aggregate: async (aggArray) => {
const res = await strapi.query("ont").model.aggregate(aggArray);
return res;
},
};
and then in api/onts/config/schema.graphql.js:
module.exports = {
definition: `
type flatOnts {
site_name: String
unit_no: String
firstname: String
lastName: String
description: String
isp_name: String
serial_number: String
status: Boolean
}
`,
query: `
flattenOntObj: [flatOnts]
`,
type: {},
resolver: {
Query: {
flattenOntObj: {
description: "Return a flat ont object",
// policies: ["plugins::users-permissions.isAuthenticated"],
resolverOf: "application::onts.onts.find",
resolver: async (obj, options, ctx) => {
const aggregationArray = [
{
$lookup: {
from: "onts",
localField: "ont",
foreignField: "_id",
as: "ont_details",
},
},
{
$replaceRoot: {
newRoot: {
$mergeObjects: [
{
$arrayElemAt: ["$ont_details", 0],
},
"$$ROOT",
],
},
},
];
const res = await strapi.api.onts.services.onts.aggregate(
aggregationArray
);
return res;
},
},
},
},
};

Unknown column 'getContent.movie_id' in 'field list

my whole schema
const Films = new GraphQLObjectType({
name: 'films',
interfaces: () => [MovieStream],
fields: () => ({
movie_id: {
type: GraphQLString,
},
id:{
type: GraphQLID
},
name: {
type: GraphQLString,
},
})
})
Films._typeConfig = {
sqlTable: "films",
uniqueKey: 'id',
}
const MovieStream = new GraphQLInterfaceType({
name: 'MovieStream',
fields: () => ({
id: {
type: GraphQLID,
},
movie_id: {
type: GraphQLString,
},
})
})
MovieStream._typeConfig = {
sqlTable: "movie_streams",
uniqueKey: 'id'
}
const QueryRoot = new GraphQLObjectType({
name: 'Query',
fields: () => ({
getContentList:{
type: new GraphQLList(Films),
args: {
id: {
type: GraphQLInt
},
permalink: {
type: GraphQLString
},
language: {
type: GraphQLString
},
content_types_id: {
type: GraphQLString
},
oauth_token:{
type: GraphQLString
}
},
resolve: (parent, args, context, resolveInfo) => {
return joinMonster.default(resolveInfo,{}, sql => {
return FilmDb.query(sql).then(function(result) {
return result[0];
});
} ,{dialect: 'mysql'});
},
}
})
})
module.exports = new GraphQLSchema({
query: QueryRoot
})
I have again modified my code still got the error
{
"errors": [
{
"message": "Unknown column 'getContent.movie_id' in 'field list'",
"locations": [
{
"line": 2,
"column": 3
}
],
"path": [
"getContentList"
]
}
],
"data": {
"getContentList": null
}
}
My previous post Is it possible to fetch data from multiple tables using GraphQLList
Please check and tell me where i am wrong??? I have already add the field still it does not access the field of that object type

Is left join only one way to fetch data using join monster?

const QueryRoot = new GraphQLObjectType({
name: 'Query',
fields: () => ({
getContentDetails: {
type: new GraphQLList(Films),
args: {
id: {
type: GraphQLInt
},
permalink: {
type: GraphQLString
},
studio_id: {
type: GraphQLString
},
content_types_id: {
type: GraphQLString
}
},
where: (filmTable, args, context) => {
return ` ${filmTable}.permalink = "${args.permalink}" and ${filmTable}.content_types_id = "${args.content_types_id}"`
},
resolve: (parent, args, context, resolveInfo) => {
return joinMonster.default(resolveInfo, {}, sql => {
return FilmDb.query(sql).then(function(result) {
return result[0];
});
},{dialect: 'mysql'});
}
}
})
})

graphql mutation & couchbase

I'm starting working with graphQL with couchbase, and I have a small problem when I run a mutation, what I'm doing is save 2 object:
key: email#email.it
{
type: 'credential',
user_id: 'xxxx-xxxx-xxxx-xxxx',
password: 'jknelkjf'
}
key: xxxx-xxxx-xxxx-xxxx
{
type: 'user',
name: 'aaaa',
surname: 'bbbb'
}
this is my mutation function:
export default {
createUser: {
type: User,
args: {
email: { type: GraphQLString },
password: { type: GraphQLString },
name: { type: GraphQLString },
surname: { type: GraphQLString }
},
resolve(source, args, req) {
const _id = uuid();
return new Promise((resolve, reject) => {
bcrypt.hash(args.password, 10)
.then(hash => req.db.insert({}, args.email, {
password: hash,
user_id: _id,
type: "credential"
}))
.then(cred => req.db.insert({}, cred.user_id, {
name: args.name,
surname: args.surname,
type: "user"
}))
.then(user => {
return resolve(user);
})
.catch(err => {
return reject(err);
});
});
}
}
}
and these are my schemas
export const UserCredential = new GraphQLObjectType({
name: 'UserCredential',
fields: () => ({
user_id: { type: GraphQLString },
type: { type: GraphQLString },
id: { type: GraphQLString },
password: { type: GraphQLString }
})
});
export const User = new GraphQLObjectType({
name: 'User',
fields: () => ({
name: { type: GraphQLString },
surname: { type: GraphQLString },
type: { type: GraphQLString },
id: { type: GraphQLString },
credential: {
type: UserCredential,
resolve: (root, args, req) => {
const query = `SELECT META(credential).id,credential.* FROM {{bucket}} as credential WHERE credential.type="credential" AND credential.user_id=$1`;
return new Promise((resolve, reject) => {
req.db.runQuery(null, query, [root.id])
.then((res) => {
return resolve(res[0]);
})
.catch((err) => {
return reject(err);
})
});
}
}
})
});
the problem is that when I run the mutation the result is the user object with the credential field null, but if I add a timeout on the resolve of the mutation I get the user with the credential object...the insert function is something like this:
db.insert(result => {
return db.find(result.id)
})
do you have any advice?

Relay flavoured graphql mutation validation errors

I've greated a simple relay flavoured mutation that works just fine. I've got a simple client side component that commits the mutation with the required data.
My question is how do I send back multiple errors to the client? Currently I can simply throw an error (or reject a promise) in mutateAndGetPayload and I will receive an error on the client side, but this currently only works with a string message. Should I simply reject the promise with a JSON string of an errors array? Or is there a better way?
const createCashAccountMutation = mutationWithClientMutationId({
name: 'CreateCashAccount',
inputFields: {
name: {
type: new GraphQLNonNull(GraphQLString),
description: 'Cash account name'
},
code: {
type: GraphQLString,
description: 'Optional code'
},
businessId: {
type: new GraphQLNonNull(GraphQLString),
description: 'Business ID'
},
currencyId: {
type: new GraphQLNonNull(GraphQLString),
description: 'Currency ID'
},
isActive: {
type: new GraphQLNonNull(GraphQLInt)
}
},
outputFields: {
name: {
type: GraphQLString,
resolve: (payload) => payload.name
},
code: {
type: GraphQLString,
resolve: (payload) => payload.code
},
businessId: {
type: GraphQLString,
resolve: (payload) => payload.businessId
},
currencyId: {
type: GraphQLString,
resolve: (payload) => payload.currencyId
},
isActive: {
type: GraphQLString,
resolve: (payload) => payload.isActive
}
},
mutateAndGetPayload: async (options) => {
throw 'wtf';
return options;
}
});
Update 1.
I've come up with the following example:
const graphQLCashAccount = new GraphQLObjectType({
name: 'cashAccount',
fields: {
name: {
type: GraphQLString,
resolve: (payload) => payload.name
},
code: {
type: GraphQLString,
resolve: (payload) => payload.code
},
businessId: {
type: GraphQLString,
resolve: (payload) => payload.businessId
},
currencyId: {
type: GraphQLString,
resolve: (payload) => payload.currencyId
},
isActive: {
type: GraphQLString,
resolve: (payload) => payload.isActive
}
}
});
const graphQLErrors = new GraphQLList(new GraphQLObjectType({
name: 'errors',
fields: {
key: {
type: GraphQLString,
resolve: (payload) => payload.key
},
message: {
type: GraphQLString,
resolve: (payload) => payload.message
}
}
}));
const graphQlInput = new GraphQLInputObjectType({
name: 'data',
fields: {
name: {
type: new GraphQLNonNull(GraphQLString),
description: 'Cash account name'
},
code: {
type: GraphQLString,
description: 'Optional code'
},
businessId: {
type: new GraphQLNonNull(GraphQLString),
description: 'Business ID'
},
currencyId: {
type: new GraphQLNonNull(GraphQLString),
description: 'Currency ID'
},
isActive: {
type: new GraphQLNonNull(GraphQLInt)
}
}
});
const createCashAccountMutation = mutationWithClientMutationId({
name: 'CreateCashAccount',
inputFields: {
data: {
type: graphQlInput
}
},
outputFields: {
data: {
type: graphQLCashAccount,
resolve: (payload) => payload.data
},
errors: {
type: graphQLErrors,
resolve: (payload) => payload.errors
}
},
mutateAndGetPayload: async (options) => {
const payload = {
errors: [{ key: 'asd', message: 'asd failed' }],
data: options
};
return payload;
}
});
This will actually resolve the transaction and simply return 2 fields, a data field and an errors field. One of them will be populated.
Is this a better approach? I'm stumped on how I should apply the update in Relays fatquery though.
Update 2.
Relay Mutation client side example.
export class NewCashAccountMutation extends Relay.Mutation {
getMutation () {
return Relay.QL`mutation {
createCashAccount
}`;
}
getVariables() {
return { data: this.props.cashAccount };
}
getFatQuery() {
return Relay.QL`
fragment on CreateCashAccountPayload {
data, errors
}
`;
}
getConfigs() {
return [{
type: 'FIELDS_CHANGE',
fieldIDs: {
data: this.props.cashAccount.id,
},
}];
}
}

Resources