Skip to content

Instantly share code, notes, and snippets.

@jackie1santana
Last active May 3, 2020 22:34
Show Gist options
  • Save jackie1santana/bc4c8be7c39477596683e296f5f9daed to your computer and use it in GitHub Desktop.
Save jackie1santana/bc4c8be7c39477596683e296f5f9daed to your computer and use it in GitHub Desktop.
Express-GraphQL/Apollo Client Set Up
const express = require('express')
const graphqlHTTP = require('express-graphql')
const schema = require('./schema/schema')
const app = express()
app.use('/graphql', graphqlHTTP({
schema,
graphiql: true
}))
app.listen(4000, () => {
console.log('server running on port 4000')
})
const graphql = require('graphql')
const { GraphQLObjectType, GraphQLString, GraphQLSchema } = graphql;
const books = [
{ name: 'Name of the Wind', genre: 'Fantasy', id: '1'},
{ name: 'The final Empire', genre: 'Fantasy', id: '2'},
{ name: 'The Long Earth', genre: 'Sci-Fi', id: '3'}
]
//defined your 1st object type for the schema
const BookType = new GraphQLObjectType({
name: 'Book',
fields: () => ({
id: { type: GraphQLString},
name: { type: GraphQLString },
genre: { type: GraphQLString }
})
})
// put both Types above inside the root query
const RootQuery = new GraphQLObjectType({
name: 'RootQueryType',
fields: {
book: {
type: BookType,
args: {id: { type: GraphQLString }},
resolve(parent, args){
//code to get data from db/ or other source
//using Array.find() to return value
return books.find(i => i.id == args.id)
}
}
}
})
module.exports = new GraphQLSchema({
query:RootQuery
})
const graphql = require('graphql')
const {
GraphQLObjectType,
GraphQLString,
GraphQLSchema ,
GraphQLID,
GraphQLInt,
GraphQLList
} = graphql;
const books = [
{ name: 'Name of the Wind', genre: 'Fantasy', id: '1', authorId: '1'},
{ name: 'The final Empire', genre: 'Fantasy', id: '2', authorId: '2'},
{ name: 'The Long Earth', genre: 'Sci-Fi', id: '3', authorId: '3'},
{ name: 'The Hero of Ages', genre: 'Fantasy', id: '4', authorId: '2' },
{ name: 'The Colour of Magic', genre: 'Fantasy', id: '5', authorId: '3' },
{ name: 'The Light Fantastic', genre: 'Fantasy', id: '6', authorId: '3' }
]
const authors = [
{ name: 'Patrick Rothfuss', age: 44, id: '1'},
{ name: 'Brandon Sanderson', age: 42, id: '2'},
{ name: 'Terry Pratchett', age: 66, id: '3'}
]
const AuthorType = new GraphQLObjectType({
name: 'Author',
fields: () => ({
id: { type: GraphQLID },
name: { type: GraphQLString },
age: { type: GraphQLInt },
books: {
type: GraphQLList(BookType),
resolve(parent, args){
console.log(parent)
return books.filter(i => i.authorId == parent.id)
}
}
})
})
//defined your 1st object type for the schema
const BookType = new GraphQLObjectType({
name: 'Book',
fields: () => ({
id: { type: GraphQLID },
name: { type: GraphQLString },
genre: { type: GraphQLString },
author:{
type: AuthorType,
resolve(parent, args){
console.log(parent)
return authors.find(i => i.id == parent.authorId)
}
}
})
})
// put both Types above inside the root query
const RootQuery = new GraphQLObjectType({
name: 'RootQueryType',
fields: {
book: {
type: BookType,
args: {id: { type: GraphQLID }},
resolve(parent, args){
//code to get data from db/ or other source
//using lodash
// return _.find(books, {id: args.id })
return books.find(i => i.id == args.id)
}
},
author: {
type: AuthorType,
args: {id: {type: GraphQLID}},
resolve(parent, args){
console.log(parent)
return authors.find(i => i.id == args.id)
}
},
books: {
type: new GraphQLList(BookType),
resolve(parent, args){
return books
}
},
authors: {
type: new GraphQLList(AuthorType),
resolve(parent, args){
return authors
}
},
}
})
module.exports = new GraphQLSchema({
query:RootQuery
})
const graphql = require('graphql')
const Book = require('../models/book')
const Author = require('../models/author')
const {
GraphQLObjectType,
GraphQLString,
GraphQLSchema ,
GraphQLID,
GraphQLInt,
GraphQLList
} = graphql;
const AuthorType = new GraphQLObjectType({
name: 'Author',
fields: () => ({
id: { type: GraphQLID },
name: { type: GraphQLString },
age: { type: GraphQLInt },
books: {
type: GraphQLList(BookType),
resolve(parent, args){
// console.log(parent)
// return books.filter(i => i.authorId == parent.id)
}
}
})
})
//defined your 1st object type for the schema
const BookType = new GraphQLObjectType({
name: 'Book',
fields: () => ({
id: { type: GraphQLID },
name: { type: GraphQLString },
genre: { type: GraphQLString },
author:{
type: AuthorType,
resolve(parent, args){
// console.log(parent)
// return authors.find(i => i.id == parent.authorId)
}
}
})
})
// put both Types above inside the root query
const RootQuery = new GraphQLObjectType({
name: 'RootQueryType',
fields: {
book: {
type: BookType,
args: {id: { type: GraphQLID }},
resolve(parent, args){
//code to get data from db/ or other source
//using lodash
// return _.find(books, {id: args.id })
// return books.find(i => i.id == args.id)
}
},
author: {
type: AuthorType,
args: {id: {type: GraphQLID}},
resolve(parent, args){
// console.log(parent)
// return authors.find(i => i.id == args.id)
}
},
books: {
type: new GraphQLList(BookType),
resolve(parent, args){
// return books
}
},
authors: {
type: new GraphQLList(AuthorType),
resolve(parent, args){
// return authors
}
},
}
})
//redefine types
const Mutation = new GraphQLObjectType({
name: 'Mutation',
fields: {
addAuthor: {
type: AuthorType,
args: {
name: { type: GraphQLString },
age: { type: GraphQLInt }
},
resolve(parent, args){
//author model from mongoose schema
let author = new Author({
name: args.name,
age: args.age
})
return author.save()
}
},
addBook: {
type: BookType,
args: {
name: { type: GraphQLString },
genre: { type: GraphQLString },
authorId: { type: GraphQLID }
},
resolve(parent, args){
//author model from mongoose schema
let book = new Book({
name: args.name,
genre: args.genre,
authorId: args.authorId
})
return book.save()
}
},
}
})
module.exports = new GraphQLSchema({
query:RootQuery,
mutation: Mutation
})
import { gql } from 'apollo-boost'
//pulling from the graphql uri
const getBooksQuery = gql`
{
books {
name
id
}
}
`
//pulling from the graphql uri
const getAuthorsQuery = gql`
{
authors {
name
id
}
}
`
const addBookMutation = gql`
mutation($name: String!, $genre: String!, $authorId: ID!) {
addBook(name: $name, genre: $genre, authorId: $authorId){
name
id
}
}
`
//making query from user
const getBookQuery = gql`
query($id: String){
book(id: ID){
id
name
genre
author{
id
name
age
books{
name
id
}
}
}
}
`
export { getAuthorsQuery, getBooksQuery, addBookMutation, getBookQuery }
app.js (pass in query varables into mutations function via state)
import React, { Component } from 'react'
import { graphql} from 'react-apollo'
import { getAuthorsQuery, addBookMutation } from '../queries/queries'
import { flowRight as compose } from 'lodash'
//form tag
class AddBook extends Component {
constructor(props){
super(props)
this.state = {
name: '',
genre: '',
authorId: ''
}
}
displayAuthors(){
const data = this.props.getAuthorsQuery
if(data.loading){
return (<option disabled>Loading Authors..</option>)
}else {
return data.authors.map(author => {
return (<option key={author.id} value={author.id} >{author.name}</option>)
})
}
}
submitForm(e){
e.preventDefault()
this.props.addBookMutation({
variables: {
name: this.state.name,
genre: this.state.genre,
authorId: this.state.authorId
}
})
}
render() {
console.log(this.props)
return (
<form id="add-book" onSubmit={this.submitForm.bind(this)} >
<div className="field" >
<label>Book Name:</label>
<input type="text" onChange={(e) => this.setState({ name: e.target.value })} />
</div>
<div className="field" >
<label>Genre:</label>
<input type="text" onChange={(e) => this.setState({ genre: e.target.value })}/>
</div>
<div className="field" >
<label>Author:</label>
<select onChange={(e) => this.setState({ authorId: e.target.value })}>
<option>Select author:</option>
{ this.displayAuthors() }
</select>
</div>
<button>+</button>
</form>
)
}
}
//this basically says, take graphql and bind geyBooks Query to BookList
export default compose(
//use compose to bind queries to client & bind mutations to client
graphql(getAuthorsQuery, {name: "getAuthorsQuery"}),
graphql(addBookMutation, {name: "addBookMutation"})
//both query & mutations are now bound to (addBook)
)(AddBook);
//use compose to bind multiple queries
import React, { Component } from 'react'
import { gql } from 'apollo-boost'
import { graphql } from 'react-apollo'
//pulling from the graphql uri
const getBooksQuery = gql `
{
books {
name,
id
}
}
`
//now we need to bind this query to this component (react-apollo package does that)
class BookList extends Component {
displayBooks(){
const data = this.props.data;
if(data.loading){
return (<div>Loading Books...</div>)
}else {
return data.books.map(book => {
return (
<li>{book.name}</li>
)
})
}
}
render() {
console.log(this.props)
return (
<div>
<ul id="book-list" >
{ this.displayBooks() }
</ul>
</div>
)
}
}
//this basically says, take graphql and bind geyBooks Query to BookList
export default graphql(getBooksQuery)(BookList);
const graphql = require('graphql')
const Book = require('../models/book')
const Author = require('../models/author')
const {
GraphQLObjectType,
GraphQLString,
GraphQLSchema ,
GraphQLID,
GraphQLInt,
GraphQLList
} = graphql;
//defined your 1st object type for the schema
const BookType = new GraphQLObjectType({
name: 'Book',
fields: () => ({
id: { type: GraphQLID },
name: { type: GraphQLString },
genre: { type: GraphQLString },
author:{
type: AuthorType,
resolve(parent, args){
// console.log(parent)
// return authors.find(i => i.id == parent.authorId)
return Author.findById(parent.authorId)
}
}
})
})
const AuthorType = new GraphQLObjectType({
name: 'Author',
fields: () => ({
id: { type: GraphQLID },
name: { type: GraphQLString },
age: { type: GraphQLInt },
books: {
type: new GraphQLList(BookType),
resolve(parent, args){
// console.log(parent)
// return books.filter(i => i.authorId == parent.id)
return Book.find({ authorId: parent.id})
}
}
})
})
// put both Types above inside the root query
const RootQuery = new GraphQLObjectType({
name: 'RootQueryType',
fields: {
book: {
type: BookType,
args: {id: { type: GraphQLID }},
resolve(parent, args){
//code to get data from db/ or other source
//using lodash
// return _.find(books, {id: args.id })
// return books.find(i => i.id == args.id)
return Book.findById(args.id)
}
},
author: {
type: AuthorType,
args: {id: {type: GraphQLID}},
resolve(parent, args){
// console.log(parent)
// return authors.find(i => i.id == args.id)
return Author.findById(args.id)
}
},
books: {
type: new GraphQLList(BookType),
resolve(parent, args){
// return books
return Book.find({})
}
},
authors: {
type: new GraphQLList(AuthorType),
resolve(parent, args){
// return authors
return Author.find({})
}
},
}
})
//redefine types
const Mutation = new GraphQLObjectType({
name: 'Mutation',
fields: {
addAuthor: {
type: AuthorType,
args: {
name: { type: GraphQLString },
age: { type: GraphQLInt }
},
resolve(parent, args){
//author model from mongoose schema
let author = new Author({
name: args.name,
age: args.age
})
return author.save()
}
},
addBook: {
type: BookType,
args: {
name: { type: GraphQLString },
genre: { type: GraphQLString },
authorId: { type: GraphQLID }
},
resolve(parent, args){
//author model from mongoose schema
let book = new Book({
name: args.name,
genre: args.genre,
authorId: args.authorId
})
return book.save()
}
},
}
})
module.exports = new GraphQLSchema({
query:RootQuery,
mutation: Mutation
})
submitForm(e){
e.preventDefault()
this.props.addBookMutation({
variables: {
name: this.state.name,
genre: this.state.genre,
authorId: this.state.authorId
},
refetchQueries: [{ query: getBooksQuery }]
})
import React from 'react';
import BookList from './components/BookList'
import AddBook from './components/AddBook'
import ApolloClient from 'apollo-boost'
import { ApolloProvider } from 'react-apollo'
//Apollo client set up
const client = new ApolloClient({
uri: '/graphql'
})
function App() {
return (
<ApolloProvider client={client}>
<div id="main">
<h1>Jackie's Reading List</h1>
<BookList/>
<AddBook/>
</div>
</ApolloProvider>
);
}
export default App;
app.js
render() {
console.log(this.props)
return (
<div>
<ul id="book-list" >
{ this.displayBooks() }
</ul>
<BookDetails bookId={this.state.selected} />
</div>
)
query.js
const getBookQuery = gql`
query($id: String){
book(id: ID){
id
name
genre
author{
id
name
age
books{
name
id
}
}
}
}
`
book details.jjs
//this basically says, take graphql and bind geyBooks Query to BookList
export default graphql(getBookQuery, {
options: (props) => {
return {
variables: {
id: props.bookId
}
}
}
})(BookDetails);
@jackie1santana
Copy link
Author

jackie1santana commented Apr 28, 2020

Type Relations

const graphql = require('graphql')
const {
GraphQLObjectType,
GraphQLString,
GraphQLSchema ,
GraphQLID,
GraphQLInt
} = graphql;

//authorId -> is for type relations
const books = [
{ name: 'Name of the Wind', genre: 'Fantasy', id: '1', authorId: '1'},
{ name: 'The final Empire', genre: 'Fantasy', id: '2', authorId: '2'},
{ name: 'The Long Earth', genre: 'Sci-Fi', id: '3', authorId: '3'}
]

const authors = [
{ name: 'Patrick Rothfuss', age: 44, id: '1'},
{ name: 'Brandon Sanderson', age: 42, id: '2'},
{ name: 'Terry Pratchett', age: 66, id: '3'}
]

//defined your 1st object type for the schema
const BookType = new GraphQLObjectType({
name: 'Book',
fields: () => ({
id: { type: GraphQLString},
name: { type: GraphQLString },
genre: { type: GraphQLString },
//type relations
author:{ type: AuthorType, resolve(parent, args){ console.log(parent) return authors.find(i => i.id == parent.authorId) }
}
})
})

const AuthorType = new GraphQLObjectType({
name: 'Author',
fields: () => ({
id: { type: GraphQLString},
name: { type: GraphQLString },
age: { type: GraphQLInt }
})
})

// put both Types above inside the root query
const RootQuery = new GraphQLObjectType({
name: 'RootQueryType',
fields: {
book: {
type: BookType,
args: {id: { type: GraphQLID }},
resolve(parent, args){
//code to get data from db/ or other source
//using lodash
// return _.find(books, {id: args.id })
return books.find(i => i.id == args.id)
}
}, author: { type: AuthorType, args: {id: {type: GraphQLID}}, resolve(parent, args){ return authors.find(i => i.id == args.id) }
}
}
})

module.exports = new GraphQLSchema({
query:RootQuery
})

/graphql query should be set up like this with type relations:
{
book(id: 2){
name,
genre,
author{ name }
}

}

@jackie1santana
Copy link
Author

jackie1santana commented May 1, 2020

React Apollo Client
npm install apollo-boost graphql react-apollo @apollo/react-hooks --save --save-exact

ApolloClient is the same as fetch or axios, Apollo client is specifically for fetching graphql urls.
ApolloProvider injects the data from graphql into JSX/Component from the Apollo Client.

once graphql query is connected to the component, you have all of the graphql data stored in the component props
This connect the graphql to the component => export default graphql(getBooksQuery)(BookList);

console.log(this.props) to see the graphql data fetched.
you can output => loading .. if this.props.data.loading = true & then output the data once this.props.data.loading = false

@jackie1santana
Copy link
Author

jackie1santana commented May 2, 2020

When you want to allow the user to implement a mutation you have to bring in lodash.flowright from lodash
since compose is now depreciated

npm install lodash.flowright --save

import { flowRight as compose } from 'lodash'

use compose to bind multiple queries & mutations

//this basically says, take graphql and bind geyBooks Query to BookList
export default compose(
//use compose to bind queries to client & bind mutations to client
graphql(getAuthorsQuery, {name: "getAuthorsQuery"}),
graphql(addBookMutation, {name: "addBookMutation"})
//both query & mutations are now bound to (addBook)
)(AddBook);

Then you have to pass in query variables into the mutation in order for it to get sent back to the server

@jackie1santana
Copy link
Author

jackie1santana commented May 2, 2020

after you use compose..if the browser states that the props.loading is undefined that means that compose altered the original props object..you need to console.log(this.props). There should be a new named object.

@jackie1santana
Copy link
Author

If you are having rendering issues after implementing a mutation & the mutation is not re rendering immediately use refetchQueries

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment