LESSON 23 ยท GRAPHQL API

GraphQL ๐Ÿ”ฎ
แˆแŠ• แ‰ตแˆแˆแŒ‹แˆˆแˆ… แ‰ฅแ‰ป แˆตแŒ แŠ!

REST API แˆฒแŒ แ‰€แˆ™ แ‰ฅแ‹™ แ‹แˆ‚แ‰ฅ แ‹ˆแ‹ญ แ‰ตแŠ•แˆฝ แ‹แˆ‚แ‰ฅ แ‹ญแˆ˜แŒฃแˆƒแˆ โ€” GraphQL แ‹ซแˆตแˆแˆแŒแˆ… แ‰ฅแ‰ป แ‹ญแˆฐแŒฃแˆƒแˆ!

โœ๏ธ แ‹จแˆฐแˆซแ‹: @AppMinds_ET ยท EthioCode SoftSelect
01
GraphQL แˆแŠ•แ‹ตแŠ• แАแ‹?

GraphQL โ€” Facebook (Meta) 2015 แ‹“.แˆ แ‹ซแˆฐแˆซแ‹ แ‹จ API query language แАแ‹แข REST API แ‹แŠ•แ‰ณ แŒฅแ‰…แˆ แˆ‹แ‹ญ แˆŠแ‹แˆ แ‹ญแ‰ฝแˆ‹แˆแข

แ‹‹แŠ“แ‹ แˆแ‹ฉแАแ‰ฑ: REST แ‹แˆตแŒฅ Server แˆแŠ• แ‹ญแˆฐแŒฃแˆƒแˆ แ‰ฅแˆŽ แ‹ญแ‹ˆแˆตแŠ“แˆ โ€” GraphQL แ‹แˆตแŒฅ แŠ แŠ•แ‰ฐ แˆแŠ• แ‰ตแˆแˆแŒ‹แˆˆแˆ… แ‰ฅแˆˆแˆ… แ‰ตแŒ แ‹ญแ‰ƒแˆˆแˆ…!

๐Ÿ’ก แˆแˆณแˆŒ แ‰ฐแŒ แ‰…แˆž แˆˆแˆ˜แˆจแ‹ณแ‰ต โ€” แˆแŒแ‰ฅ แ‰คแ‰ต แˆแˆณแˆŒ
REST API
๐Ÿฝ๏ธ แˆ™แˆ‰ แˆแŠ“แˆŒ
แŠฅแŠ•แŒ€แˆซ แ‰ฅแ‰ป แ‰ตแˆแˆแŒ‹แˆˆแˆ… โ€” แˆ™แˆ‰ แˆแŠ“แˆŒ แ‹ญแˆฐแŒฅแˆƒแˆ (แˆตแŒ‹แฃ แแˆญแแˆญแฃ แˆปแ‹ญ แˆแˆ‰ แŠ แ‰ฅแˆฎ!)
โ†’
GraphQL
๐ŸŽฏ แˆแ‰ƒแ‹ฐแŠ› แˆแŠ“แˆŒ
"แŠฅแŠ•แŒ€แˆซ แ‰ฅแ‰ป แˆตแŒ แŠ" แ‰ตแˆ‹แˆˆแˆ… โ€” แŠฅแŠ•แŒ€แˆซ แ‰ฅแ‰ป แ‹ญแˆฐแŒฅแˆƒแˆ! แ‰ตแŠญแŠญแˆˆแŠ› แ‹ซแˆตแˆแˆแŒแˆ… แ‰ฅแ‰ป!
REST แ‰ฝแŒแˆญ
โŒ Over-fetching
name แ‰ฅแ‰ป แ‰ตแˆแˆแŒ‹แˆˆแˆ… โ€” user แˆ™แˆ‰ แˆแˆ‰ แ‹ญแˆฐแŒฅแˆƒแˆ (id, email, address, posts...)
โ†’
GraphQL แˆ˜แแ‰ตแˆ”
โœ… Exact data
{ user { name } } โ€” name แ‰ฅแ‰ป แ‹ญแˆฐแŒฅแˆƒแˆ! แˆแŠ•แˆ extra data!
02
REST vs GraphQL โ€” แˆแ‹ฉแАแ‰ฑ

REST API แ‹แˆตแŒฅ แ‰ฅแ‹™ endpoints แŠ แˆ‰ โ€” /users, /posts, /commentsโ€ฆ GraphQL แ‹แˆตแŒฅ แŠ แŠ•แ‹ต endpoint แ‰ฅแ‰ป (/graphql) แŠ แˆˆ โ€” แˆแˆ‰แˆ query แ‹ˆแ‹ฐ แ‹ซ แŠ แŠ•แ‹ต endpoint แ‹ญแˆ„แ‹ณแˆ!

REST API
// User name แˆˆแˆ›แˆแŒฃแ‰ต:
GET /api/users/1

// Response (แˆแˆ‰แˆ แ‹ญแˆฐแŒฃแˆƒแˆ):
{
 "id": 1,
 "name": "Abel",
 "email": "...",
 "address": {...},
 "posts": [...],
 "settings": {...}
}
โŒ name แ‰ฅแ‰ป แˆแˆˆแŒแŠ• โ€” แˆแˆ‰แˆ แˆ˜แŒฃ!
GraphQL
// User name แˆˆแˆ›แˆแŒฃแ‰ต:
POST /graphql

// Query (แˆแŠ• แ‰ตแˆแˆแŒ‹แˆˆแˆ… แ‰ฅแ‰ป):
{
 user(id: 1) {
  name
 }
}

// Response:
{ "name": "Abel" }
โœ… name แ‰ฅแ‰ป! แˆแŠ•แˆ extra!
03
GraphQL แˆฆแˆตแ‰ต Operations

GraphQL แ‹แˆตแŒฅ 3 แ‹“แ‹ญแАแ‰ต operations แŠ แˆ‰ โ€” Query (แˆˆแˆ›แŠ•แ‰ แ‰ฅ)แฃ Mutation (แˆˆแˆ˜แ‰€แ‹จแˆญ/แˆˆแˆ˜แแŒ แˆญ)แฃ Subscription (แˆˆ real-time)แข REST แ‹แˆตแŒฅ GET/POST/PUT/DELETE แ‹แŠ•แ‰ณ แŠฅแАแ‹šแˆ… แŠ“แ‰ธแ‹!

Operations แˆ แŠ•แŒ แˆจแ‹ฅ:

OPERATIONแˆแŠ• แ‹ซแ‹ฐแˆญแŒ‹แˆ?REST แˆแ‰ตแŠญแˆแˆณแˆŒ
query แ‹แˆ‚แ‰ฅ แˆ›แŠ•แ‰ แ‰ฅ / Read data GET query { users { name } }
mutation แ‹แˆ‚แ‰ฅ แแŒ แˆญ/แ‰€แ‹ญแˆญ/แˆฐแˆญแ‹ POST/PUT/DELETE mutation { createUser(...) }
subscription Real-time แˆˆแ‹แŒฅ แˆ›แ‹ณแˆ˜แŒฅ WebSocket subscription { newMessage }

GraphQL แˆ‚แ‹ฐแ‰ต โ€” แŠจ Client แŠฅแˆตแŠจ DB:

01
๐Ÿ–ฅ๏ธ
Client
Query แ‹ญแƒแ‹แˆ
{ user { name } }
โ†’
02
๐Ÿ“ก
HTTP POST
แ‹ˆแ‹ฐ /graphql
แŠ แŠ•แ‹ต endpoint
โ†’
03
๐Ÿงฉ
Resolver
Query แŠ• แ‹ญแˆฐแˆซแ‹‹แˆ
DB แ‹ญแŒ แ‹ญแ‰ƒแˆ
โ†’
04
๐Ÿ—„๏ธ
Database
แ‹แˆ‚แ‰ฅ แ‹ญแˆฐแŒฃแˆ
โ†’
05
๐Ÿ“ฆ
JSON
แ‹ซแˆตแˆแˆแŒ แ‰ฅแ‰ป
แ‹ญแˆ˜แˆˆแˆณแˆƒแˆ
04
Schema แŠฅแŠ“ Resolvers

Schema โ€” GraphQL แ‹แˆตแŒฅ แˆแŠ• types แŠ แˆ‰แฃ แˆแŠ• queries/mutations แ‹ญแˆแ‰€แ‹ณแˆ‰ แˆแˆ‰ แ‹ญแƒแ‹แˆ‰แข แŠฅแŠ•แ‹ฐ Prisma schema แ‹“แ‹ญแАแ‰ต แАแ‹!

Resolver โ€” แ‹ซ query แˆฒแŒ แ‹จแ‰… แˆแŠ• แˆ›แ‹ตแˆจแŒ? DB แŠ• แŒ แ‹ญแ‰…? แˆแŠ• แ‹ญแˆ˜แˆˆแˆต? แˆแˆ‰ แ‹ญแƒแ‹แˆ!

schema.graphql โ€” Type Definitions
# GraphQL Schema โ€” แˆแŠ• types แŠ แˆ‰?
type User {
  id:    ID!           # ! = required (แŒแ‹ดแ‰ณ)
  name:  String!
  email: String!
  posts: [Post]       # User แŠ• Posts แŒ‹แˆญ relation
}

type Post {
  id:      ID!
  title:   String!
  content: String    # แ‹ซแˆˆ ! = optional
  author:  User!
}

# แˆแŠ• queries แ‹ญแˆแ‰€แ‹ณแˆ‰?
type Query {
  users:         [User]     # แˆแˆ‰แˆ users
  user(id: ID!):  User      # แŠ แŠ•แ‹ต user
  posts:         [Post]     # แˆแˆ‰แˆ posts
}

# แˆแŠ• mutations แ‹ญแˆแ‰€แ‹ณแˆ‰?
type Mutation {
  createUser(name: String!, email: String!): User
  deleteUser(id: ID!): Boolean
}
resolvers.js โ€” Schema แŠ• แˆ•แ‹ซแ‹ แ‹ซแ‹ฐแˆญแŒ‹แˆ‰
const resolvers = {

  // Query resolvers โ€” แˆฒแŒ แ‹จแ‰ แˆแŠ• แ‹ซแ‹ฐแˆญแŒ‹แˆ‰?
  Query: {
    // users query โ†’ DB แˆแˆ‰แˆ users แŠ แˆแŒฃ
    users: async () => {
      return await prisma.user.findMany();
    },

    // user(id) query โ†’ แŠ แŠ•แ‹ฑแŠ• user แŠ แˆแŒฃ
    user: async (_, { id }) => {
      return await prisma.user.findUnique({ where: { id } });
    },
  },

  // Mutation resolvers โ€” แˆฒแ‰€แˆฉ แˆแŠ• แ‹ซแ‹ฐแˆญแŒ‹แˆ‰?
  Mutation: {
    // createUser โ†’ แŠ แ‹ฒแˆต user แแŒ แˆญ
    createUser: async (_, { name, email }) => {
      return await prisma.user.create({ data: { name, email } });
    },

    // deleteUser โ†’ user แˆฐแˆญแ‹
    deleteUser: async (_, { id }) => {
      await prisma.user.delete({ where: { id } });
      return true;
    },
  },

  // Type resolvers โ€” relation แ‹ซแˆตแ‰ฐแŠ“แŒแ‹ณแˆ‰
  User: {
    posts: async (parent) => {
      return await prisma.post.findMany({ where: { authorId: parent.id } });
    },
  },
};
05
Queries แŠฅแŠ“ Mutations โ€” แˆแˆณแˆŒแ‹Žแ‰ฝ
graphql-examples.graphql โ€” แˆ™แˆ‰ แˆแˆณแˆŒแ‹Žแ‰ฝ
# โ”€โ”€ QUERY โ€” แ‹แˆ‚แ‰ฅ แˆ›แŠ•แ‰ แ‰ฅ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€

# แˆแˆ‰แˆ users โ€” name แŠฅแŠ“ email แ‰ฅแ‰ป แˆแˆแŒ‹แˆˆแˆ
query {
  users {
    name
    email
  }
}

# แŠ แŠ•แ‹ต user โ€” id แฃ name แฃ posts แŒญแˆแˆญ
query GetUserWithPosts {
  user(id: "1") {
    id
    name
    posts {
      title
      content
    }
  }
}

# โ”€โ”€ MUTATION โ€” แ‹แˆ‚แ‰ฅ แแŒ แˆญ/แ‰€แ‹ญแˆญ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€

# แŠ แ‹ฒแˆต user แแŒ แˆญ
mutation CreateNewUser {
  createUser(
    name: "Abel Tesfaye"
    email: "abel@ethiocode.com"
  ) {
    id
    name
    email
  }
}

# user แˆฐแˆญแ‹
mutation {
  deleteUser(id: "3")
}

# โ”€โ”€ VARIABLES โ€” Query แŠ• แ‰ฐแˆˆแ‹‹แ‹‹แŒญ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
query GetUser($userId: ID!) {
  user(id: $userId) {
    name
    email
  }
}
# Variables: { "userId": "1" }
06
Live GraphQL Playground

GraphQL Simulator! Query แŒปแ โ†’ Run โ†’ Response แ‹ญแ‰ณแ‹ซแˆƒแˆ! Fields Selector โ†’ แˆแŠ• fields แ‰ตแˆแˆแŒ‹แˆˆแˆ… แˆแˆจแŒฅ โ†’ Query แˆซแˆฑ แ‹ญแˆฐแˆซแˆƒแˆ!

GraphQL Playground โ€” /graphql
Apollo Server v4
๐Ÿ“ Query Editor
๐ŸŽฏ Field Selector
โœ๏ธ Mutations
GRAPHQL QUERY
RESPONSE
โ† Run แ‰แˆแ แŒซแŠ• โ†’ result แ‹ญแ‰ณแ‹ซแˆƒแˆ

แˆแŠ• fields แ‰ตแˆแˆแŒ‹แˆˆแˆ…? แˆแˆจแŒฅ โ†’ Query แˆซแˆฑ แ‹ญแˆฐแˆซแˆแˆƒแˆ!
แ‹ญแˆ… แАแ‹ GraphQL แŒฅแ‰…แˆ™ โ€” แ‹ซแˆตแˆแˆแŒแˆ… fields แ‰ฅแ‰ป!

User Fields
Generated Query
โ† Fields แˆแˆจแŒฅ
โ† Run แ‰แˆแ แŒซแŠ•

Mutation = แ‹แˆ‚แ‰ฅ แแŒ แˆญแฃ แ‰€แ‹ญแˆญแฃ แˆฐแˆญแ‹! Query แ‹แŠ•แ‰ณ mutation แ‰ตแŒ แ‰€แˆ›แˆˆแˆ…!

โ† Mutation แŠ• แˆžแŠญแˆญ
07
แ‹‹แŠ“ แ‹‹แŠ“ แАแŒฅแ‰ฆแ‰ฝ
1
๐Ÿ”ฎ GraphQL = แ‹ซแˆตแˆแˆแŒแˆ… แ‰ฅแ‰ป แŒ แ‹ญแ‰…

REST API แˆแŠ• แ‹ญแˆฐแŒฃแˆƒแˆ แ‰ฅแˆŽ แ‹ญแ‹ˆแˆตแŠ“แˆ โ€” GraphQL แŠ แŠ•แ‰ฐ แˆแŠ• แ‰ตแˆแˆแŒ‹แˆˆแˆ… แ‰ฅแˆˆแˆ… แ‰ตแŒ แ‹ญแ‰ƒแˆˆแˆ…! Over-fetching (แ‰ฅแ‹™ แˆแŒฃ) แŠฅแŠ“ Under-fetching (แ‰ตแŠ•แˆฝ แˆแŒฃ) แ‰ฝแŒแˆญ แ‹ซแˆตแ‹ˆแŒฃแˆƒแˆ!

2
๐Ÿ“ แŠ แŠ•แ‹ต Endpoint แ‰ฅแ‰ป โ€” /graphql

REST แ‹แˆตแŒฅ /users, /posts, /commentsโ€ฆ แ‰ฅแ‹™ endpoints แŠ แˆ‰ โ€” GraphQL แ‹แˆตแŒฅ /graphql แŠ แŠ•แ‹ต แ‰ฅแ‰ป แАแ‹! แˆแˆ‰แˆ query แ‹ˆแ‹ฐ แ‹ซ แ‹ญแˆ„แ‹ณแˆ‰!

3
๐Ÿงฉ Schema + Resolvers โ€” แˆแˆˆแ‰ฑ แ‰…แˆญแˆถแ‰ฝ

Schema = แˆแŠ• types แŠ แˆ‰? แˆแŠ• queries แ‹ญแˆแ‰€แ‹ณแˆ‰? | Resolver = แ‹ซ query แˆฒแŒ แ‹จแ‰… แˆแŠ• แ‹ซแ‹ฐแˆญแŒ‹แˆ‰? DB แ‹ญแŒ แ‹ญแ‰ƒแˆ‰!

4
โšก 3 Operations โ€” Query / Mutation / Subscription

query = แˆ›แŠ•แ‰ แ‰ฅ (REST GET) | mutation = แแŒ แˆญ/แ‰€แ‹ญแˆญ/แˆฐแˆญแ‹ (REST POST/PUT/DELETE) | subscription = Real-time (WebSocket)

5
๐Ÿ”— Relations แ‰ แ‰€แˆ‹แˆ‰ โ€” แŠ แ‰ฅแˆฎ แŒ แ‹ญแ‰…

User + Posts แŠ แŠ•แ‹ต query แ‹แˆตแŒฅ แŠ แˆแŒฃ! { user { name posts { title } } } โ€” REST แ‹แˆตแŒฅ แˆแˆˆแ‰ต requests แ‹ซแˆตแˆแˆแŒ‹แˆ‰ แАแ‰ แˆญ!

08
Quiz
โ“ GraphQL แ‹แˆตแŒฅ แŠ แ‹ฒแˆต user แˆˆแˆ˜แแŒ แˆญ แ‹จแ‰ฑ operation แ‰ตแŒ แ‰€แˆ›แˆˆแˆ…?
GraphQL แ‹แˆตแŒฅ data แˆˆแˆ˜แแŒ แˆญ/แˆˆแˆ˜แ‰€แ‹จแˆญ/แˆˆแˆ˜แˆฐแˆญแ‹ แ‹จแˆšแŒ แ‰…แˆ˜แ‹ operation?
Aquery
Bmutation โœ…
Csubscription
DPOST request