【譯】GraphQL 初學者指南

API 是互聯網行業討論最多的術語之一,可是不少人並不確切知道 API 究竟是什麼。基本上,API 表明應用程序編程接口(Application Programming Interface)。顧名思義,它至關於一個「界面」,令人們(開發人員、用戶、消費者)可以經過它與數據進行交互。php

你能夠理解爲 API 就像是個酒保,你向酒保要一杯酒,他便把一杯你想要的酒遞給你,看起來很簡單的事,還有什麼問題呢?git

構建 API 不是一件困難的事,但學習和理解具體的 API 可能存在必定的困難。多數開發者都會使用你的 API 去開發功能或者只是消費數據,這就要求 API 須要儘量保持乾淨、直觀。精心設計、直觀性強的 API 會很是容易理解和使用。github

一直以來,咱們都在用 REST 來構建 API,使用這種方式會存在一些問題,例如:數據庫

  • 多端點
  • 開發人員學習理解 API 的成本比較高
  • API 的信息過分和信息不足問題

爲了解決以上的相似問題,Facebook 創造了 GraphQL。我認爲 GraphQL 是當代構建 API 的最佳方式,本文將闡述爲何你應該開始學習 GraphQL,讓你瞭解 GraphQL 的工做原理,以及如何使用 GraphQL 建立設計精良、高效而且功能強大的 API。npm

你可能已經據說過 GraphQL,由於不少開發者和公司都在使用它。因爲 GraphQL 是開源的,因此社區也是很龐大的存在。讓咱們在實踐中學習 GraphQL 的工做原理,領略它的魔力了。編程

什麼是GraphQL?

GraphQL (譯者注:中文文檔)是 Facebook 開發的一種開源查詢語言。它爲咱們提供了一種更有效的方式來設計、建立和消費咱們的 API 。基本上,它是 REST 的替代品。json

GraphQL 有不少功能,例如:數組

  1. 咱們能夠編寫本身所需的數據,並得到所需的數據。不用再像咱們習慣使用的 REST 那樣過分獲取信息
  2. GraphQL 爲咱們提供了單個端點,再也不爲同一 API 提供版本2或版本3。
  3. GraphQL 是強類型的,因此咱們能夠在執行以前在 GraphQL 類型系統中驗證查詢。有助於構建更強大的 API。

這是對 GraphQL 的基本介紹,解釋了爲何它如此強大以及爲何它現在得到了不少人氣。若是想了解更多相關信息,我建議訪問 GraphQL 網站去了解。瀏覽器

入門

本文主要目的不是學習如何配置 GraphQL 服務器,因此咱們如今不會深刻研究。本文的目標是瞭解 GraphQL 在實踐中的工做原理,所以咱們將使用一個叫作☄️Traderpack的零配置GraphQL服務器庫。bash

第一步,咱們須要建立一個新文件夾,你能夠隨意命名。我將它命名爲 graphql-server :

mkdir graphql-server
複製代碼

假定你已經在本身的機器中安裝了 npm 或 yarn。若是你不知道它們是什麼,npm 和 yarn 是 JavaScript 編程語言的包管理器。對於 Node.js,默認包管理器是 npm。

在建立的文件夾中,輸入如下命令:

npm init -y
複製代碼

若是你使用 yarn :

yarn init 
複製代碼

npm 會建立一個 package.json 文件,項目安裝的全部依賴項和命令都在這個文件中。

接下來,咱們來安裝本項目要使用的惟一依賴項,☄️Traderpack 容許你建立零配置的 GraphQL 服務器。因爲咱們剛剛開始使用 GraphQL,這將幫助咱們繼續學習更多內容,而沒必要擔憂服務器配置。

打開終端進入項目文件夾,鍵入如下命令:

npm install --save-dev graphpack
複製代碼

若是你使用 yarn,應該這樣:

yarn add --dev graphpack
複製代碼

安裝 Graphpack 以後,轉到 package.json 文件中的腳本,並在其中輸入如下代碼:

"scripts": {
    "dev": "graphpack",
    "build": "graphpack build"
}
複製代碼

咱們將建立一個名爲 src 的文件夾做爲整個服務器中惟一的文件夾,而後在 src 文件夾中建立三個文件。

譯者注:使用 VSCode 的童鞋能夠安裝 `GraphQL for VSCode` 插件進行語法高亮

首先,咱們建立第一個文件,名叫 schema.graphql,並在這個文件中輸入如下代碼:

type Query {
  hello: String
}
複製代碼

這個 schema.graphql 文件將是咱們的整個 GraphQL 架構,稍後我會解釋它的做用。

接下來,在 src 文件夾中建立第二個文件 resolvers.js,並在這個文件中輸入如下代碼:

import { users } from "./db"

const resolvers = {
  Query: {
    hello: () => "Hello World!"
  }
}

export default resolvers
複製代碼

這個 resolvers.js 文件將是咱們提供將 GraphQL 操做轉換爲數據的指令的方式。

最後,在src文件夾中建立第三個文件 db.js,並在這個文件中輸入如下代碼:

export let users = [
  { id: 1, name: "John Doe", email: "john@gmail.com", age: 22 },
  { id: 2, name: "Jane Doe", email: "jane@gmail.com", age: 23 }
]
複製代碼

在本教程中,咱們沒有使用真實數據庫。因此這個 db.js 文件將模擬數據庫,僅用於學習目的。

如今咱們的src文件夾應以下所示:

src
  |--db.js
  |--resolvers.js
  |--schema.graphql
複製代碼

如今,若是你運行命令 npm run dev,或者若是你正在使用yarn,則運行 yarn dev,應該在終端中看到此輸出:

如今能夠用瀏覽器打開 localhost:4000,這意味着咱們已準備好開始在 GraphQL 中編寫咱們的第一個 queries(查詢),mutations(突變)和 subscriptions(訂閱)。

若是感興趣能夠看看 GraphQL Playground,這是一個功能強大的 GraphQL IDE,可用於更好的開發工做流程。若是你想了解有關 GraphQL Playground 的更多信息,請單擊此處

Schema

GraphQL 有本身的語言類型,用於編寫 Schema(模式)。這是一種人類可讀的模式語法,稱爲 Schema Definition Language - 模式定義語言(SDL)。不管使用何種技術,SDL都是相同的 - 你能夠將其用於你想要的任何語言或框架。這種模式語言很是有用,由於它會讓你很容易直觀的理解你的 API 將具備哪些類型。

Types

Types(類型)是 GraphQL 最重要的特性之一。Types 是自定義對象,表示 API 的外觀。舉個例子,若是你正在構建社交媒體應用程序,那麼你的 API 可能會有 PostsUsersLikesGroups 等 Types。

Types 下有 fields(字段),這些字段返回特定類型的數據。例如,咱們要建立一個 User 類型,咱們應該有 nameemailage 等字段。字段能夠是任何類型,並始終返回一種數據類型,好比 Int、Float、String、Boolean、ID、對象類型列表或自定義對象類型。

如今編寫咱們的第一個 Type,轉到 schema.graphql 文件並用如下內容替換已存在的 Query 類型:

type User {
  id: ID!
  name: String!
  email: String!
  age: Int
}
複製代碼

每一個 User 都將擁有一個 ID,所以咱們爲其提供了 ID 類型。User 也會有一個 nameemail,因此咱們給它們 String 類型,年齡咱們給了 Int 類型。很簡單吧?

數據類型後面的 ! 表示該字段非空(non-nullable),這意味着這些帶 ! 的字段必須在每一個查詢中返回一些數據。

在 GraphQL 中有三個主要概念:

  1. 查詢(queries) - 從服務器獲取數據
  2. 突變(mutations) - 修改服務器上的數據並獲取更新數據(建立,更新,刪除)
  3. 訂閱(subscriptions) - 與服務器保持實時鏈接

這三個主要概念我會一一解釋。

Queries

簡單來講,GraphQL 中的查詢就是獲取數據的方式。GraphQL 中的查詢會得到所需的確切數據。很少也很多。這對咱們的 API 產生了巨大的積極影響 - 再也不像咱們使用 REST API 那樣過分獲取或提取不足信息。

讓咱們來中建立一個查詢類型,首先,在 schema.graphql中添加一個名爲 Query 的新類型:

type Query {
  users: [User!]!
}
複製代碼

users 查詢將返回給咱們一個或多個用戶的數組。它不會返回 null,由於咱們在後面加了 ! ,這意味着它是一個不可爲空的查詢,應該老是返回一些東西。

既然能返回多個,咱們也能返回一個特定用戶,在 Query 類型中添加一個新的查詢 user:

type Query {
    users: [User!]!
+   user(id: ID!): User!
  }
複製代碼

你會發現查詢可以傳遞參數,查詢特定用戶的時候把用戶的 id 做爲參數傳入。

那麼 GraphQL 如何知道去哪獲取到數據返回呢?這就是 resolvers.js 的做用,它會告訴 GraphQL 如何以及在何處獲取數據。

打開 resolvers.js 文件,更改一下代碼:

import { users } from "./db"

const resolvers = {
  Query: {
    user: (parent, { id }, context, info) => {
      return users.find(user => user.id === id)
    },
    users: (parent, args, context, info) => {
      return users
    }
  }
}

export default resolvers
複製代碼

解釋一下以上代碼是如何工做的:

  • 每一個查詢解析器都有四個參數。在 user 函數中,咱們將 id 做爲參數傳遞,而後返回與傳遞的 id 匹配的特定用戶
  • users 函數中,咱們只是返回已存在的 users 數組,它會返回全部的用戶

如今,咱們將測試咱們的查詢是否正常工做。瀏覽器打開 localhost:4000,在左邊輸入如下代碼而後點運行按鈕:

query {
  users {
    id
    name
    email
    age
  }
}
複製代碼

試試返回 id 爲 1 的用戶:

query {
  user(id: 1) {
    id
    name
    email
    age
  }
}
複製代碼

Mutations

在 GraphQL 中,Mutations 是修改服務器上的數據並獲取更新數據的方式。你能夠理解爲相似 REST 的CUD(CREATE,UPDATE,DELETE)。

咱們來建立一個類型突變,咱們全部的突變都將在這種類型中結束。在 schema.graphql 文件中編寫一個名爲 mutation 的新類型:

type Mutation {
  createUser(id: ID!, name: String!, email: String!, age: Int): User!
  updateUser(id: ID!, name: String, email: String, age: Int): User!
  deleteUser(id: ID!): User!
}
複製代碼

上述代碼建立了三個 Mutation:

  1. createUser - 咱們傳入的參數 idnameemailage,應該返回一個新的用戶
  2. updateUser - 傳入 id 和新的 nameemailage, 應該返回一個更新後的用戶
  3. deleteUser - 傳入 id ,應該返回被刪除掉用戶的信息

如今,咱們去 resolvers.js 文件中,在 Query 對象下方插入一個新的 Mutation 對象。

Mutation: {
    createUser: (parent, { id, name, email, age }, context, info) => {
      const newUser = { id, name, email, age }
      users.push(newUser)
      return newUser
    },
    updateUser: (parent, { id, name, email, age }, context, info) => {
      let newUser = users.find(user => user.id === id)
      newUser.name = name
      newUser.email = email
      newUser.age = age
      return newUser
    },
    deleteUser: (parent, { id }, context, info) => {
      const userIndex = users.findIndex(user => user.id === id)
      if (userIndex === -1) throw new Error("User not found.")
      const deletedUsers = users.splice(userIndex, 1)
      return deletedUsers[0]
    }
  }
複製代碼

該去 localhost:4000 看看咱們寫的 Mutations 是否有效了,在頁面上輸入:

mutation {
  createUser(id: 3, name: "Robert", email: "robert@gmail.com", age: 21) {
    id
    name
    email
    age
  }
}
複製代碼

你也能夠嘗試一下其餘的 Mutation。

Subscriptions

正如我以前所說,Subscriptions (訂閱)是你與服務器保持實時鏈接的方式。這意味着不管什麼時候在服務器中發生事件,而且每當調用該事件時,服務器都會將相應的數據發送到客戶端。經過使用訂閱,你能夠將應用程序更新爲不一樣用戶之間的最新更改。

最基本的訂閱示例:

subscription {
  users {
    id
    name
    email
    age
  }
}
複製代碼

你會說它與查詢很是類似,但它的工做方式和查詢不一樣。當服務器中的某些內容更新時,服務器將運行訂閱中指定的 GraphQL 查詢,並將更新的結果發送到客戶端。我並不打算在這篇文章中使用訂閱,但若是你想了解更多關於它們的信息,請點擊此處

總結

如你所見,GraphQL 是一項很是強大的新技術。它爲咱們提供了構建更好和精心設計的 API 的真正能力。這就是爲何我建議你如今開始學習它。

對我來講,它最終將取代 REST。

感謝閱讀文章,請在下面發表評論!

相關文章
相關標籤/搜索