Hey Team,
I am trying to play around with the newest release of Meteor (2.7.1) and Apollo, for the GraphQL richness, but am really struggling with the mutations side of things.
When trying to add a simple database insert I get “Error: GraphQL error: Meteor code must always run within a Fiber. Try wrapping callbacks that you pass to non-Meteor libraries with Meteor.bindEnvironment.”
GraphQL file:
type Device {
_id: ID!
mac: String!
name: String
}
type Query {
getDevice (id: ID!): Device
getDevices: [Device]
}
type Mutation {
createDevice( mac: String!, name: String! ): Device
}
Database file:
import { Mongo } from 'meteor/mongo';
const deviceCollection = Object.assign(new Mongo.Collection('devices'), {
save({ mac, name }) {
const newDeviceId = this.insert({
mac,
name,
createdAt: new Date(),
});
return this.findOne(newDeviceId);
}
});
export { deviceCollection as DeviceCollection }
Resolvers File:
import { DeviceCollection } from '../../api/Devices/devices';
import deviceSchema from './devices.graphql';
export default {
Query: {
getDevice: async (obj, { id }) => DeviceCollection.findOne(id),
getDevices: async () => DeviceCollection.find({}).fetch()
},
Mutation: {
createDevice( obj, { mac, name }, context ) {
return DeviceCollection.save({ mac, name });
}
}
};
Server File:
import { Meteor } from 'meteor/meteor';
import { startApolloServer } from './apollo';
try {
startApolloServer().then();
} catch (e) {
console.error(e.reason);
}
Meteor.startup(() => {
});
Apollo file:
import { ApolloServer } from 'apollo-server-express';
import { WebApp } from 'meteor/webapp';
import { getUser } from 'meteor/apollo';
import merge from 'lodash/merge';
import { DeviceCollection } from '../../api/Devices/devices';
import deviceSchema from '../../api/Devices/devices.graphql';
import deviceResolvers from '../../api/Devices/resolvers';
const typeDefs = [
deviceSchema
];
const resolvers = merge(
deviceResolvers
);
const server = new ApolloServer({
typeDefs,
resolvers,
context: async ({ req }) => ({
user: await getUser(req.headers.authorization)
})
});
export async function startApolloServer() {
await server.start();
const app = WebApp.connectHandlers;
server.applyMiddleware({
app,
cors: true
});
}
App file:
import React from "react";
import gql from "graphql-tag";
import { graphql } from "react-apollo";
import DeviceForm from "./DeviceForm";
const deviceQuery = gql`
{
getDevices {
_id
mac
name
}
}
`;
const App = ({ data }) => {
if (data.loading) return <h1>Loading</h1>;
return (
<div>
<h1>Hello</h1>
<DeviceForm refetch={data.refetch} />
<ul>
{data.getDevices.map(device => (
<li key={device._id}>{device.name}</li>
))}
</ul>
</div>
)
};
export default graphql(deviceQuery)(App);
Device Form:
import React, { Component } from "react";
import gql from "graphql-tag";
import { graphql } from "react-apollo";
const createDevice = gql`
mutation createDevice( $mac: String!, $name: String! ) {
createDevice( mac: $mac, name: $name ) {
_id
}
}
`;
class DeviceForm extends Component {
submitForm = () => {
this.props.createDevice({
variables: {
mac: this.mac.value,
name: this.name.value
},
refetch: () => ['getDevices']
}).then(({ data }) => {
//this.props.refetch();
}).catch( error => {
console.log( error );
});
};
render() {
return (
<div>
<input type="text" ref={input => (this.mac = input)}/>
<input type="text" ref={input => (this.name = input)}/>
<button onClick={this.submitForm}>Create</button>
</div>
)
}
}
export default graphql(createDevice, {
name: "createDevice"
})(DeviceForm)
The app compiles and everything looks fine, until you click “create” and it tries to insert a new entry into the devices database.