๋ธ”๋กœ๊ทธ

๐Ÿฅณ Gato GraphQL v0.9์ด ์ถœ์‹œ๋˜์—ˆ์Šต๋‹ˆ๋‹ค!

Leonardo Losoviz
์ž‘์„ฑ์ž: Leonardo Losoviz ยท

์•ฝ 1.5๋…„์˜ ๊ฐœ๋ฐœ ๊ธฐ๊ฐ„๊ณผ 16,000๊ฐœ ์ด์ƒ์˜ ์ปค๋ฐ‹์„ ๊ฑฐ์ณ, Gato GraphQL์˜ ์ƒˆ ๋ฒ„์ „์ด ๋“œ๋””์–ด ์ถœ์‹œ๋˜์—ˆ์Šต๋‹ˆ๋‹ค! ๐Ÿฅณ

๋ฒ„์ „ 0.9์€ ํ”Œ๋Ÿฌ๊ทธ์ธ ์—ญ์‚ฌ์ƒ ๊ฐ€์žฅ ํฐ ๋ฆด๋ฆฌ์Šค์ž…๋‹ˆ๋‹ค. ๋ณ€๊ฒฝ ๋กœ๊ทธ๋Š” ์—ฌ๊ธฐ์—์„œ ํ™•์ธํ•˜์‹ค ์ˆ˜ ์žˆ์œผ๋ฉฐ, ๋ชจ๋“  ์ƒˆ ๊ธฐ๋Šฅ์˜ ์ „์ฒด ๋‚ด์—ญ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค:

github.com/GatoGraphQL/GatoGraphQL/releases/tag/0.9.3

์ด ๋ฌธ์„œ๋Š” ๋งค์šฐ ๊ธธ๊ธฐ ๋•Œ๋ฌธ์— (์ฝ๋Š” ๋ฐ 40๋ถ„ ์ด์ƒ ์†Œ์š”!), ์•„๋ž˜์— ๊ฐ€์žฅ ์ค‘์š”ํ•œ ๋ณ€๊ฒฝ ์‚ฌํ•ญ์˜ TL;DR์„ ์ •๋ฆฌํ–ˆ์Šต๋‹ˆ๋‹ค.

GraphQL ์Šคํ‚ค๋งˆ์˜ ๋Œ€ํญ ํ™•์ถฉ

WordPress ๋ฐ์ดํ„ฐ ๋ชจ๋ธ์ด GraphQL ์Šคํ‚ค๋งˆ์— ๋Œ€ํญ ๋งคํ•‘๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

GraphQL ์Šคํ‚ค๋งˆ

๊ทธ ์ค‘์—์„œ๋„ ์Šคํ‚ค๋งˆ์—๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๊ฐœ์„  ์‚ฌํ•ญ์ด ํฌํ•จ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค:

  • ํ…Œ๋งˆ ๋ฐ ํ”Œ๋Ÿฌ๊ทธ์ธ์„ ํฌํ•จํ•œ ๋ชจ๋“  CPT์—์„œ ๋ฐ์ดํ„ฐ ์ฟผ๋ฆฌ ๊ฐ€๋Šฅ
  • ์ปค์Šคํ…€ ํƒ์†Œ๋…ธ๋ฏธ(ํƒœ๊ทธ์™€ ์นดํ…Œ๊ณ ๋ฆฌ) ๋งคํ•‘
  • ๋” ์ ํ•ฉํ•œ GraphQL ํƒ€์ž… ์ƒ์„ฑ ๋ฐ ๋ฐ˜ํ™˜ (์˜ˆ: HTML, URL, DateTime)
  • ์ธํ’‹ ๊ฐ์ฒด๋ฅผ ํ†ตํ•œ ํ•„๋“œ ์ธ์ˆ˜ ์ •๋ฆฌ
  • oneof ์ธํ’‹ ๊ฐ์ฒด๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋‹ค์–‘ํ•œ ์†์„ฑ(์˜ˆ: id, slug)์œผ๋กœ ์—”ํ‹ฐํ‹ฐ ์„ ํƒ
  • ๋ฎคํ…Œ์ด์…˜ ํŽ˜์ด๋กœ๋“œ ๋ฐ˜ํ™˜
  • ์„ค์ •(wp_options๋กœ๋ถ€ํ„ฐ) ๋ฐ ๋ฉ”ํƒ€ ๊ฐ’(ํฌ์ŠคํŠธ, ์‚ฌ์šฉ์ž, ๋Œ“๊ธ€, ํƒ์†Œ๋…ธ๋ฏธ์šฉ) ์ฟผ๋ฆฌ

์ปค์Šคํ…€ ์Šค์นผ๋ผ

GraphQL ์„œ๋ฒ„์— ์ปค์Šคํ…€ ์Šค์นผ๋ผ ํƒ€์ž… ์ง€์›์ด ์ถ”๊ฐ€๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ์ปค์Šคํ…€ ์Šค์นผ๋ผ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ํ•„๋“œ ์ธ์ˆ˜๋ฅผ ํ†ตํ•œ ์ž…๋ ฅ ์ˆ˜์‹ ์ด๋‚˜ ์‘๋‹ต์—์„œ์˜ ์ปค์Šคํ…€ ์ถœ๋ ฅ ์ธ์‡„ ๋“ฑ ๋ฐ์ดํ„ฐ๋ฅผ ๋” ์ ์ ˆํ•˜๊ฒŒ ํ‘œํ˜„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์—ฌ๋Ÿฌ ํ‘œ์ค€ ์ปค์Šคํ…€ ์Šค์นผ๋ผ ํƒ€์ž…์ด ๊ตฌํ˜„๋˜์–ด GraphQL ์Šคํ‚ค๋งˆ์—์„œ ์ฆ‰์‹œ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค:

  • Date
  • DateTime
  • Email
  • HTML
  • URL
  • URLAbsolutePath

์ปค์Šคํ…€ enum

์ปค์Šคํ…€ enum ํƒ€์ž…์ด ์ด์ œ ์ง€์›๋ฉ๋‹ˆ๋‹ค. enum์€ ํŠน์ • ํ—ˆ์šฉ ๊ฐ’์˜ ์ง‘ํ•ฉ์œผ๋กœ ์ œํ•œ๋œ ํŠน์ˆ˜ํ•œ ์ข…๋ฅ˜์˜ ์Šค์นผ๋ผ์ž…๋‹ˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ๋‹ค์Œ์ด ๊ฐ€๋Šฅํ•ด์ง‘๋‹ˆ๋‹ค:

  • ์ด ํƒ€์ž…์˜ ์ธ์ˆ˜๊ฐ€ ํ—ˆ์šฉ๋œ ๊ฐ’ ์ค‘ ํ•˜๋‚˜์ธ์ง€ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ
  • ํƒ€์ž… ์‹œ์Šคํ…œ์„ ํ†ตํ•ด ํ•„๋“œ๊ฐ€ ํ•ญ์ƒ ์œ ํ•œํ•œ ๊ฐ’์˜ ์ง‘ํ•ฉ ์ค‘ ํ•˜๋‚˜์ž„์„ ์ „๋‹ฌ

์—ฌ๋Ÿฌ enum ํƒ€์ž…์ด ๊ตฌํ˜„๋˜์–ด GraphQL ์Šคํ‚ค๋งˆ์—์„œ ์ ์ ˆํ•œ ๊ณณ์— ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค. ๋‹ค์Œ์ด ํฌํ•จ๋ฉ๋‹ˆ๋‹ค:

  • CommentOrderByEnum
  • CommentStatusEnum
  • CommentTypeEnum
  • CustomPostOrderByEnum
  • CustomPostStatusEnum
  • MediaItemOrderByEnum
  • MenuOrderByEnum
  • TaxonomyOrderByEnum
  • UserOrderByEnum

์ธํ’‹ ๊ฐ์ฒด

GraphQL ์„œ๋ฒ„๋Š” ์ด์ œ ์ธํ’‹ ํƒ€์ž…์„ ์ง€์›ํ•˜๋ฉฐ, ๊ณ ์œ ํ•œ ์ธํ’‹ ๊ฐ์ฒด๋ฅผ GraphQL ์Šคํ‚ค๋งˆ์— ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ธํ’‹ ๊ฐ์ฒด๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ํ•„๋“œ์— ๋Œ€ํ•œ ์ž…๋ ฅ์œผ๋กœ ๋ณต์žกํ•œ ๊ฐ์ฒด๋ฅผ ์ „๋‹ฌํ•  ์ˆ˜ ์žˆ์–ด, ๋ฎคํ…Œ์ด์…˜์— ํŠนํžˆ ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค.

์Šคํ‚ค๋งˆ์˜ ์ ์ ˆํ•œ ๊ณณ์— ์—ฌ๋Ÿฌ ์ธํ’‹ ๊ฐ์ฒด๊ฐ€ ์ถ”๊ฐ€๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ๋ฐ์ดํ„ฐ๋ฅผ ์ฟผ๋ฆฌํ•˜๋Š” ํ•„๋“œ(posts, users, comments ๋“ฑ)๋Š” ํ•„๋“œ ์ธ์ˆ˜ filter, sort, pagination ์•„๋ž˜์— ๋ณต์žกํ•œ ์ธํ’‹ ๊ฐ์ฒด๋ฅผ ์ˆ˜์‹ ํ•˜๊ณ , ๋ฐ์ดํ„ฐ๋ฅผ ๋ณ€๊ฒฝํ•˜๋Š” ํ•„๋“œ(createPost, addCommentToCustomPost ๋“ฑ)๋Š” ํ•„๋“œ ์ธ์ˆ˜ input ์•„๋ž˜์— ์ธํ’‹ ๊ฐ์ฒด๋ฅผ ์ˆ˜์‹ ํ•ฉ๋‹ˆ๋‹ค.

Oneof ์ธํ’‹ ๊ฐ์ฒด

ใ€Œoneofใ€ ์ธํ’‹ ๊ฐ์ฒด๋Š” ํŠน์ˆ˜ํ•œ ์ธํ’‹ ๊ฐ์ฒด๋กœ, ์ธํ’‹ ํ•„๋“œ ์ค‘ ์ •ํ™•ํžˆ ํ•˜๋‚˜๋งŒ ์ž…๋ ฅ์œผ๋กœ ์ œ๊ณตํ•ด์•ผ ํ•˜๋ฉฐ, ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ ์˜ค๋ฅ˜๊ฐ€ ๋ฐ˜ํ™˜๋ฉ๋‹ˆ๋‹ค. ์ด ๋™์ž‘์€ ์ž…๋ ฅ์— ๋‹คํ˜•์„ฑ์„ ๋„์ž…ํ•ฉ๋‹ˆ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด, ํ•„๋“œ Root.post์— ํ•„๋“œ ์ธ์ˆ˜ by๊ฐ€ ์ถ”๊ฐ€๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ์ด๋Š” oneof ์ธํ’‹ ๊ฐ์ฒด๋กœ, id๋‚˜ slug ๋“ฑ ๋‹ค์–‘ํ•œ ์†์„ฑ์„ ์‚ฌ์šฉํ•˜์—ฌ ํฌ์ŠคํŠธ๋ฅผ ๊ฒ€์ƒ‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

{
  postByID: post(by: {
    id: 1
  }) {
    id
    title
  }
 
  postBySlug: post(by: {
    slug: "hello-world"
  }) {
    id
    title
  }
}

์ด ๋ฐฉ์‹์˜ ์žฅ์ ์€ ํ•˜๋‚˜์˜ ํ•„๋“œ๋กœ ๋‹ค์–‘ํ•œ ์‚ฌ์šฉ ์‚ฌ๋ก€๋ฅผ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ์–ด, ๊ฐ ์‚ฌ์šฉ ์‚ฌ๋ก€๋ณ„๋กœ ๋ณ„๋„์˜ ํ•„๋“œ(postByID, postBySlug ๋“ฑ)๋ฅผ ๋งŒ๋“ค ํ•„์š”๊ฐ€ ์—†์–ด์ง€๋ฏ€๋กœ GraphQL ์Šคํ‚ค๋งˆ๊ฐ€ ๋” ๊ฐ„๊ฒฐํ•˜๊ณ  ์šฐ์•„ํ•ด์ง„๋‹ค๋Š” ์ ์ž…๋‹ˆ๋‹ค.

์—ฌ๋Ÿฌ Oneof ์ธํ’‹ ๊ฐ์ฒด๊ฐ€ ๊ตฌํ˜„๋˜์—ˆ์Šต๋‹ˆ๋‹ค:

  • Root.customPost(by:)
  • Root.mediaItem(by:)
  • Root.menu(by:)
  • Root.page(by:)
  • Root.postCategory(by:)
  • Root.postTag(by:)
  • Root.post(by:)
  • Root.user(by:)

์˜คํผ๋ ˆ์ด์…˜ ๋””๋ ‰ํ‹ฐ๋ธŒ

GraphQL ์˜คํผ๋ ˆ์ด์…˜(์ฆ‰, query ๋ฐ mutation ์˜คํผ๋ ˆ์ด์…˜)๋„ ์ด์ œ ๋””๋ ‰ํ‹ฐ๋ธŒ๋ฅผ ๋ฐ›์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

ํŠน์ • ํƒ€์ž…์œผ๋กœ ๋””๋ ‰ํ‹ฐ๋ธŒ ์ œํ•œ

(ํ•„๋“œ) ๋””๋ ‰ํ‹ฐ๋ธŒ๋ฅผ ํŠน์ • ํƒ€์ž…์˜ ํ•„๋“œ์—๋งŒ ์ ์šฉ๋˜๋„๋ก ์ œํ•œํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ํ•„๋“œ ๊ฐ’์„ ๋Œ€๋ฌธ์ž๋กœ ๋ณ€ํ™˜ํ•˜๋Š” ๋””๋ ‰ํ‹ฐ๋ธŒ @strUpperCase๋Š” String ํ•„๋“œ์—๋งŒ ์˜๋ฏธ๊ฐ€ ์žˆ์œผ๋ฉฐ, Int, Float, Boolean์—๋Š” ์ ์šฉํ•  ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ์ด ์ œํ•œ์„ ๋””๋ ‰ํ‹ฐ๋ธŒ ๋ฆฌ์กธ๋ฒ„์—์„œ ์„ ์–ธํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

์˜ค๋ฅ˜๋ฅผ ๋ฐœ์ƒ์‹œํ‚จ GraphQL ์ฟผ๋ฆฌ ๋…ธ๋“œ์˜ ์ „์ฒด ๊ฒฝ๋กœ ์ถœ๋ ฅ

์‘๋‹ต์— ์˜ค๋ฅ˜๋ฅผ ๋ฐ˜ํ™˜ํ•œ GraphQL ์ฟผ๋ฆฌ์˜ ๋…ธ๋“œ์— ๋Œ€ํ•œ ์ „์ฒด ๊ฒฝ๋กœ๊ฐ€ ํฌํ•จ๋˜๊ฒŒ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค(์„œ๋ธŒ ์—”ํŠธ๋ฆฌ extensions.path ์•„๋ž˜). ์ด๋ฅผ ํ†ตํ•ด ๋ฌธ์ œ์˜ ์›์ธ์„ ๋” ์‰ฝ๊ฒŒ ํŒŒ์•…ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด, ๋‹ค์Œ ์ฟผ๋ฆฌ์—์„œ ๋””๋ ‰ํ‹ฐ๋ธŒ @nonExisting์€ ์กด์žฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค:

query {
  myField @nonExisting
}

์‘๋‹ต์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค:

{
  "errors": [
    {
      "message": "There is no directive with name 'nonExisting'",
      "locations": [
        {
          "line": 2,
          "column": 7
        }
      ],
      "extensions": {
        "type": "QueryRoot",
        "field": "myField @nonExisting",
        "path": [
          "@nonExisting",
          "myField @nonExisting",
          "query { ... }"
        ],
        "code": "PoP\\ComponentModel\\e20"
      }
    }
  ],
  "data": {
    "id": "root"
  }
}

์•ˆ์ „ํ•˜์ง€ ์•Š์€ ๊ธฐ๋ณธ ์„ค์ • ํ™œ์„ฑํ™”

Gato GraphQL์€ ์•ˆ์ „ํ•œ ๊ธฐ๋ณธ ์„ค์ •์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค:

  • ๋‹จ์ผ ์—”๋“œํฌ์ธํŠธ๊ฐ€ ๋น„ํ™œ์„ฑํ™”๋จ
  • GraphQL ์Šคํ‚ค๋งˆ์˜ ใ€Œ๋ฏผ๊ฐํ•œใ€ ๋ฐ์ดํ„ฐ ์š”์†Œ(์˜ˆ: User.roles ๋˜๋Š” status๋กœ ํฌ์ŠคํŠธ ํ•„ํ„ฐ๋ง)๊ฐ€ ๋…ธ์ถœ๋˜์ง€ ์•Š์Œ
  • ์ฟผ๋ฆฌํ•  ์ˆ˜ ์žˆ๋Š” ์„ค์ • ์˜ต์…˜ ๋ฐ ๋ฉ”ํƒ€ ํ‚ค(ํฌ์ŠคํŠธ, ์‚ฌ์šฉ์ž ๋“ฑ)๊ฐ€ ์ผ๋ถ€๋กœ ์ œํ•œ๋จ
  • ํ•œ ๋ฒˆ์— ์ฟผ๋ฆฌํ•  ์ˆ˜ ์žˆ๋Š” ์—”ํ‹ฐํ‹ฐ ์ˆ˜๊ฐ€ ์ œํ•œ๋จ(ํฌ์ŠคํŠธ, ์‚ฌ์šฉ์ž ๋“ฑ)

์ด๋Ÿฌํ•œ ์•ˆ์ „ํ•œ ๊ธฐ๋ณธ ์„ค์ •์€ ์•…์˜์ ์ธ ๊ณต๊ฒฉ์„ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•ด ใ€Œ๋ผ์ด๋ธŒใ€ ์‚ฌ์ดํŠธ๋ฅผ ์•ˆ์ „ํ•˜๊ฒŒ ์œ ์ง€ํ•˜๋Š” ๋ฐ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ใ€Œ์Šคํƒœํ‹ฑใ€ ์‚ฌ์ดํŠธ๋ฅผ ๊ตฌ์ถ•ํ•  ๋•Œ(๋…ธํŠธ๋ถ์˜ ๊ฐœ๋ฐœ ์‚ฌ์ดํŠธ, ์•ˆ์ „ํ•œ ๋ฐฉํ™”๋ฒฝ ๋’ค, ๋˜๋Š” ์ธํ„ฐ๋„ท์— ๋…ธ์ถœ๋˜์ง€ ์•Š์€ WordPress ์‚ฌ์ดํŠธ ๋“ฑ ๊ณต๊ฒฉ์— ์ทจ์•ฝํ•˜์ง€ ์•Š์€ ๊ฒฝ์šฐ)์—๋Š” ํ•„์š”ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

v0.9๋ถ€ํ„ฐ wp-config.php์— ๋‹ค์Œ์„ ์ถ”๊ฐ€ํ•˜์—ฌ ์•ˆ์ „ํ•˜์ง€ ์•Š์€ ๊ธฐ๋ณธ๊ฐ’์„ ํ™œ์„ฑํ™”ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

define( 'GRAPHQL_API_ENABLE_UNSAFE_DEFAULTS', true );

๋˜๋Š” ๋™์ผํ•œ ํ‚ค/๊ฐ’์„ ํ™˜๊ฒฝ ๋ณ€์ˆ˜๋กœ ์ •์˜ํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

์•ˆ์ „ํ•˜์ง€ ์•Š์€ ๊ธฐ๋ณธ๊ฐ’์„ ํ™œ์„ฑํ™”ํ•˜๋ฉด ํ”Œ๋Ÿฌ๊ทธ์ธ์˜ ๊ธฐ๋ณธ ์„ค์ •์ด ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋ณ€๊ฒฝ๋ฉ๋‹ˆ๋‹ค:

  • ๋‹จ์ผ ์—”๋“œํฌ์ธํŠธ๊ฐ€ ํ™œ์„ฑํ™”๋จ
  • GraphQL ์Šคํ‚ค๋งˆ์—์„œ ใ€Œ๋ฏผ๊ฐํ•œใ€ ๋ฐ์ดํ„ฐ ์š”์†Œ๊ฐ€ ๋…ธ์ถœ๋จ
  • ๋ชจ๋“  ์„ค์ • ์˜ต์…˜ ๋ฐ ๋ฉ”ํƒ€ ํ‚ค๋ฅผ ์ฟผ๋ฆฌํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋จ
  • ํ•œ ๋ฒˆ์— ์ฟผ๋ฆฌํ•  ์ˆ˜ ์žˆ๋Š” ์—”ํ‹ฐํ‹ฐ ์ˆ˜๊ฐ€ ๋ฌด์ œํ•œ์ด ๋จ

์นดํ…Œ๊ณ ๋ฆฌ๋ณ„ ์ปค์Šคํ…€ ์—”๋“œํฌ์ธํŠธ ๋ฐ Persisted ์ฟผ๋ฆฌ ์ •๋ฆฌ

์ปค์Šคํ…€ ์—”๋“œํฌ์ธํŠธ ๋˜๋Š” Persisted ์ฟผ๋ฆฌ๋ฅผ ์ƒ์„ฑํ•  ๋•Œ, ๋ชจ๋“  ์—”๋“œํฌ์ธํŠธ๋ฅผ ์ •๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด ใ€ŒGraphQL ์—”๋“œํฌ์ธํŠธ ์นดํ…Œ๊ณ ๋ฆฌใ€๋ฅผ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

์ปค์Šคํ…€ ์—”๋“œํฌ์ธํŠธ ํŽธ์ง‘ ์‹œ ์—”๋“œํฌ์ธํŠธ ์นดํ…Œ๊ณ ๋ฆฌ

์˜ˆ๋ฅผ ๋“ค์–ด, ํด๋ผ์ด์–ธํŠธ, ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋˜๋Š” ๊ธฐํƒ€ ํ•„์š”ํ•œ ์ •๋ณด๋ณ„๋กœ ์—”๋“œํฌ์ธํŠธ๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” ์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

์—”๋“œํฌ์ธํŠธ ์นดํ…Œ๊ณ ๋ฆฌ ๋ชฉ๋ก

์ปค์Šคํ…€ ์—”๋“œํฌ์ธํŠธ ๋ฐ Persisted ์ฟผ๋ฆฌ ๋ชฉ๋ก์—์„œ ๊ฐ ์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์นดํ…Œ๊ณ ๋ฆฌ ๋งํฌ๋ฅผ ํด๋ฆญํ•˜๊ฑฐ๋‚˜ ์ƒ๋‹จ์˜ ํ•„ํ„ฐ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ํ•ด๋‹น ์นดํ…Œ๊ณ ๋ฆฌ์˜ ํ•ญ๋ชฉ๋งŒ ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค.

์นดํ…Œ๊ณ ๋ฆฌ๊ฐ€ ์žˆ๋Š” ์ปค์Šคํ…€ ์—”๋“œํฌ์ธํŠธ ๋ชฉ๋ก

์ธํŠธ๋กœ์ŠคํŽ™์…˜์„ ํ†ตํ•œ ์Šคํ‚ค๋งˆ ํ™•์žฅ ์ฟผ๋ฆฌ

์Šคํ‚ค๋งˆ ์š”์†Œ์— ์ฒจ๋ถ€๋œ ์ปค์Šคํ…€ ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ๋ฅผ ์ด์ œ ํ•„๋“œ extensions๋ฅผ ํ†ตํ•ด ์ฟผ๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์Šคํ‚ค๋งˆ์˜ ๋ชจ๋“  ์ธํŠธ๋กœ์ŠคํŽ™์…˜ ์š”์†Œ๊ฐ€ ์ƒˆ ํ•„๋“œ๋กœ ์—…๊ทธ๋ ˆ์ด๋“œ๋˜์–ด, ๊ฐ๊ฐ ํ•ด๋‹นํ•˜๋Š” ใ€ŒExtensionsใ€ ํƒ€์ž…์˜ ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜ํ•˜๊ฒŒ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ์ด ํƒ€์ž…์€ ํ•ด๋‹น ์š”์†Œ์˜ ์ปค์Šคํ…€ ์†์„ฑ์„ ๋…ธ์ถœํ•ฉ๋‹ˆ๋‹ค.

# Using "_" instead of "__" in introspection type name to avoid errors in graphql-js
type _SchemaExtensions {
  # Is the schema being namespaced?
  isNamespaced: Boolean!
}
 
extend type __Schema {
  extensions: _SchemaExtensions!
}
 
type _NamedTypeExtensions {
  # The type name
  elementName: String!
 
  # The "namespaced" type name
  namespacedName: String!
 
  # Enum-like "possible values" for EnumString type resolvers, `null` otherwise
  possibleValues: [String!]
 
  # OneOf Input Objects are a special variant of Input Objects where the type system asserts that exactly one of the fields must be set and non-null, all others being omitted.
  isOneOf: Boolean!
}
 
extend type __Type {
  # Non-null for named types, null for wrapping types (Non-Null and List)
  extensions: _NamedTypeExtensions
}
 
type _DirectiveExtensions {
  # If no objects are returned in the field (eg: because they failed validation), does the directive still need to be executed?
  needsDataToExecute: Boolean!
 
  # Names or descriptions of the types the field directives is restricted to, or `null` if it supports any type (i.e. it defines no restrictions)
  fieldDirectiveSupportedTypeNamesOrDescriptions: [String!]
}
 
extend type __Directive {
  extensions: _DirectiveExtensions!
}
 
type _FieldExtensions {
  isGlobal: Boolean!
 
  # Useful for nested mutations
  isMutation: Boolean!
 
  # `true` => Only exposed when "Expose "sensitive" data elements" is enabled
  isSensitiveDataElement: Boolean!
}
 
extend type __Field {
  extensions: _FieldExtensions!
}
 
type _InputValueExtensions {
  isSensitiveDataElement: Boolean!
}
 
extend type __InputValue {
  extensions: _InputValueExtensions!
}
 
type _EnumValueExtensions {
  isSensitiveDataElement: Boolean!
}
 
extend type __EnumValue {
  extensions: _EnumValueExtensions!
}

GraphQL ์„œ๋ฒ„ ์ฝ”๋“œ์˜ WordPress ๋ถ„๋ฆฌ ์™„๋ฃŒ

ํ”Œ๋Ÿฌ๊ทธ์ธ์„ ๊ตฌ๋™ํ•˜๋Š” ๊ธฐ๋ฐ˜ GraphQL ์„œ๋ฒ„๋Š” ์ด์ œ ๋…๋ฆฝ์ ์ธ PHP ์ปดํฌ๋„ŒํŠธ๋กœ ์„ค์น˜ ๋ฐ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ฆ‰, WordPress์™€ ๋…๋ฆฝ์ ์œผ๋กœ ๋™์ž‘ํ•ฉ๋‹ˆ๋‹ค.

์ด๋ฅผ ํ†ตํ•ด Gato GraphQL์„ ๋‹ค๋ฅธ ํ”„๋ ˆ์ž„์›Œํฌ(์˜ˆ: Laravel)์—์„œ ์‚ฌ์šฉํ•˜๊ฑฐ๋‚˜, WordPress์˜ ์‚ฌ์šฉ ๊ฐ€๋Šฅ ์—ฌ๋ถ€์— ๊ด€๊ณ„์—†์ด(์ง€์†์  ํ†ตํ•ฉ ์ž‘์—… ์‹คํ–‰ ์‹œ ๋“ฑ) ๋ชจ๋“  PHP ํ™˜๊ฒฝ์—์„œ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๊ธธ์ด ์—ด๋ฆฝ๋‹ˆ๋‹ค.

์Šคํ‚ค๋งˆ ๊ตฌ์„ฑ, ์ปค์Šคํ…€ ์—”๋“œํฌ์ธํŠธ, Persisted ์ฟผ๋ฆฌ ํŽธ์ง‘ ์‹œ ๋ฌธ์„œ ํƒ์ƒ‰

์Šคํ‚ค๋งˆ ๊ตฌ์„ฑ, ์ปค์Šคํ…€ ์—”๋“œํฌ์ธํŠธ, Persisted ์ฟผ๋ฆฌ ํŽธ์ง‘ ์‹œ ํ‘œ์‹œ๋˜๋Š” ๋ชจ๋“  ๋ธ”๋ก์— ใ€Œinfoใ€ ๋ฒ„ํŠผ์ด ์ถ”๊ฐ€๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ํด๋ฆญํ•˜๋ฉด ๋ชจ๋‹ฌ ์ฐฝ์— ๋ฌธ์„œ๊ฐ€ ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค.

ใ€Œinfoใ€ ๋ฒ„ํŠผ์„ ํด๋ฆญํ•˜๋ฉด...

...๋ฌธ์„œ ๋ชจ๋‹ฌ ์ฐฝ์ด ์—ด๋ฆฝ๋‹ˆ๋‹ค

๊ทธ ์™ธ ๋” ๋งŽ์€ ๊ธฐ๋Šฅ

๋‹ค๋ฅธ ๋ชจ๋“  ์ƒˆ ๊ธฐ๋Šฅ์„ ํ™•์ธํ•˜๋ ค๋ฉด ์ƒˆ ๋ฆด๋ฆฌ์Šค์˜ ์ „์ฒด ์„ค๋ช…์„ ์ฐธ์กฐํ•˜์‹œ๊ฑฐ๋‚˜, ๋ณ€๊ฒฝ ๋กœ๊ทธ๋ฅผ ์‚ดํŽด๋ณด์„ธ์š”.

๊ทธ๋ฆฌ๊ณ  ์—ฌ๊ธฐ์—์„œ ํ”Œ๋Ÿฌ๊ทธ์ธ์„ ๋‹ค์šด๋กœ๋“œํ•˜์„ธ์š”.

๋งˆ์Œ์— ๋“œ์…จ๋‹ค๋ฉด, ์‚ฌ๋ž‘์„ ๋„๋ฆฌ ์ „ํŒŒํ•ด ์ฃผ์„ธ์š” โค๏ธ


๋‰ด์Šค๋ ˆํ„ฐ ๊ตฌ๋…ํ•˜๊ธฐ

Gato GraphQL์˜ ๋ชจ๋“  ์—…๋ฐ์ดํŠธ๋ฅผ ๋†“์น˜์ง€ ๋งˆ์„ธ์š”.