├── .gitignore ├── DateTimeTypeDef.js ├── package.js ├── server.js ├── DateTimeResolver.js ├── client.js └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | -------------------------------------------------------------------------------- /DateTimeTypeDef.js: -------------------------------------------------------------------------------- 1 | export const DateTimeTypeDef = ` 2 | scalar DateTime 3 | 4 | type Now { 5 | dateTime: DateTime 6 | } 7 | 8 | type Query { 9 | now: Now 10 | } 11 | `; 12 | -------------------------------------------------------------------------------- /package.js: -------------------------------------------------------------------------------- 1 | Package.describe({ 2 | name: 'quave:graphql', 3 | version: '1.0.0', 4 | summary: 'Utility package to create GraphQL setup in a standard way', 5 | git: 'https://github.com/quavedev/graphql', 6 | }); 7 | 8 | Package.onUse(function(api) { 9 | api.versionsFrom('1.10.1'); 10 | api.use('ecmascript'); 11 | api.use('swydo:ddp-apollo@3.0.0', 'server'); 12 | 13 | api.mainModule('server.js', 'server'); 14 | api.mainModule('client.js', 'client'); 15 | }); 16 | -------------------------------------------------------------------------------- /server.js: -------------------------------------------------------------------------------- 1 | import {setup} from 'meteor/swydo:ddp-apollo'; 2 | 3 | import {makeExecutableSchema} from 'graphql-tools'; 4 | import {getSchema, load} from 'graphql-load'; 5 | 6 | const defaultLog = e => console.error('GraphQL server error', e); 7 | 8 | export const startGraphQLServer = ({typeDefs, resolvers, log}) => { 9 | load({ 10 | typeDefs, 11 | resolvers, 12 | }); 13 | const schema = makeExecutableSchema({ 14 | ...getSchema(), 15 | logger: { log: log || defaultLog }, 16 | }); 17 | setup({schema}); 18 | }; 19 | -------------------------------------------------------------------------------- /DateTimeResolver.js: -------------------------------------------------------------------------------- 1 | export const DateTimeResolver = { 2 | DateTime: 3 | { 4 | __parseValue(value) { 5 | return new Date(value); // value from the client 6 | }, 7 | __serialize(value) { 8 | return value.getTime(); // value sent to the client 9 | }, 10 | __parseLiteral(ast) { 11 | // eslint-disable-next-line no-undef 12 | if (ast.kind === Kind.INT) { 13 | return parseInt(ast.value, 10); // ast value is always in string format 14 | } 15 | return null; 16 | }, 17 | }, 18 | Query: { 19 | async now() { 20 | return { 21 | dateTime: new Date() 22 | }; 23 | }, 24 | } 25 | }; 26 | -------------------------------------------------------------------------------- /client.js: -------------------------------------------------------------------------------- 1 | import {InMemoryCache} from 'apollo-cache-inmemory'; 2 | import ApolloClient from 'apollo-client'; 3 | import {onError} from 'apollo-link-error'; 4 | import {DDPLink} from 'apollo-link-ddp'; 5 | 6 | const link = onError(({graphQLErrors, networkError}) => { 7 | if (graphQLErrors) { 8 | graphQLErrors.map(({message, locations, path, ...rest}) => 9 | console.error( 10 | `[GraphQL error]: Message: ${message}, Location: ${locations}, Path: ${path}`, 11 | rest 12 | ) 13 | ); 14 | } 15 | 16 | if (networkError) console.error('[Network error]: ', networkError); 17 | }); 18 | 19 | export const startGraphQLClient = ({connectToDevTools = false} = {}) => new ApolloClient({ 20 | link: link.concat(new DDPLink()), 21 | cache: new InMemoryCache(), 22 | connectToDevTools, 23 | }); 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # quave:graphql 2 | 3 | `quave:graphql` is a Meteor package that allows you to create your GraphQL server and client in a standard way. 4 | 5 | ## Why 6 | Every application that wants to use GraphQL needs to connect some packages and some npm modules. Also need: 7 | - Declare types and resolvers in separate files 8 | - Log for errors 9 | - Connect to Devtools 10 | 11 | We believe we are not reinventing the wheel in this package but what we are doing is like putting together the wheels in the vehicle :). 12 | 13 | ## Installation 14 | 15 | Meteor package 16 | ```sh 17 | meteor add quave:graphql 18 | ``` 19 | Server NPM packages 20 | ```sh 21 | meteor npm install graphql-tools graphql-load graphql 22 | ``` 23 | Client NPM packages 24 | ```sh 25 | meteor npm install apollo-client apollo-cache-inmemory apollo-link-error apollo-link-ddp 26 | ``` 27 | 28 | ### Usage 29 | 30 | #### Server 31 | In the server you should call `startGraphQLServer` providing your types and your resolvers. This function needs to be called during the server start so you should place it in the files imported by your main server file. 32 | 33 | Here you can check one example of [type](https://github.com/quavedev/graphql/blob/master/DateTimeTypeDef.js) and [resolver](https://github.com/quavedev/graphql/blob/master/DateTimeResolver.js). 34 | 35 | See below how to use it: 36 | ```javascript 37 | import { startGraphQLServer } from "meteor/quave:graphql/server"; 38 | 39 | import { logger } from 'meteor/quave:logs/logger'; 40 | 41 | 42 | import { DateTimeTypeDef } from "meteor/quave:graphql/DateTimeTypeDef"; 43 | import { DateTimeResolver } from "meteor/quave:graphql/DateTimeResolver"; 44 | 45 | const log = error => logger.error({ message: 'GraphQL server error', error }) 46 | 47 | startGraphQLServer({ typeDefs: [DateTimeTypeDef], resolvers: [DateTimeResolver], log }); 48 | ``` 49 | `typeDefs` expects an array of types definitions (schemas) and `resolvers` expects an array of resolvers. You can use a single type definition and a single resolver but usually is better to split them in multiple files. 50 | 51 | You don't need to use `DateTimeTypeDef` and `DateTimeResolver` they are just examples. 52 | 53 | You also don't need to provide a log function, by default it will log to console.error. 54 | 55 | #### Client 56 | In the client you should call `startGraphQLClient`, this is going to return an Apollo client already configured to you. 57 | ```javascript 58 | import { startGraphQLClient } from "meteor/quave:graphql/client"; 59 | 60 | const apolloClient = startGraphQLClient({ connectToDevTools: true }); 61 | ``` 62 | Then you can use the `apolloClient` as you want, see below two examples. 63 | 64 | ### Optional installations 65 | 66 | #### React 67 | To use GraphQL with React you probably want to have a provider around your app main component so you need to install `@apollo/react-hooks` 68 | 69 | ```sh 70 | meteor npm install @apollo/react-hooks 71 | ``` 72 | 73 | then you can use `ApolloProvider` 74 | 75 | ```javascript 76 | import { startGraphQLClient } from "meteor/quave:graphql/client"; 77 | 78 | import { ApolloProvider } from '@apollo/react-hooks'; 79 | 80 | const apolloClient = startGraphQLClient({ connectToDevTools: true }); 81 | 82 | Meteor.startup(() => { 83 | render( 84 | 85 | 86 | , 87 | document.getElementById('react-target') 88 | ); 89 | }); 90 | ``` 91 | 92 | To write queries and mutations you are going to use `gql` and so install `graphql-tag`. 93 | 94 | ```sh 95 | meteor npm install graphql-tag 96 | ``` 97 | 98 | And here is how to use with hooks, in this example we are using `useQuery` hook. 99 | 100 | ```javascript 101 | import React from 'react'; 102 | import gql from 'graphql-tag'; 103 | import { useQuery } from '@apollo/react-hooks'; 104 | 105 | const nowQuery = gql` 106 | query Now { 107 | now { 108 | dateTime 109 | } 110 | } 111 | `; 112 | 113 | export const App = () => { 114 | const { loading, error, data } = useQuery(nowQuery); 115 | 116 | console.log('loading', loading); 117 | console.log('error', error); 118 | console.log('data', data); 119 | 120 | const today = data && data.now && new Date(data.now.dateTime); 121 | const dayOfMonth = today && today.getDate(); 122 | const monthOfYear = today && today.getMonth() + 1; 123 | 124 | const welcome = loading ?

loading

: 125 |

Welcome to quave:graphql ({dayOfMonth}/{monthOfYear})!

; 126 | 127 | return ( 128 |
129 | {welcome} 130 |
131 | ); 132 | }; 133 | ``` 134 | 135 | #### No React 136 | You can use this package in any app to setup GraphQL for you and then you can write queries and mutations using Apollo client or other wrappers, you will probably use `gql` then you should install `graphql-tag` 137 | 138 | ```sh 139 | meteor npm install graphql-tag 140 | ``` 141 | and then use like this 142 | 143 | ```javascript 144 | import { Meteor } from 'meteor/meteor'; 145 | import { startGraphQLClient } from "meteor/quave:graphql/client"; 146 | 147 | import gql from 'graphql-tag'; 148 | 149 | const apolloClient = startGraphQLClient({ connectToDevTools: true }); 150 | 151 | Meteor.startup(() => { 152 | apolloClient.query({ 153 | query: gql` 154 | query Now { 155 | now { 156 | dateTime 157 | } 158 | } 159 | ` 160 | }).then(({ data: { now }}) => console.log(now)); 161 | }); 162 | ``` 163 | 164 | ## Limitations 165 | - It's not ready yet for auto-complete queries with IDEs, at least on WebStorm it's not working out-of-box. 166 | 167 | ### License 168 | 169 | MIT 170 | --------------------------------------------------------------------------------