-
-
Save jackie1santana/bc4c8be7c39477596683e296f5f9daed to your computer and use it in GitHub Desktop.
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); |
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 }
}
}
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
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
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.
If you are having rendering issues after implementing a mutation & the mutation is not re rendering immediately use refetchQueries
Install these npm packages: