Skip to content

Instantly share code, notes, and snippets.

@filipenevola
Last active January 23, 2020 20:57
Show Gist options
  • Save filipenevola/17ae16917616d27729ea113de838dcf8 to your computer and use it in GitHub Desktop.
Save filipenevola/17ae16917616d27729ea113de838dcf8 to your computer and use it in GitHub Desktop.
Meteor Apollo snippets
/**
Snippets showing how to configure Apollo with Meteor in two different ways:
1 - Using DDP (websocket connection)
2 - Using HTTP (post requests)
I'm using a regular HTTP post approach when isAPIModule() returns true
and DDP approach when returns false. I control isAPIModule changing
a setting in the deployment settings.json
That is not necessary for almost every application but in my case I have
two back-ends apps implemented using the same code.
One back-end app using DDP that is accessed by my Meteor front-end and other
back-end app accessed by third parties using HTTP posts.
The client side is also configured in different ways depending on
isAPIModule() return
**/
import { isAPIModule } from '../../api/apiModuleCommon';
import { Meteor } from 'meteor/meteor';
import { ReactiveVar } from 'meteor/reactive-var';
import { Tracker } from 'meteor/tracker';
import { InMemoryCache } from 'apollo-cache-inmemory';
import React from 'react';
import { render } from 'react-dom';
import { Router } from 'react-router-dom';
import { createBrowserHistory } from 'history';
import ApolloClient from 'apollo-client';
import { onError } from 'apollo-link-error';
import { DDPLink, MeteorLink } from 'apollo-link-ddp';
import { ApolloProvider } from 'react-apollo';
import { Provider } from 'react-redux';
import ThemeProvider from '@material-ui/styles/ThemeProvider';
import '../../setup/client/index';
import { theme } from '../../styles/styles';
import { reduxStore } from '../../reducers';
import { AppContainer } from '../../ui/AppContainer';
import '../../../infra/types/types';
import { modeLoad } from '../../mode/modeLoad';
import { getMode } from '../../mode/modeClient';
import { Loading } from '../../ui/components/Loading';
import { loggerStartup } from '../../logs/loggerStartup';
import { logger } from '../../logs/logger';
import { initializeGoogleAnalytics } from '../../service/google-analytics';
import { Environments } from '../../envs';
import { APIHome } from '../../api/APIHome';
const link = onError(({ graphQLErrors, networkError }) => {
if (graphQLErrors) {
graphQLErrors.map(({ message, locations, path, ...rest }) =>
logger.error(
`[GraphQL error]: Message: ${message}, Location: ${locations}, Path: ${path}`,
rest
)
);
}
if (networkError) logger.error('[Network error]: ', networkError);
});
export const apolloClient = new ApolloClient({
link: link.concat(isAPIModule() ? new MeteorLink() : new DDPLink()),
cache: new InMemoryCache(),
connectToDevTools: !Environments.isProduction(),
});
export const history = createBrowserHistory();
const initialize = () => {
initializeGoogleAnalytics();
loggerStartup('initialized');
};
Meteor.startup(() => {
loggerStartup('init');
const appElement = document.getElementById('app');
if (isAPIModule()) {
logger.log('** API: RUNNING AS API MODULE **');
render(<APIHome />, appElement);
return;
}
const modeReactiveVar = new ReactiveVar(
getMode(),
(oldConfig, newConfig) =>
oldConfig.ready === newConfig.ready &&
oldConfig.slug === newConfig.slug &&
oldConfig.name === newConfig.name
);
modeLoad(modeReactiveVar);
Tracker.autorun(computation => {
if (!modeReactiveVar.get().ready) {
loggerStartup('not ready');
render(<Loading />, appElement);
return;
}
loggerStartup('ready');
initialize();
computation.stop();
render(
<Provider store={reduxStore}>
<ApolloProvider client={apolloClient}>
<ThemeProvider theme={theme}>
<Router history={history}>
<AppContainer />
</Router>
</ThemeProvider>
</ApolloProvider>
</Provider>,
appElement
);
});
});
import { makeExecutableSchema } from 'graphql-tools';
import { getSchema, load } from 'graphql-load';
import { setup, setupHttpEndpoint } from 'meteor/swydo:ddp-apollo';
import ApolloClient from 'apollo-client';
import { InMemoryCache } from 'apollo-cache-inmemory';
import { SchemaLink } from 'apollo-link-schema';
import '../../setup/server/index';
import { InfraTypeDefs } from '../../../infra/data/Infra.schema';
import { InfraResolvers } from '../../../infra/data/Infra.resolvers';
import { UserTypeDefs } from '../../../app/users/data/User.schema';
import { UserResolvers } from '../../../app/users/data/User.resolvers';
import '../../../infra/types/types';
import { logger } from '../../logs/logger';
import { apiAuthMiddleware } from '../../api/apiModule';
import { isAPIModule } from '../../api/apiModuleCommon';
import { ContentResolvers } from '../../../lemeno/content/Content.resolvers';
import { ContentTypeDefs } from '../../../lemeno/content/Content.schema';
import { FollowerTypeDefs } from '../../../lemeno/follower/Follower.schema';
import { FollowerResolvers } from '../../../lemeno/follower/Follower.resolvers';
import { FollowerContentTypeDefs } from '../../../lemeno/follower/FollowerContent.schema';
import { FollowerContentResolvers } from '../../../lemeno/follower/FollowerContent.resolvers';
load({
typeDefs: [
InfraTypeDefs,
UserTypeDefs,
ContentTypeDefs,
FollowerTypeDefs,
FollowerContentTypeDefs,
],
resolvers: [
InfraResolvers,
UserResolvers,
ContentResolvers,
FollowerResolvers,
FollowerContentResolvers,
],
});
const schema = makeExecutableSchema({
...getSchema(),
logger: { log: e => logger.error('GraphQL server error', e) },
});
if (isAPIModule()) {
setupHttpEndpoint({
schema,
authMiddleware: apiAuthMiddleware,
});
} else {
setup({ schema });
}
export const getApolloServerClient = () =>
new ApolloClient({
ssrMode: true,
cache: new InMemoryCache(),
link: new SchemaLink({ schema }),
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment