What is GraphQL?
GraphQL is an open source query and data manipulation language for APIs. It was developed with the goal of providing single endpoints for data, allowing applications to request exactly the data that is needed. This has the benefit of not only simplifying our UI code, but also improving performance by limiting the amount of data that needs to be sent over the wire.
* apollo-server is a library that enables us to work with GraphQL within our Node application. We’ll be using it as a standalone library, but the team at Apollo has also created middleware for working with existing Node web applications in Express, hapi, Fastify, and Koa.
* graphql includes the GraphQL language and is a required peer dependency of apollo-server.
GraphQL schemaA schema is a written representation of our data and interactions. By requiring a schema, GraphQL enforces a strict plan for our API. This is because the API can only return data and perform interactions that are defined within the schema. The fundamental component of GraphQL schemas are object types.
ResolversThough we’ve developed our project with an initial schema and Apollo Server setup, we can’t yet interact with our API. To do so, we’ll introduce resolvers. Resolvers perform exactly the action their name implies; they resolve the data that the API user has requested. We will write these resolvers by first defining them in our schema and then implementing the logic within our JavaScript code. Our API will contain two types of resolvers: queries and mutations.
QueriesA query requests specific data from an API, in its desired format. The query will then return an object, containing the data that the API user has requested. A query never modifies the data; it only accesses it.
Mutations
We use a mutation when we want to modify the data in our API. In our highlight example, we will want to write a mutation to create a new highlight, one to update an existing highlight, and a third to delete a highlight. Similar to a query, a mutation is also expected to return a result in the form of an object, typically the end result of the performed action.
Apollo GrqphQL API Development against an in-memory data object.
Wrapping up
Congratulations! You’ve now successfully built a GraphQL API, using Apollo Server, and can run GraphQL queries and mutations against an in-memory data object. We’ve established a solid foundation for exploring the world of GraphQL API development.
What GraphQL library should I use? Apollo vs Express GraphQL vs GraphQL Yoga?
Apollo Server, it has a cooler playground editor, has great documentation, is commercially backed,and you can use GraphQL template literals.
The main differences between express-graphql and Apollo Server is the way how you define your schemas and types, express-graphql uses programmatic definitions vs Apollo Server uses GraphQL template literals.
const { ApolloServer, gql } = require('apollo-server');
// Construct a schema, using GraphQL schema language
const typeDefs = gql`
type Query {
hello: String
}
`;
// Provide resolver functions for your schema fields
const resolvers = {
Query: {
hello: () => 'Hello world!'
},
};
const server = new ApolloServer({ typeDefs, resolvers });
server.listen().then(({ url }) => {
console.log(`🚀 Server ready at ${url}`)
});
Dependency :
{
"name": "apollo-demo",
"version": "0.0.1",
"description": "Simple example covering the very basics of Graphql, and Apollo",
"main": "index.js",
"scripts": {
"start": "node index.js"
},
"dependencies": {
"apollo-server": "2.0.0-rc.8",
"graphql": "^0.13.2"
},
"engines": {
"node": "8.x"
},
"repository": {
"url": "https://glitch.com/edit/#!/apollo-server"
},
"license": "MIT",
"keywords": [
"apollo",
"glitch",
"graphql"
]
}
Example 1
Index.js
const { ApolloServer, gql } = require('apollo-server')
const crypto = require('crypto');
const db = {
users: [
{ id: '1', email: 'alex@gmail.com', name: 'Alex', avatarUrl: 'https://gravatar.com/...' },
{ id: '2', email: 'max@gmail.com', name: 'Max', avatarUrl: 'https://gravatar.com/...' }
],
messages: [
{ id: '1', userId: '1', body: 'Hello', createdAt: Date.now() },
{ id: '2', userId: '2', body: 'Hi', createdAt: Date.now() },
{ id: '3', userId: '2', body: 'Whats app', createdAt: Date.now() },
]
}
//We should have the definition for Query and Mutation type properties in resolver
//gql is a template literal call
const typeDefs = gql`
type Query{
users: [User!]!
user(id: ID!): User
messages: [Message!]!
}
type Mutation {
addUser(email: String!, name: String): User!
}
type User{
id: ID!
email: String!
name: String
avatarUrl: String
messages: [Message!]!
}
type Message {
id: ID!
body: String!
createdAt: String!
}
`
//Query is the top level resolvers
//Anything goes inside the rootQuery also needs to be presents on the Query resolver map
//root - rootvalue you can pass into the server optionally
const resolvers = {
Query: {
users: () => db.users,
user: (root, { id }) => db.users.find(user => user.id === id),
messages: () => db.messages
},
Mutation: {
addUser: (root, { email, name }) => {
const user = {
id: crypto.randomBytes(10).toString(),
email,
name
}
db.users.push(user);
return user
}
},
User: {
messages: user => db.messages.filter(message => message.userId === user.id)
}
}
const server = new ApolloServer({ typeDefs, resolvers})
//const server = new ApolloServer({ typeDefs, mocks: true})
server.listen().then(({url})=>{console.log(url)})
What happen if the users has the reference of the message. The message is another collection
What do we do with these messages over here.
users {
email
message {
id
body
}
}
Because the messages have to be resolved on the user object . What if we make a query that asks for messages on the user so we’re gonna need to find a way to deal with those messages now in Express
1. express-graphql does not have much cohice, because your rootValue object only allows you to create top-level resolvers
2. Whith Apollo-server everything actually changes because now you can go ahead and create nested types so you can actually go ahead and create a definition for a user so anything that you want to resolve on the user that’s not available on the actual data source,
const db={
users: [
{ id: '1', email: 'alex@gmail.com', name: 'Alex', avatarUrl: 'https://gravatar.com/...' },
{ id: '2', email: 'max@gmail.com', name: 'Max', avatarUrl: 'https://gravatar.com/...' }
],
messages: [
{id: '1', userId: '1', body:'Hello', createdAt: Date.now()},
{id: '2', userId: '2', body:'Hi', createdAt: Date.now()},
{id: '3', userId: '2', body:'Whats app', createdAt: Date.now()},
]
}
example messages that actually not available on the data source we can go ahead and create a definition for those messages inside of that user resolver function.
In this case we do need to provide one argument and it’s actually going to be the root value now
I told you that the root value inside of query or inside of mutation is typically going to be undefined unless you provide a value for root value to your server, in this case the root object will actually be the user now that’s because the user is being resolved on the user’s collection
so far example if you make a query to users and you also include a sub selection of messages on those users those messages will be resolved on the user object. That’s why this user key over here anything that’s listed under that key will alos be resolved with the user object itslef, so we can basically just rename root to user just for clarity and this
one will refer to a single individual user object when this function is being called so we can go ahead and reference the user ID like this “user.id”. We do need to actually check those messages against the user ID to filter them down accordingly
User: {
//messages: root => db.messages.filter(message => message.userId === this.id)
messages: user => db.messages.filter(message => message.userId === user.id)
}
Dependency
{
"name": "GraphQL_intro",
"version": "1.0.0",
"main": "index.js",
"license": "MIT",
"scripts":{
"watch":"nodemon"
},
"dependencies": {
"apollo-server": "^2.15.0",
"graphql": "^15.1.0"
},
"devDependencies": {
"nodemon": "^2.0.4"
}
}
https://www.youtube.com/results?search_query=formik+material+ui+tamil
Code Realm – React Material
Use JavaScript Objects In Material UI Select Component Using React (Set Default Value)
ApolloGraphQL
=============
Will Ward : https://www.youtube.com/watch?v=h-ZCVUAzR-0&list=PLASldBPN_pkDUuOzyPotAkKmvwqyDoA0g
https://www.apollographql.com/docs/
https://developer-log.netlify.app/full-stack-apollo-graphql-tutorial-pt-1-setup/
What GraphQl ?
What we have in express is same, just we need Type definition and schema. We are making some request like Query and Mutations from client side. Those we need to define some where and our server needs to be bootstrap with all avaiable query at the backend and all avaiable mutation at the backend.
We can define the query and mutation in my schema . For that first doing a type definition (ex : User, Recipe..from there we will returning User object, Recipe object) then define the query and mutation then defining the implementation of those queries and mutation in the resolvers.
We will not be returning only single attribute otherwise for the single attribute you don’t need a type definition
Here i have a type query and in the type query here these all the queries will be triggering from the client-side
type Query {
user(Id: Int!) : User; //User is the returning object
When i hit the query user , i should get a user object. When i have all users , what should i get the user array (allUsers(): [User !]). Another we can get whole recipe , it will return an array of recipes. Below is the query to fetch data from the server.
Ex : type Query {
user(Id: Int!) : User; //get user by id
allUsers(): [User !] // get all users
allRecipe: [Recipe !] // get all recipe
recipe(Id: Int!): Recipe // get single recipe
Now there can be some mutations which we’ll be talking. Mutations are same as query only the differences will be using mutation for them like createUser(…),createRecipe(…). This mutation will be used for creating the resource and updating resource. They will have enough payload (name: string, )From client-side will be triggering only query, mutation and subscription .
To implement all this we will use resolver
https://www.linkedin.com/pulse/alternative-rest-api-graphql-your-business-needs-tarun-sharma?articleId=6151613129752064000#comments-6151613129752064000&trk=public_profile_article_view
Example
CHAT :
-_id : ObjectId,
-title
-users : [ObjectId] -> User
-lastmessage: ObjectId
Chat / resolver
startChat: async(root, args, {req}, info)=> {
const chat = await Chat.create({title, users: userIds})
await User.updateMany(
{_id : {'$in' : userIds} },
{$push: {chats: chat}}
)
return chat
}
Mutation: {
//every messages going to have a chat ID property
Chat: {
messages: async (chat, args, context, info) => {
return (await Message.find('chat: chat.id')
//return user.chats
},
users: async (chat, args, context, info) => {
return (await chat.populate('users').execPopulate()).users
},
lastMessage: async (chat, args, context, info) => {
return (await chat.populate('lastMessage').execPopulate()).lastMessage
}
}
}
Query
query {
users {
id
chats {
id
users {
id
chats {
id
}
}
messages {
id
}
lastMessage {
id
}
}
}
}
USER :
-_id: ObjectId
-name
-email
-username
-password
-chats : [OjbectId] -> Chat
//Need to specify a custom resolution logic for the chats of the user and I’ll put in the key referring to the user and we’re going to specify chats on it, once again it’s a regular resolver with the exception that the root object in this case is going to be the actual user model
Mutation: {
User: {
chats: async (user, args, context, info) => {
return (await user.populate('chats').execPopulate()).chats
//return user.chats
}
}
}
// user = {chats: [1,2,3]}
MESSAGE :
-_id : ObjectId
-body
-sender: ObjectId -> User
-chat: OjbectId -> Chat
Reference
Apollo
Apollo Tutorial
Apollo Server Docs
ApolloGraphQL github
Apollographql/graphql-tag – github
type schema system-Apollo Tutorial
scalable-modular-structure-graphql-node-api
modularizing-your-graphql-schema-code
express-graphql-tutorial
Apollo Server PlayList