cult-of-coders / apollo Goto Github PK
View Code? Open in Web Editor NEWMeteor & Apollo integration
License: MIT License
Meteor & Apollo integration
License: MIT License
Is it possible to have both a meteor DDP connection open, and an apollo GraphQL connection open. Yes, I am talking about two separate connections, I guess.
Here is why: My client will be a react-native app connecting to a Meteor with Apollo server. I would like to use meteor ddp connection just for reactive connection status (connected/not connected) and meteor user information, and I want to use apollo for everything else. I want to able to know if the client has disconnected from the server.
Is there a better way to achieve this? Should I just set up a polling mechanism?
When I upgraded my meteor application from 1.7 to 1.8 the user object on my Apollo context lost the "profile" object containing the user's name and other profile information. The _id is still added to context and so as a work around I just called Meteor.users.findOne(context.user._id) to get the rest of the information and that works so far but I just wanted to bring it up here. I am not sure why this upgrade would drop only a part of the user object and perhaps it has to do with my accounts set up but it was working fine in 1.7 and then 1.8 the only errors I received had to do with missing information in the user object. Once I implemented the above work around all works as expected.
Hello,
It would be very helpul to have a full example based on the documentation you provide.
It will help understand how everything fits together.
I am trying to use this package to have a simple example with authentification and documents that belongs to a user but I have great difficulties.
Will update this if I manage to do it, but in the meantime, if you can point me to something it would be awesome.
Just leave it behind and implement our own custom integrations.
Also make user object optional to provide.
Hi,
Is there a boilerplate available for this package by any chance? I am currently referencing the grapher-boilerplate, but just checking if is there is an updated boilerplate that includes cult-of-coders/apollo.
Thanks,
-ujwal
@theodorDiaconu Is it not possible to leverage the DDP connection like swydo:ddp-apollo? Or are there good reasons not to?
Following though the documentation and I ran into an issue on the "working with the database" section here: https://github.com/cult-of-coders/apollo/blob/master/docs/db.md
I have a users collection and a form collection. the forms have a userId field. I would assume that following this setup, i should be able to just add in the link and it would work. I have the two collections setup the following way:
type User @mongo(name: "users") {
_id: ID!
firstname: String
lastname: String
fullname: String
}
type Form @mongo(name: "formcollection")
{
_id:ID
firstName: String
userId: ID
author: User @link(field: "userId")
}
type Query {
forms: [Form]
users: [User]
}
Error: [You cannot add the link with name: author because it was already added to formcollection collection]
when i do this, I get the error above. I'm not sure what it means. thanks for any input you may have.
Hi,
after install:
meteor add cultofcoders:apollo
W20180803-10:41:27.398(2)? (STDERR) TypeError: Class extends value undefined is not a constructor or null
W20180803-10:41:27.399(2)? (STDERR) at MongoDirective.js (packages/cultofcoders:grapher-schema-directives/MongoDirective.js:4:45)
W20180803-10:41:27.399(2)? (STDERR) at fileEvaluate (packages/modules-runtime.js:322:7)
W20180803-10:41:27.399(2)? (STDERR) at Module.require (packages/modules-runtime.js:224:14)
W20180803-10:41:27.399(2)? (STDERR) at require (packages/modules-runtime.js:244:21)
W20180803-10:41:27.399(2)? (STDERR) at LinkDirective.js (packages/cultofcoders:grapher-schema-directives/LinkDirective.js:1:472)
W20180803-10:41:27.399(2)? (STDERR) at fileEvaluate (packages/modules-runtime.js:322:7)
W20180803-10:41:27.400(2)? (STDERR) at Module.require (packages/modules-runtime.js:224:14)
W20180803-10:41:27.400(2)? (STDERR) at require (packages/modules-runtime.js:244:21)
W20180803-10:41:27.400(2)? (STDERR) at index.js (packages/cultofcoders:grapher-schema-directives/index.js:1:333)
W20180803-10:41:27.400(2)? (STDERR) at fileEvaluate (packages/modules-runtime.js:322:7)
W20180803-10:41:27.400(2)? (STDERR) at Module.require (packages/modules-runtime.js:224:14)
W20180803-10:41:27.400(2)? (STDERR) at require (packages/modules-runtime.js:244:21)
W20180803-10:41:27.401(2)? (STDERR) at /home/palpinter/Fejlesztés/militia/apollo-server/.meteor/local/build/programs/server/packages/cultofcoders_grapher-schema-directives.js:364:15
W20180803-10:41:27.401(2)? (STDERR) at /home/palpinter/Fejlesztés/militia/apollo-server/.meteor/local/build/programs/server/packages/cultofcoders_grapher-schema-directives.js:369:3
W20180803-10:41:27.401(2)? (STDERR) at /home/palpinter/Fejlesztés/militia/apollo-server/.meteor/local/build/programs/server/boot.js:411:36
W20180803-10:41:27.401(2)? (STDERR) at Array.forEach (<anonymous>)
Thx Pal
import { setContext } from 'meteor/cultofcoders:apollo';
// deep merge
setContext({
db: {
users: Meteor.users
}
})
Hi,
I am evaluating this stack for my next project, and I was really excited to see this project integrating Meteor and Apollo, since I want to have the best of both worlds.
I just ran your example code, but I cannot connect with react-native-meteor. I can connect via the web browser to http://localhost:3000/graphiql just fine, and I can run queries.
However, when I connect from react-native-meteor to ws://<host_name>:3000/websocket, I cannot connect.
This is what I get:
04-09 06:34:00.432 4346 5296 I ReactNativeJS: Connecting to Meteor port at ws://192.168.1.103:3000/websocket
04-09 06:34:00.450 4346 5296 I ReactNativeJS: We are disconnected!!!
04-09 06:34:00.450 4346 5296 I ReactNativeJS: Disconnected from DDP server.
I thought this was still using DDP as the connection protocol? If I run a standard meteor app, I can connect from react-native-meteor just fine.
Any known issues with connecting from react-native-meteor? Maybe I just don't understand this layout well enough...I thought this was both a Meteor server and an Apollo server?
in the file:
apollo/server/core/main-server.js
import { graphqlExpress, graphiqlExpress } from 'apollo-server-express';
are being undefined for:
"apollo-server-express": "^2.0.0",
In addition to #4, it would be nice if our own context
constructor, was provided with the default context. So we can use the context in our injected methods.
import initServices from './services';
initialize({
context: async ({ userId, db }) => ({
services: initServices({ userId, db }),
}),
});
// services
export default ({ userId, db }) => ({
users: {
find: ({ organisation }) => {
const hasAccess = !!db.organisations.findOne({ _id: organisation, members: userId });
if (!hasAccess) {
return [];
}
return db.users.find({ organisation }).fetch();
},
},
});
// resolvers
{
Query: {
getUsers(_, { organisation }, { services }) {
return services.users.find({ organisation });
}
}
}
I have 2 collections: users and groups. I have a main link from groups to users based on memberIds field. I also have an inverse link from users to groups:
I have two users: Ujwal and Vineet. I have 5 groups:
Here are the records:
{
"_id" : "nSkwTyjPFnmmZ6DYY",
"name" : "Ujwal and Vineet",
"description" : "Ujwal is admin",
"createdAt" : ISODate("2018-07-31T22:22:03.607Z"),
"createdBy" : "WaHgrKPe6ePJJuE2o",
"adminIds" : [
"WaHgrKPe6ePJJuE2o"
],
"memberIds" : [
"WaHgrKPe6ePJJuE2o",
"yf2AsaHQN36TqKtFc"
]
}
{
"_id" : "beLXTBrRAXtcf2oZc",
"name" : "Vineet and Ujwal",
"description" : "Vineet is admin",
"createdAt" : ISODate("2018-07-31T22:23:51.461Z"),
"createdBy" : "yf2AsaHQN36TqKtFc",
"adminIds" : [
"yf2AsaHQN36TqKtFc"
],
"memberIds" : [
"WaHgrKPe6ePJJuE2o",
"yf2AsaHQN36TqKtFc"
]
}
{
"_id" : "Ga4is5nwBXugxpRGt",
"name" : "Vineet",
"description" : "Vineet is admin",
"createdAt" : ISODate("2018-07-31T22:24:40.055Z"),
"createdBy" : "yf2AsaHQN36TqKtFc",
"adminIds" : [
"yf2AsaHQN36TqKtFc"
],
"memberIds" : [
"yf2AsaHQN36TqKtFc"
]
}
{
"_id" : "CFycmtemFgSeZNFJA",
"name" : "Ujwal",
"description" : "Ujwal is admin",
"createdAt" : ISODate("2018-07-31T22:25:07.206Z"),
"createdBy" : "WaHgrKPe6ePJJuE2o",
"adminIds" : [
"WaHgrKPe6ePJJuE2o"
],
"memberIds" : [
"WaHgrKPe6ePJJuE2o"
]
}
{
"_id" : "cyqFAhpCA2LzBGhsP",
"name" : "Ujwal and Vineet",
"description" : "Both are admin",
"createdAt" : ISODate("2018-07-31T22:25:50.003Z"),
"createdBy" : "WaHgrKPe6ePJJuE2o",
"adminIds" : [
"WaHgrKPe6ePJJuE2o",
"yf2AsaHQN36TqKtFc"
],
"memberIds" : [
"WaHgrKPe6ePJJuE2o",
"yf2AsaHQN36TqKtFc"
]
}
Here is my GraphQL and grapher setup:
type Group @mongo(name: "groups")
{
_id: ID!
name: String
members: [User] @link(field: "memberIds")
}
type User @mongo(name: "users")
{
_id: ID!
emails: [Email]
firstName: String
lastName: String
name: String
roles: [String]
groups: [Group] @link(to: "members")
}
I can query via the main link to get all groups and the members in them:
query groups {
groups{
_id
name
members {
_id
firstName
lastName
name
}
}
}
Result:
{
"data": {
"groups": [
{
"_id": "nSkwTyjPFnmmZ6DYY",
"name": "Ujwal and Vineet",
"description": "Ujwal is admin",
"members": [
{
"_id": "WaHgrKPe6ePJJuE2o",
"firstName": "Ujwal",
"lastName": "Setlur",
"name": "Ujwal Setlur"
},
{
"_id": "yf2AsaHQN36TqKtFc",
"firstName": "Vineet",
"lastName": "Chikarmane",
"name": "Vineet Chikarmane"
}
]
},
{
"_id": "beLXTBrRAXtcf2oZc",
"name": "Vineet and Ujwal",
"description": "Vineet is admin",
"members": [
{
"_id": "WaHgrKPe6ePJJuE2o",
"firstName": "Ujwal",
"lastName": "Setlur",
"name": "Ujwal Setlur"
},
{
"_id": "yf2AsaHQN36TqKtFc",
"firstName": "Vineet",
"lastName": "Chikarmane",
"name": "Vineet Chikarmane"
}
]
},
{
"_id": "Ga4is5nwBXugxpRGt",
"name": "Vineet",
"description": "Vineet is admin",
"members": [
{
"_id": "yf2AsaHQN36TqKtFc",
"firstName": "Vineet",
"lastName": "Chikarmane",
"name": "Vineet Chikarmane"
}
]
},
{
"_id": "cyqFAhpCA2LzBGhsP",
"name": "Ujwal and Vineet",
"description": "Both are admin",
"members": [
{
"_id": "WaHgrKPe6ePJJuE2o",
"firstName": "Ujwal",
"lastName": "Setlur",
"name": "Ujwal Setlur"
},
{
"_id": "yf2AsaHQN36TqKtFc",
"firstName": "Vineet",
"lastName": "Chikarmane",
"name": "Vineet Chikarmane"
}
]
}
]
}
}
But when I query from the users via the inverse link by user and all the groups that the user is member of, I don't get all the records. Specifically, I don't the record where they are the only member:
query me {
me{
_id
name
groups {
_id
name
description
}
}
}
This is the result I get for Vineet is this. Notice that we are missing the group where Vineet is the only member.
{
"data": {
"me": {
"_id": "yf2AsaHQN36TqKtFc",
"name": "Vineet Chikarmane",
"groups": [
{
"_id": "nSkwTyjPFnmmZ6DYY",
"name": "Ujwal and Vineet",
"description": "Ujwal is admin"
},
{
"_id": "beLXTBrRAXtcf2oZc",
"name": "Vineet and Ujwal",
"description": "Vineet is admin"
},
{
"_id": "cyqFAhpCA2LzBGhsP",
"name": "Ujwal and Vineet",
"description": "Both are admin"
}
]
}
}
}
Same case if I query for Ujwal, record with Ujwal as only member is missing:
{
"data": {
"me": {
"_id": "WaHgrKPe6ePJJuE2o",
"name": "Ujwal Setlur",
"groups": [
{
"_id": "nSkwTyjPFnmmZ6DYY",
"name": "Ujwal and Vineet",
"description": "Ujwal is admin"
},
{
"_id": "beLXTBrRAXtcf2oZc",
"name": "Vineet and Ujwal",
"description": "Vineet is admin"
},
{
"_id": "cyqFAhpCA2LzBGhsP",
"name": "Ujwal and Vineet",
"description": "Both are admin"
}
]
}
}
}
When I query for all users and their groups, I get this:
query users {
users{
_id
name
groups {
_id
name
description
}
}
}
{
"data": {
"users": [
{
"_id": "ZbbLfS2tcwdnhLgeY",
"name": "Seamlz Admin",
"groups": null
},
{
"_id": "WaHgrKPe6ePJJuE2o",
"name": "Ujwal Setlur",
"groups": [
{
"_id": "nSkwTyjPFnmmZ6DYY",
"name": "Ujwal and Vineet",
"description": "Ujwal is admin"
},
{
"_id": "beLXTBrRAXtcf2oZc",
"name": "Vineet and Ujwal",
"description": "Vineet is admin"
},
{
"_id": "cyqFAhpCA2LzBGhsP",
"name": "Ujwal and Vineet",
"description": "Both are admin"
}
]
},
{
"_id": "yf2AsaHQN36TqKtFc",
"name": "Vineet Chikarmane",
"groups": [
{
"_id": "Ga4is5nwBXugxpRGt",
"name": "Vineet",
"description": "Vineet is admin"
}
]
}
]
}
}
Notice that for Vineet, it does not list all his groups, only the group where he is the sole member.
What am I doing wrong?
It doesn't make sense to have it as a separate package, the way apollo-live-server is designed is to work specifically with Meteor and observable collections.
Features:
Hi,
I have a subscription going with apollo-live-server which I can test with GraphiQL:
subscription {
groups {
event
doc {
_id
name
}
}
}
However, it is not clear how to use the apollo-live-client. I am using it in a react-native environment. I have set up the websocket link correctly, I believe:
// our websocket link for subscriptions
const wsLink = new WebSocketLink({
uri: constants.GRAPHQL_SUBSCRIPTION_ENDPOINT,
options: {
reconnect: true,
connectionParams: () => ({
[constants.AUTH_TOKEN_KEY]: getLoginToken() // this is asynchronous
})
}
});
// concat our link for a subscription link which uses websocket
const subscriptionLink = ApolloLink.from([errorLink, wsLink]);
// now use split to choose the correct link for subscription vs method
const link = split(({query}) => {
const {kind, operation} = getMainDefinition(query);
return kind === "OperationDefinition" && operation === "subscription";
}, subscriptionLink, methodLink);
Regular queries work fine, but I haven't gotten subscriptions to work yet. Here is what I am using. I am sure it's wrong. Any help will be appreciated:
const GET_GROUPS = gql`
query {
groups {
_id
name
}
}
`;
const SUBSCRIBE_GROUPS = gql`
subscription {
groups {
event
doc {
_id
name
}
}
}
`;
render() {
return (
<Container>
<Content>
<ReactiveQuery
query={GET_GROUPS}
subscription={SUBSCRIBE_GROUPS}
>
{({data: {groups}, loading, error}) => {
if (loading) return <Text>
Loading
</Text>;
if (error) return <Text>
{error}
</Text>;
return <Text>
{JSON.stringify(groups)}
</Text>;
}}
</ReactiveQuery>
</Content>
</Container>
);
}
What gets rendered is the just the query results, but I don't see the subscription updates coming in.
How do I debug this?
Thanks!
for the client side, is there anyway to get the cache or add our own cache to initialize, just wondering since i'm using apollo-link-state and it requires a cache to be passed into it's initialization.
I'm having trouble getting inverse links to function. I keep getting the fields returned as null. I have everything setup properly, and the data is being returned properly the other way.
type Counter @mongo(name: "counters") {
_id: ID!
count: Float
userId: ID!
user: User @link(field: "userId")
}
type User @mongo(name: "users") {
_id: ID!
counter: Counter @link(to: "user")
}
I imagine that it should just work both ways? or am i mistaken? My "Counter" query will return any information from User that i want. but if i try to return the count in my User query, i get null.
Also, does this automatically map the field specified in the first collection to the _id in the second?
posts
?W20180731-11:08:21.525(3)? (STDERR) TypeError: Cannot destructure property `Accounts` of 'undefined' or 'null'.
W20180731-11:08:21.525(3)? (STDERR) at users.js (packages/cultofcoders:apollo/server/core/users.js:4:22)
Current solution: meteor add accounts-password
https://github.com/excitement-engineer/graphql-iso-date
Explore (OkGrow scalars) ?
I see in the grapher
project that the db
is a pretty simple Proxy
. Are there any requirements to make collections available?
Sometimes, and it seems to be at random, a collection
is undefined
. Resulting in errors like Cannot read property 'find' of undefined
. Like for example:
Query: {
async blob(_, { blogId }, { userId, db }) {
const blog = db.blogs.find({ _id: blogId }).fetch();
const comments = db.comments.find({ blogId }).fetch();
return { blog, comments };
}
}
I have cases where db.blogs
would work just fine, while db.comments
is undefined
. A few restarts later, and it's working again.
I guess it's a simple issue somewhere, but I'm not really understanding why this happens.
Is it because of a missing @mongo(name: "comments")
annotation? Does that magically register the Collection
?
import { init } from 'meteor/cultofcoders:apollo';
init(Config, () => {
// When everything is ready
});
Problems:
This may need to be a separate package, as we want this decoupled from the frontend layer.
Hi,
I have a question on how to setup grapher and links. Let's say I have two collections: Users and Groups. Groups will have a a field called memberIds that is an array of Users.
What I want to do is get a list of all the groups I am a member of, and get the firstName of all the other users of the groups as well. I set up the schema/links in this way:
type Group @mongo(name: "groups")
{
_id: ID!
name: String
members: [User] @link(field: "memberIds")
admins: [User] @link(field: "adminIds")
}
# our user type
type User @mongo(name: "users")
{
_id: ID!
emails: [Email]
firstName: String
lastName: String
fullName: String
roles: [String]
groups: [Group] @link(to: "members")
admins: [Group] @link(to: "admins")
}
Here is my GraphQL query:
query groups {
groups{
_id
name
members {
_id
firstName
roles
}
}
}
The issue I am facing is that the first name of user is not being retrieved:
{
"data": {
"groups": [
{
"_id": "YqzhXSWYp6BXGBRkz",
"name": "Test Group",
"members": [
{
"_id": "PHpfwhHDR25koG5Bd",
"firstName": null,
"roles": [
"seamlz.factory"
]
}
]
}
]
},
"errors": [
{
"message": "Cannot read property 'firstName' of undefined",
"locations": [
{
"line": 7,
"column": 7
}
],
"path": [
"groups",
0,
"members",
0,
"firstName"
]
}
]
}
The first name is actually buried in the profile object in the user collection:
{
"_id" : "PHpfwhHDR25koG5Bd",
"createdAt" : ISODate("2018-07-31T07:34:47.128Z"),
"services" : {
"phone" : {
},
"resume" : {
"loginTokens" : [
{
"when" : ISODate("2018-07-31T07:34:55.384Z"),
"hashedToken" : "65jCfZi4ItIU3OwQyhUEZg158QUXp21vV6thfYV/31c="
}
]
}
},
"phone" : {
"number" : "+19253174023",
"verified" : true
},
"profile" : {
"name" : "Vineet Chikarmane",
"firstName" : "Vineet",
"lastName" : "Chikarmane",
"company" : "Pret Interpret"
},
"roles" : [
"seamlz.factory"
]
}
How do I get grapher to dig into the profile section to retrieve the firstName?
Thanks!
I just upgraded to 0.5.1 version of this package which has the support for apollo 2.0 server. My client is react-native. With the upgrade, the websocket link to the server is dropping after I log in. I don't know why yet. I am investigating.
I noticed that the subscription endpoint was changed from "subscriptions" to "graphql". Could this have caused it since the main endpoint is also "graphql"
When I revert to 0.4.2 version of this package and apollo-server-express 1.4.0, things work again.
A sort of Meteor startup but after everything this package has importer properly. Something like at the end:
// Because of Grapher
Meteor.startup(() => {
setReady();
});
I am using grapher schema directives to refer to the roles collection created by alanning:rloles package. If the cultofcoders:apollo package is installed after alanning:roles, you run into a server startup exception:
W20180726-17:35:12.428(-7)? (STDERR) /Users/ujwal/.meteor/packages/meteor-tool/.1.7.0_3.w8zcf.uowlh++os.osx.x86_64+web.browser+web.browser.legacy+web.cordova/mt-os.osx.x86_64/dev_bundle/server-lib/node_modules/fibers/future.js:280
W20180726-17:35:12.513(-7)? (STDERR) throw(ex);
W20180726-17:35:12.514(-7)? (STDERR) ^
W20180726-17:35:12.514(-7)? (STDERR)
W20180726-17:35:12.514(-7)? (STDERR) Error: There is already a collection named "roles"
W20180726-17:35:12.514(-7)? (STDERR) at ns.Collection.Collection (packages/mongo/collection.js:122:15)
W20180726-17:35:12.515(-7)? (STDERR) at ns.Collection (packages/matb33_collection-hooks.js:275:27)
W20180726-17:35:12.515(-7)? (STDERR) at new ns.Collection (packages/lai_collection-extensions.js:107:27)
W20180726-17:35:12.515(-7)? (STDERR) at setupMongoDirective (packages/cultofcoders:grapher-schema-directives/MongoDirective.js:27:18)
W20180726-17:35:12.515(-7)? (STDERR) at MongoDirective.visitObject (packages/cultofcoders:grapher-schema-directives/MongoDirective.js:14:5)
W20180726-17:35:12.515(-7)? (STDERR) at /Users/ujwal/Work/seamlz/seamlz-server/node_modules/graphql-tools/dist/schemaVisitor.js:89:47
W20180726-17:35:12.515(-7)? (STDERR) at Array.every (<anonymous>)
W20180726-17:35:12.516(-7)? (STDERR) at callMethod (/Users/ujwal/Work/seamlz/seamlz-server/node_modules/graphql-tools/dist/schemaVisitor.js:88:43)
W20180726-17:35:12.516(-7)? (STDERR) at visit (/Users/ujwal/Work/seamlz/seamlz-server/node_modules/graphql-tools/dist/schemaVisitor.js:138:29)
W20180726-17:35:12.516(-7)? (STDERR) at /Users/ujwal/Work/seamlz/seamlz-server/node_modules/graphql-tools/dist/schemaVisitor.js:128:28
W20180726-17:35:12.516(-7)? (STDERR) at /Users/ujwal/Work/seamlz/seamlz-server/node_modules/graphql-tools/dist/schemaVisitor.js:534:22
W20180726-17:35:12.516(-7)? (STDERR) at Array.forEach (<anonymous>)
W20180726-17:35:12.516(-7)? (STDERR) at updateEachKey (/Users/ujwal/Work/seamlz/seamlz-server/node_modules/graphql-tools/dist/schemaVisitor.js:533:32)
W20180726-17:35:12.517(-7)? (STDERR) at visit (/Users/ujwal/Work/seamlz/seamlz-server/node_modules/graphql-tools/dist/schemaVisitor.js:122:13)
W20180726-17:35:12.517(-7)? (STDERR) at visitSchema (/Users/ujwal/Work/seamlz/seamlz-server/node_modules/graphql-tools/dist/schemaVisitor.js:214:5)
W20180726-17:35:12.517(-7)? (STDERR) at Function.SchemaDirectiveVisitor.visitSchemaDirectives (/Users/ujwal/Work/seamlz/seamlz-server/node_modules/graphql-tools/dist/schemaVisitor.js:467:9)
So, we need to make sure that cultofcoders:apollo is before alanning:roles in the .meteor/packages file.
@theodorDiaconu I get a double slash in the uri when making a call to the graphql endpoint (e.g http://localhost:3050//graphql). Seems meteor adds a / at the end when Meteor.absoluteUrl() is called, so the export line in constants.js
export const GRAPHQL_ENDPOINT = Meteor.absoluteUrl('/graphql');
causes the double slash, any other way to fix this. Currently cloned the project and changed that line to export const GRAPHQL_ENDPOINT = Meteor.absoluteUrl('graphql'); to make it work
Meteor.settings.public.apollo: {withWebsockets: false}
I found DISABLE_SUBSCRIPTIONS
was removed from settings.
Something is strange and it may be related to either GraphQl or this package or meteor-apollo-accounts the error is confusing and it refers to tokenExpires
:
Float cannot represent non numeric value: {}
I have this stack working pretty well now and have near meteor type behaviour: server connection is checked, once established, user info is checked, etc. Client is react-native.
This is a great stack! Great job!
I do have an issue. I have a subscription going using ReactiveQuery, and it's working well.
However, when I bring down the server, i detect that in the client and navigate to a different page. I expect at this point that the subscription is gone. But it's not.
When I bring the server back up, it gets the old subscription, and the new one as the page is loaded. Well, I see the subscription resolver getting called twice.
Is there a way to cancel all subscriptions on the client when the network/server is down?
initialize({
links: []
})
We check the token only once when the websocket connects. But what if, in the meantime, the user gets deleted or something about him changes.
It's not enough only do run this check on every subscription request, but also have a sort of interval for this check, as a user may already have been subscribed and authorised. And if, for example, the token is no longer available we close down the connection.
meteor create testapp --bare
cd testapp
meteor npm i -S graphql graphql-load subscriptions-transport-ws apollo-live-server apollo-live-client apollo-client apollo-cache-inmemory apollo-link apollo-link-http apollo-link-ws express apollo-server-express uuid graphql-subscriptions body-parser graphql-tools graphql-type-json
meteor add cultofcoders:apollo
meteor
it looks like it use accounts package defaultly
I have 2 collections: users and groups. I have 2 main link sfrom groups to users based on memberIds and adminIds fields. Essentially who are the members and who are the admins.
Here is my GraphQL schema with schema directives:
Group:
type Group @mongo(name: "groups")
{
_id: ID!
name: String
description: String
members: [User] @link(field: "memberIds")
admins: [User] @link(field: "adminIds")
}
type ReactiveEventGroup {
event: String,
doc: Group
}
type Query {
groups(_id: String): [Group]
}
type Subscription {
groups: ReactiveEventGroup
}
Here is my User schema:
type Email
{
address: String
verified: Boolean
}
# our user type
type User @mongo(name: "users")
{
_id: ID!
emails: [Email]
firstName: String
lastName: String
name: String
company: String
roles: [String]
groups: [Group] @link(to: "members")
admins: [Group] @link(to: "admins")
}
# our queries
type Query {
users: [User]
me: User
}
Here is how I do my subscription:
const GET_GROUPS = gql`
query {
groups {
_id
name
description
members {
_id
name
company
}
admins {
_id
}
}
}
`;
const SUBSCRIBE_GROUPS = gql`
subscription {
groups {
event
doc {
_id
name
description
members {
_id
name
company
}
admins {
_id
}
}
}
}
`;
render() {
return (
<ReactiveQuery
query={GET_GROUPS}
subscription={SUBSCRIBE_GROUPS}
>
{({data, loading, error}) => {
if (loading) {
return <Text>
Loading
</Text>;
}
if (error) {
return <Text>
{error}
</Text>;
}
return <Groups
groups={data.groups}
onPress={this.viewGroup}
ref={(ref) => {
this.ref = ref;
}}
onSwipe={this.swipeButtons}
>
</Groups>;
}}
</ReactiveQuery>
);
}
Here are my query and subscription resolvers:
Query: {
groups(_, args, {db, userId}, ast) {
// sanity checks
if (!userId) {
throw new Meteor.Error("authorization-error", "Action not authorized");
}
let filter = {
memberIds: userId
};
if (args._id) {
filter._id = args._id;
}
// use grapher to do the query instead of direct mongo query
let allGroups = db.groups.astToQuery(ast, {
$filters: filter
}).fetch();
return allGroups;
}
},
Subscription: {
groups: {
resolve: payload => payload,
subscribe(_, args, context) {
console.log("Calling groups subscription; user = " + context.userId);
// sanity checks
if (!context.userId) {
throw new Meteor.Error("authorization-error", "Action not authorized");
}
const observer = context.db.groups.find();
return asyncIterator(observer);
}
}
}
On initial load, all is well and good. I get a good list with all the data. However, when I create a new group, say with GraphQL playground, then I run into a problem. I do get the group created event, but I do not get all the information about the group, particularly the ones attached to links.
Here is the mutation that added the query:
mutation saveGroup {
saveGroup(name: "Ujwal and Vineet",
members: ["WaHgrKPe6ePJJuE2o", "yf2AsaHQN36TqKtFc"],
admins: ["WaHgrKPe6ePJJuE2o"],
description:"Ujwal is admin") {
success
}
}
Here is the update record I got:
{
"_id": "DbvtEuZrwZYJpZh4x",
"name": "Ujwal and Vineet",
"description": "Ujwal is admin",
"members": null,
"admins": null,
"__typename": "Group"
}
Notice that I get only _id, name, and description. I don't get members and admins fields. Both those fields have links on them pointing to User.
What am I doing wrong?
The current user is resolved by a Meteor.users.findOne
. Works perfectly. Although, I would like to replace this with a Meteor.users.rawCollection().findAndModify
to keep track of user activity;
Meteor.users.rawCollection().findAndModify(
{ _id: userId },
{},
{ $set: { lastSeen: new Date() } },
{ new: true },
);
Lines 24 to 34 in 307bc8f
What's your opinion on this? Are you open for this change? And if you are, in what way?
Options that come to my mind:
Add simple initialize
setting:
initialize({}, {
trackUserLastSeen: true,
userFields: {
_id: 1,
roles: 1,
}
}),
Add resolveUser
function
initialize({}, {
resolveUser: (token, fields) => Meteor.users.rawCollection().findAndModify(..)
}),
// /server/core/users
const currentUser = typeof resolveUser === 'function'
? resolveUser(token)
: Meteor.users.findOne(...)
First option benefits from easy config. One of the selling points of this library. The second one provides better decoupling from database / meteor. But that doesn't seem to be one of the goals for this library.
On calling intialise
to retrieve client object,
creation of the original ApolloClient is limited.
For instance, applying a config like addTypename: false
becomes impossible;
Below is the exact code-snippet that intialises and returns the client object
const client = new ApolloClient({
link: terminatingLink,
cache: new InMemoryCache({
dataIdFromObject: object => object._id || null,
}).restore(window.__APOLLO_STATE__ || {}),
});
return {
client,
};
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.