Custom type in GraphQL mutation - ecmascript-6

I am using GraphQL js.I want to implement One-to-many association in it.I have two types user and Office.One user has many offices.
userType:
var graphql = require('graphql');
const userType = new graphql.GraphQLObjectType({
name: 'user',
fields :()=>{
var officeType=require('./officeSchema');
return {
_id: {
type: graphql.GraphQLID
},
name: {
type: graphql.GraphQLString
},
age: {
type: graphql.GraphQLString
},
office:{
type:officeType
}
};
}
});
module.exports=userType;
officeSchema:
const officeType = new graphql.GraphQLObjectType({
name: 'office',
fields:()=> {
var userType = require('./userSchema');
return {
_id: {
type: graphql.GraphQLID
},
room: {
type: graphql.GraphQLString
},
location: {
type: graphql.GraphQLString
},
users: {
type: new graphql.GraphQLList(userType),
resolve: (obj,{_id}) => {
fetch('http://0.0.0.0:8082/office/user/'+obj._id, {
method: "GET",
headers: {
'Content-Type': 'application/json'
}
})
.then(function(res) {return res});
}
}
};
}
});
Now the mutation code is as follows:
const Adduser = {
type: userType,
args: {
name: {
type: graphql.GraphQLString
},
age: {
type: graphql.GraphQLString
}
},
resolve: (obj, {
input
}) => {
}
};
const Addoffice = {
type: OfficeType,
args: {
room: {
type: graphql.GraphQLString
},
location: {
type: graphql.GraphQLString
},
users: {
type: new graphql.GraphQLList(userInputType)
}
},
resolve: (obj, {
input
}) => {
}
};
const Rootmutation = new graphql.GraphQLObjectType({
name: 'Rootmutation',
fields: {
Adduser: Adduser,
Addoffice: Addoffice
}
});
This code is throwing error as
Rootmutation.Addoffice(users:) argument type must be Input Type but got: [user].
I want to add the actual fields in database as well as associated tables' fields but couldn't figure out the problem.
Updated:
1-Added GraphQLInputObjectType:
const officeInputType = new graphql.GraphQLInputObjectType({
name: 'officeinput',
fields: () => {
return {
room: {
type: graphql.GraphQLString
},
location: {
type: graphql.GraphQLString
}
}
}
});
const userInputType = new graphql.GraphQLInputObjectType({
name: 'userinput',
fields: () => {
return {
name: {
type: graphql.GraphQLString
},
age: {
type: graphql.GraphQLString
}
}
}
});
2-Added userinputtype instead of usertype in AddOffice.
Now the error is
Rootmutation.Addoffice(user:) argument type must be Input Type but got: userinput.

The problem is that you provided userType as one of the argument types for the Addoffice mutation. userType cannot be an argument type. Instead, you must use an input type.
There are two object types: output and input types. Your userType and officeType are output types. You need to create an input type using GraphQLInputObjectType [docs]. It will likely have very similar fields. You can use that as a type on your argument field.
const userInputType = new graphql.GraphQLInputObjectType({
name: 'UserInput',
fields () => {
return {
_id: {
type: graphql.GraphQLID
},
// ...
};
}
});

Related

Schema/Resolve for nested objects graphql/mongoose

I am using graphql with mongoose and I am trying to access a nested object array in a json of this form:
"Plans": [
{
"id": ...
"name": ...
"frequency": ...
"lastExecuted": ...
"Steps": {
"Step": [
{
"id": ...
"shortDescription": ...
"description": ...
...
},
{...],
}
I created a mongoose model:
const PlanModel = Mongoose.model("Plan", {
name: String,
frequency: GraphQLString,
lastExecuted: String,
Steps: []
})
Intuitively I would insert my Stepmodel in the array, but this is giving me an error.
So I tried populating the array with the resolver:
Plans: {
type: GraphQLList(PlanType),
args: getGraphQLQueryArgs(PlanType),
resolve: (root, args, context, info) => {
return PlanModel
.find()
.populate("Steps")
.populate("Steps.Step")
.exec();
}
},
This is my PlanType:
const PlanType = new GraphQLObjectType({
name: 'Plan',
fields: () => ({
id: {
type: GraphQLID
},
name: {
type: GraphQLString
},
frequency: {
type: GraphQLString
},
lastExecuted: {
type: GraphQLString
},
maintenanceSteps: {
type: GraphQLList(StepType)
},
})
})
My GraphQL query returns an empty array in this case. I know this is a common problem, but I couldn't find any solution for my problem
The solution to my problem was adding another type:
const StepsType = new GraphQLObjectType({
name: 'Steps',
fields: () => ({
Step: {
type: GraphQLList(StepType)
}
})
})
const PlanType = new GraphQLObjectType({
name: 'Plan',
fields: () => ({
_id: {
type: GraphQLID
},
id: {
type: GraphQLString
},
name: {
type: GraphQLString
},
frequency: {
type: GraphQLString
},
lastExecuted: {
type: GraphQLString
},
status: {
type: GraphQLString
},
Steps: {
type: StepsType
},
})
})

Load form data via REST into vue-form-generator

I am building a form, that needs to get data dynamically via a JSON request that needs to be made while loading the form. I don't see a way to load this data. Anybody out here who can help?
JSON calls are being done via vue-resource, and the forms are being generated via vue-form-generator.
export default Vue.extend({
template,
data() {
return {
model: {
id: 1,
password: 'J0hnD03!x4',
skills: ['Javascript', 'VueJS'],
email: 'john.doe#gmail.com',
status: true
},
schema: {
fields: [
{
type: 'input',
inputType: 'text',
label: 'Website',
model: 'name',
maxlength: 50,
required: true,
placeholder: companyList
},
]
},
formOptions: {
validateAfterLoad: true,
validateAfterChanged: true
},
companies: []
};
},
created(){
this.fetchCompanyData();
},
methods: {
fetchCompanyData(){
this.$http.get('http://echo.jsontest.com/key/value/load/dynamicly').then((response) => {
console.log(response.data.company);
let companyList = response.data.company; // Use this var above
}, (response) => {
console.log(response);
});
}
}
});
You can just assign this.schema.fields.placeholder to the value returned by the API like following:
methods: {
fetchCompanyData(){
this.$http.get('http://echo.jsontest.com/key/value/load/dynamicly').then((response) => {
console.log(response.data.company);
this.schema.fields.placeholder = response.data.company
}, (response) => {
console.log(response);
});
}
}

Single JSON argument in mutation

Below I'm trying to set a mutation example with one object-arg credentials. I had this working previously then all the sudden it stopped working failing on the JSON part. Why can't I send json through credentials?
import {
GraphQLSchema,
GraphQLObjectType,
GraphQLString,
GraphQLInt,
GraphQLInputObjectType,
GraphQLNonNull,
graphql
} from 'graphql'
let requestType = new GraphQLInputObjectType({
name: 'Request',
fields: {
name: {type: GraphQLString},
}
})
let responseType = new GraphQLObjectType({
name: 'Response',
fields: {
name: {type: GraphQLString},
age: {type: GraphQLInt}
}
})
let schema = new GraphQLSchema({
query: new GraphQLObjectType({
name: 'Query',
fields: {
author: {
type: GraphQLString,
resolve: (source, args, context, info) => {
return 'Thomas Reggi'
}
}
}
}),
mutation: new GraphQLObjectType({
name: 'Mutation',
fields: {
example: {
type: responseType,
args: {
credentials: {
name: 'credentials',
type: requestType
}
},
resolve: (source, args, context, info) => {
return {
'name': 'Thomas Reggi',
'age': 26
}
}
}
}
})
})
let credentials = { name: "Thomas Reggi" }
let requestString = `
mutation {
example(credentials: ${JSON.stringify(credentials)}) {
name,
age
}
}`
graphql(schema, requestString).then(result => {
console.log(result)
})
Here's the error:
{ errors:
[ Syntax Error GraphQL request (3:25) Expected Name, found String "name: "
2: mutation {
3: example(credentials: {"name":"Thomas Reggi"}) {
^
4: name,
] }
Where does the reference to Name come from? Why is this throwing an error?
Just found out the hard way. You can't have {"name": "Thomas Reggi"} because name is in quotes.
This query works.
mutation {
example(credentials: {name: "Thomas Reggi"}) {
name,
age
}
}

aurelia bridge kendo grid refresh

I'm trying to use Aurelia KendoUi Bridge in my application.
In my code I have a service which returns a new KendoDataSource :
export class KendoDataSource {
ToKendoDataSource(data: any, recordCount: number, pageSize: number, currentPage: number): any {
return {
transport: {
read: (p) => {
p.success({ data: data, recordCount: recordCount });
}
},
pageSize: pageSize,
serverPaging: true,
serverFiltering: true,
serverSorting: true,
schema: {
data: (result) => {
console.log('Transforming data to kendo datasource.');
return result.data;
},
total: (result) => {
return result.recordCount;
}
}
};
}
}
And this is my viewModel:
#inject(HttpService, KendoDataSource, EventAggregator)
export class GroupList {
grid: any;
gridVM: any;
datasource: any;
pageable: any;
subscriber: any;
paginationDetailsRequest: PaginationDetailsRequest;
test: string;
constructor(private httpService: HttpService, private kendoDataSource: KendoDataSource, private eventAggregator: EventAggregator) {
this.httpService = httpService;
this.kendoDataSource = kendoDataSource;
this.eventAggregator = eventAggregator;
this.paginationDetailsRequest = new PaginationDetailsRequest(4, 1);
this.GetGroups(this.paginationDetailsRequest);
this.datasource = {
transport: {
read: {
url: 'PersonGroup/GetGroups',
type: 'POST',
contentType: "application/json; charset=utf-8",
dataType: 'json'
},
parameterMap: function (data, type) {
if (type == "read") {
let paginationDetails = new PaginationDetailsRequest(data.pageSize, data.page);
if(data.sort && data.sort.length > 0){
paginationDetails.orderBy = data.sort[0].field;
paginationDetails.OrderDesc = (data.sort[0].dir == 'desc');
}
console.log(this.datasource);
return JSON.stringify(paginationDetails);
}
}
},
schema: {
data: "data.currentPageData",
total: "data.totalCount"
},
pageSize: 2,
serverPaging: true,
serverFiltering: true,
serverSorting: true
};
};
attached() {
this.subscriber = this.eventAggregator.subscribe('Search', response => {
this.search(response);
});
}
activate() {
this.pageable = {
refresh: true,
pageSizes: true,
buttonCount: 10
};
}
GetGroups(paginationDetails: PaginationDetailsRequest): void {
this.httpService.post('PersonGroup/GetGroups', paginationDetails)
.then(response => response.json())
.then(groups => {
console.log(groups);
if (groups.succeeded) {
this.datasource = this.kendoDataSource.ToKendoDataSource(groups.data.currentPageData, groups.totalCount, groups.pageSize, groups.currentPage);
this.grid.setDataSource(this.datasource); // initialize the grid
}
else {
//TODO: Show error messages on screen
console.log(groups.errors);
}
})
.catch(error => {
//TODO: Show error message on screen.
console.log(error);
});
}
search(searchDetails: Filter) {
console.log(searchDetails);
this.paginationDetailsRequest.filters.push(searchDetails);
console.log(this.paginationDetailsRequest);
this.GetGroups(this.paginationDetailsRequest);
}
detached() {
this.subscriber.dispose();
}
}
I understand that kendo does not have two-way data binding, But I'm trying to find a way to refresh the grid when I filter the data and the data source has changed.
Thanks.
I had this problem and found the solution by creating a new dataSource and assigning it to setDataSource, as follows... Note, getClients() is a search activated by a button click.
Here is the grid:
<ak-grid k-data-source.bind="datasource"
k-pageable.bind="{ input: true, numeric: false}"
k-filterable.bind="true"
k-sortable.bind="true"
k-scrollable.bind="true"
k-widget.bind="clientgrid"
k-selectable.bind="true">
<ak-col k-title="First Name" k-field="firstName" k-width="120px"></ak-col>
<ak-col k-title="Last Name" k-field="lastName" k-width="120px"></ak-col>
<ak-col k-title="Email Address" k-field="primaryEmail" k-width="230px"></ak-col>
</ak-grid>
And here is the code that updates the dataSource
public getClients()
{
console.log("ClientService.getClients");
this.clientService.getClients()
.then(result =>
{
this.clientList = result;
// the new datasource in the next line is displayed
// after the call to setDataSource(ds) below.
let ds: kendo.data.DataSource = new kendo.data.DataSource({
data: this.clientList,
schema: {
model: {
id: "id",
fields: {
firstName: { type: 'string' },
id: { type: 'number' },
lastName: { type: 'string' },
primaryEmail: { type: 'string' }
}
}
},
pageSize: 10
});
this.clientgrid.setDataSource(ds);
this.clientgrid.refresh();
})
.catch(err => console.log("Error returned from getClients " + err));
}
You don't really need to create a brand new datasource. To refresh the grid after changing the underlying data you can just replace the data element in the dataSource like so:
this.clientgrid.dataSource.data(this.datasource.data);

Mongoose many to many relation and circular structure to JSON

I am trying to create a classic Articles/Categories association with mongoose.
Everything works fine, but since I am trying to expose the query results as JSON, I get a Converting circular structure to JSON error.
I know the issue is related in cross referencing models, but I don't know how to solve this.
Here are my model schemas.
var ArticleSchema = new Schema({
created: {
type: Date,
default: Date.now
},
title: {
type: String,
default: '',
trim: true
},
content: {
type: String,
default: '',
trim: true
},
user: {
type: Schema.ObjectId,
ref: 'User'
},
categories: [{
type: Schema.ObjectId,
ref: 'Category'
}]
});
ArticleSchema.statics.load = function(id, cb) {
this.findOne({
_id: id
}).populate('user', 'name username').populate('categories', 'title').exec(cb);
};
/**
* Category Schema
*/
var CategorySchema = new Schema({
created: {
type: Date,
default: Date.now
},
title: {
type: String,
default: '',
trim: true
},
user: {
type: Schema.ObjectId,
ref: 'User'
}
},
{
toObject: { virtuals: true },
toJSON: { virtuals: true }
});
/**
* Virtual Schema
*/
var articles = CategorySchema.virtual('articles');
articles.get(function () {
return Article.find({categories : { $eq: this }});
});
Seems to be like you have circular references, this mean that the json you create is calling it self in somere.. Im not sure if this line could be the problem:
articles.get(function () {
return Article.find({categories : { $eq: this }});
});
why dont you try with a hardcore value in $eq ??