Agreed, as someone who is also implementing Apollo already, what should I be aware of when writing code now, to help make the 1.5 transition easier?
Here’s what I said before on another thread:
I don’t think there is anything that should stop you from writing the code right now! The whole point is that it’s an independent project, so you don’t have to worry too much about Meteor specific stuff. Ideally you will just be able to remove some boilerplate you might have now around accounts, database stuff, and more.
We’re also working on some basic realtime data support in Apollo right now via GraphQL subscriptions, which is a great candidate for having a tighter integration with Meteor’s backend systems.
Are we likely to see the Meteor Apollo package updated anytime soon, to support the latest releases of apollo-client
and apollo-server
? Or is it just a case of waiting for the “new” approach version to become available?
I feel like the Express, Koa, etc. people have more up-to-date packages for Apollo than we do for Meteor, which is a bit of a shame.
EDIT: https://github.com/apollostack/meteor-integration/ this is the package I am referring too.
I’m just trying to understand what’s coming is all… This implies, AT THIS TIME, even though you’re “integrating” Apollo into Meteor-classic, there’s a complete disconnect between the two. Is the only real “integration” between the two that they’ll ship along side one another?
And I read here, SOME TIME IN THE FUTURE, they’ll be some REAL coming together of the two stacks?
Is this actually better integration or just more recent?
The Apollo integration packages for React, Angular, etc. are community-maintained. It looks like that model hasn’t worked out as well for the Meteor integration, so we need to find someone who has more time to maintain it.
@Siyfion are you planning on using Meteor + Apollo in production? If so, I’d be happy to work together with you to ensure the Meteor integration stays up to date!
Apollo works fine with connect
, Meteor’s underlying web server, in the same way as it works with express
. The Meteor integration package tries to make the integration more automatic. If you just want to attach Apollo to your Meteor app just like you can do with express, you don’t need that package at all.
Perhaps we should go back to the previous state, which was that we just had a few lines of code you could copy-paste from the docs to do your own integration.
You can think of it as similar to integration React and Meteor - they are two separate technologies that are great to use together. I’d say that puts it in a pretty positive light, since using React with Meteor is a pretty great experience.
There won’t be any features in Apollo that you can only get with Meteor, if that’s what you mean.
Yes, I am! Trying to migrate just one big part of my application first, then will probably move the majority over. Currently it’s already running some of the Apollo stuff on my development server on Galaxy. I’ve definitely got some suggestions as to where the guide/docs could do with a bit more explanation. On that note…
I think that would probably be best actually, as you say, if it’s only a few lines of code, better to just have it in the guide and up-to-date there than rely on a package maintainer for a “trivial” bit of code… left-pad
anyone!?
Yeah. There are a couple things about getting and caching user documents, but those don’t need to be wrapped up in a whole integration framework.
Meteor Accounts support for SQL databases would be helpful. That way I wouldn’t need a separate Mongo database just to handle Meteor accounts (which I love).
You can write new publish/subscribe calls with a Meteor method instead. Call the method and store the static data somewhere, eg… setState, redux, local minimongo collection… whatever you’re using today. GraphQL mutations are very similar. But as Sashko said… you really don’t have to do anything today to prepare for it, but making Meteor methods may save you a bit of time.
I disagree - I think using Apollo is much more like pub/sub than methods. A big part of the goal is to save people from writing manual data loading code with redux.
Yeah I totally agree with the end goal not having to do a lot of manual loading code. I just meant that i’ve found it easier to migrate a Meteor method to a GraphQL mutation. I def. wouldn’t refactor current pub/sub code to methods and manual loading but if someone needed a bridge than that’s saved me a lot of effort. However, in the big scope of things I haven’t found it hard to switch a page over to 100% Apollo either.
FWIW Apollo Client has saved me from all that Redux wiring ceremony… @sashko thank you x100 !!! I’ve found that I only use Redux for truly global state (modals, etc…) and I can use Apollo and local state 99% of the time which makes for really cohesive code
fyi: co·he·sion: the action or fact of forming a united whole.
Apollo makes for united under whole code…
What about deploying Apollo Servers to Galaxy?
Right now, only Meteor-based servers can be deployed to Galaxy.
If you read deeply into the end of this blog post, you’ll find that Galaxy infrastructure has been upgraded to potentially support arbitrary containers. We’ll see if that might include plain Node apps soon, with a simple Meteor-independent deploy tool; it depends on what customers are asking for.
Awesome, that’s very exciting.
It makes a lot of sense to be able to be able to deploy pure node apps to Galaxy with a global NPM package, especially if Meteor is going to be converted into NPM modules moving forward.
It’d also be really interesting to have the Galaxy console categorize its services, similar to how the AWS console categorizes its services. For example “Node.js - Apollo - Meteor” and MDG can continue to build on those services and add more in the future, right to the “console” (again, like AWS or Google Cloud) until it has the whole deployment and infrastructure figured out, making web development easy and hassle free.
Yikes… my mouth is watering at the thought of it.
Hi, interesting comment, care to elaborate? If I understand their correctly, you use Apollo react to load data into your component and then you use stateful react components to maintain state?
Ok I’ll bite
So previously I went in the direction of having all stateless components and one single source of in memory state. This state (redux) would hold local state for keeping track of spinners, tab positions, pretty much everything. One of the really nice parts about this that it’s easy to test the views again because they just take in props (from Redux’s connect
) and they call an action creator function which can be stubbed out in tests easily.
In theory this is nice and you have this trail of actions streaming through your app but in reality it was a bit of wiring or “ceremony” for local state and a lot of wiring and boilerplate for getting server data… especially with handling errors. Now the actually ajax call is outside of the view and the only way to get the error back into the view is to send more actions. In theory this is ok but practically it’s a pain in the butt (still better than the Blaze spaghetti mess of 2012 area).
Now with GraphQL and Redux it’s about the same amount of wiring as AJAX/REST and Redux but you get a little bit of a code reduction and can usually use fragments (depending on the client library). Fragments allow you to re-use fields and make GraphQL less verbose. It also co-locates the fields to fetch right next to the view (same file).
With Apollo you can forget about the Redux cache for all server related state. You can just keep making calls and the first time will hit the server and by default future queries will read from the cache. To sync the cache you can return the new data in a mutation response (forcing views to update automatically).
To tie these together, using containers to separate data concerns and handle state (via setState
) means you can get those nice clean views back because they’re now just taking props. You can define functions in the container and pass them down, keeping it testable and clean. This also make it easy for designers!
I’ve been using this for approx 3 months and it’s been working out really really well. It actually makes React fun again!
Example of a container and view component (note, a container isn’t required for apollo, i just prefer the organization). I’ve also left out the mutation to keep the example shorter:
// app/pages/post/index.js
const Container = React.createClass({
viewerOwnsPost() {
return this.props.data.post.userId === _viewerId;
},
handleEditClick(postId) {
// use a closure to capture post id and return a new func for the click handler
// I use this technique for a list of posts however here we could just use props.post.id since there is only 1
return (event) => {
// call Apollo mutation to edit data
}
},
// do data manipulation here and pass down as props
render(props=this.props) {
const {post, loading, error} = this.props.data;
if (error) {
AlertError(error);
return null;
}
return (
<Post
{...post}
loading={loading}
viewerOwnsPost={this.viewerOwnsPost}
/>;
);
}
});
export default graphql(gql`
query getPost {
posts(id: "p123") {
id
title
desc
}
}
`)(Container);
// app/pages/post/post.js
const Post = (props) => {
if (props.loading) return <LoadingSpinner />;
return (
<View style={styles.container}>
<Text style={styles.title}>{props.title}</Text>
<Text style={styles.desc}>{props.desc}</Text>
{props.viewerOwnsPost &&
<Link onClick={props.handleEditClick(props._id)} style={styles.title}>
Edit Post
</Link>
}
</View>
);
};
// throw warning if props are not used in dev
Post.propTypes = {
title: React.PropTypes.string.isRequired,
viewerOwnsPost: React.PropTypes.func.isRequired,
};
const styles = StyleSheet.create({
...
});
export default Post;
Fantastic! Thanks for that! One last question … how does a view know to update data after your mutation? Do you just call refetch? That seems like an overkill. You mention that this can happen by returning data from mutation. But how do you wire the change to the component?
Indeed, manually refetching would be a hassle. You can do this at will when you need to (like a refresh button on a mobile app).
However, your mutation has to return something (I think at least) and most of the time you would return the data it’s changed. When you do this you want to return the _id
of the document so that Apollo can merge the old object with the new one you just returned. The react-apollo
binding take care of re-rending the view whenever the apollo cache has changed.
// in click handler
this.props.mutate({ variables: { text: "task", list_id: 1 } })
.then(({ data }) => {
// use it here if you like, this will also update the redux cache
console.log('got data', data);
}).catch((error) => {
console.log('there was an error sending the query', error);
});
Note you can also call this from outside the view when needed. Sometimes i’ll want to preload the “feed” data right after logging in so I’ll manually fetch the minimum for that, then hide the spinner and redirect, to make the view feel “fast”.