Apollo是一套用於創建GraphQL服務器和使用GraphQL API的工具集合。讓我們詳細探討Apollo,包括Apollo Client和Apollo Server。
警告!此教程已過時。Apollo現在使用
@apollo/xxx
而不是apollo-xxx
,請在我更新之前自行研究 :)
Apollo介紹
在過去的幾年中,GraphQL作為構建REST API的一種替代方案,變得非常流行。
GraphQL是一種讓客戶端決定它們想要在網絡上傳輸哪些數據的方法,而不是由服務器發送固定的數據集。
此外,它允許您指定嵌套的資源,從而減少處理REST API時有時所需的來回操作。
Apollo是一個團隊和社區,基於GraphQL進行構建,並提供了幫助您構建項目的不同工具。
Apollo提供的工具主要有3個部分:Client、Server和Engine。
Apollo Client幫助您使用GraphQL API,支持最流行的前端Web技術,包括React、Vue、Angular、Ember、Meteor等,以及iOS和Android的原生開發。
Apollo Server是GraphQL的服務器部分,與您的後端進行交互,並將響應返回給客戶端的請求。
Apollo Engine是一個托管基礎設施(SAAS),它充當客戶端和服務器之間的中間人,提供緩存、性能報告、負載測量、錯誤跟踪、模式字段使用統計、歷史統計和許多其他好東西。目前免費每月100萬次請求,它是Apollo唯一不開源和免費的部分,並為項目的開源部分提供資金支持。
值得注意的是,這3個工具並沒有以任何方式相互關聯,您可以僅使用Apollo Client與第三方API進行交互,或者僅使用Apollo Server來提供API,而不需要客戶端。
它們都與GraphQL標準規範相容,因此Apollo中沒有專有或不相容的技術。
但將所有這些工具放在一個地方非常方便,這是一個完整的套件,滿足您所有與GraphQL相關的需求。
Apollo致力於易於使用和易於參與貢獻。
Apollo的重點是保持事情簡單。這對於想要流行的技術非常重要,因為某些技術、框架或庫對於99%的中小型公司來說可能過於複雜,只適用於具有非常復雜需求的大公司。
Apollo Client
Apollo Client是用於GraphQL的領先JavaScript客戶端。由社區驅動,設計用於讓您構建與GraphQL數據進行接口的UI組件,無論是在顯示數據時還是在某些操作發生時進行變更。
您不需要更改應用程序中的所有內容才能使用Apollo Client。您可以從一個極小的層開始,一個請求,然後逐漸擴展。
最重要的是,Apollo Client從一開始就設計成簡單、輕巧和靈活。
在本文中,我將詳細介紹如何在React應用程序中使用Apollo Client。
我將使用GitHub的GraphQL API作為服務器。
啟動React應用程式
我使用create-react-app
來設置React應用程序,這非常方便,只需添加我們所需的基礎結構即可:
npx create-react-app myapp
npx
是最新版本的npm中可用的命令。如果您沒有這個命令,請更新npm。
然後使用npm啟動應用程序本地服務器:
npm start
這將在localhost:3000
上啟動應用程序。
現在打開src/index.js
文件:
import React from 'react'
import ReactDOM from 'react-dom'
import './index.css'
import App from './App'
import registerServiceWorker from './registerServiceWorker'
ReactDOM.render(<App />, document.getElementById('root'))
registerServiceWorker()
並刪除所有這些內容。
使用Apollo Boost開始
Apollo Boost是開始在新項目中使用Apollo Client的最簡單方法。我們將安裝它,以及react-apollo
和graphql
。
在控制台中運行以下命令:
npm install apollo-boost react-apollo graphql
創建ApolloClient對象
您可以從index.js
文件中的apollo-client
導入ApolloClient:
import { ApolloClient } from 'apollo-client'
const client = new ApolloClient()
Apollo Client默認使用當前主機上的/graphql
端點,因此讓我們使用Apollo Link來通過設置GraphQL端點URI來指定與GraphQL服務器的連接詳細信息。
Apollo連結
Apollo Link由apollo-link-http
模塊導入的HttpLink
對象表示。
Apollo Link為我們提供了一種描述如何獲取GraphQL操作的結果以及想要如何處理響應的方法。
簡而言之,您可以創建多個Apollo Link實例,它們會連續地應用在GraphQL請求上,提供您想要的最終結果。某些鏈接還可以提供重試請求的選項,批量處理等。
我們將向我們的Apollo Client實例添加一個Apollo Link,以使用GitHub的GraphQL端點URI https://api.github.com/graphql
:
import { ApolloClient } from 'apollo-client'
import { createHttpLink } from 'apollo-link-http'
const client = new ApolloClient({
link: createHttpLink({ uri: 'https://api.github.com/graphql' })
})
緩存
我們還沒有完成。在擁有一個可運行的示例之前,我們還必須告訴ApolloClient
使用哪種caching策略:InMemoryCache
是默認策略,也是一個不錯的起點。
import { ApolloClient } from 'apollo-client'
import { createHttpLink } from 'apollo-link-http'
import { InMemoryCache } from 'apollo-cache-inmemory'
const client = new ApolloClient({
link: createHttpLink({ uri: 'https://api.github.com/graphql' }),
cache: new InMemoryCache()
})
使用ApolloProvider
現在,我們需要使用ApolloProvider
將Apollo Client連接到組件樹中。我們可以在主React文件中使用ApolloProvider
:
import React from 'react'
import ReactDOM from 'react-dom'
import { ApolloClient } from 'apollo-client'
import { createHttpLink } from 'apollo-link-http'
import { InMemoryCache } from 'apollo-cache-inmemory'
import { ApolloProvider } from 'react-apollo'
import App from './App'
const client = new ApolloClient({
link: createHttpLink({ uri: 'https://api.github.com/graphql' }),
cache: new InMemoryCache()
})
ReactDOM.render(
<ApolloProvider client={client}>
<App />
</ApolloProvider>,
document.getElementById('root')
)
這足以渲染默認create-react-app
屏幕,已初始化Apollo Client:
gql
模板標記
我們現在可以使用Apollo Client做一些事情了,我們要從GitHub API獲取一些數據並渲染它。
為此,我們需要在index.js
頂部導入gql
模板標記:
import gql from 'graphql-tag'
使用此模板標記可以創建任何GraphQL查詢,例如:
const query = gql`
query {
...
}
`
執行GraphQL請求
導入gql
是我們工具箱中所需的最後一個項目。
現在,我們可以使用Apollo Client做一些事情了,我們要從GitHub API獲取一些數據並渲染它。
獲取API的訪問令牌
首先要做的是從GitHub獲取一個個人訪問令牌。
GitHub通過提供一個界面,讓您選擇可能需要的任何權限,使其變得很容易:
出於這個例子教程的目的,您不需要這些權限,它們用於訪問私有用戶數據,但我們只是查詢公共存儲庫數據。
不過,您仍然需要一個令牌。
您獲得的令牌是一個OAuth 2.0 Bearer token。
您可以通過在命令行中運行以下命令輕松測試它:
$ curl -H "Authorization: bearer ***_YOUR_TOKEN_HERE_***" -X POST -d " \
{ \
\"query\": \"query { viewer { login }}\" \
} \
" https://api.github.com/graphql
(將***_YOUR_TOKEN_HERE_***
替換為實際令牌)
如果一切正常,您將獲得結果:
{"data":{"viewer":{"login":"***_YOUR_LOGIN_NAME_***"}}}
或者如果出現問題,例如如果您忘記插入令牌:
{
"message": "Bad credentials",
"documentation_url": "https://developer.github.com/v4"
}
使用Apollo連結進行身份驗證
現在,我們需要將Authorization標頭與我們的GraphQL請求一起發送,就像我們在上面的curl
請求中所做的那樣。
我們可以通過創建一個Apollo Link中間件來使用Apollo Client進行身份驗證。首先安裝apollo-link-context
:
npm install apollo-link-context
該程序允許我們通過設置請求的上下文來添加身份驗證機制。
我們可以通過如下方式在代碼中引用setContext
函數使用它:
import { setContext } from 'apollo-link-context'
...
const authLink = setContext((_, { headers }) => {
const token = '***YOUR_TOKEN***'
return {
headers: {
...headers,
authorization: `Bearer ${token}`
}
}
})
一旦我們有了這個新的Apollo Link,我們就可以使用concat()
方法組合現有的HttpLink
,如下所示:
const link = authLink.concat(httpLink)
以下是具有我們現在擁有的代碼的src/index.js
文件的完整代碼:
import React from 'react'
import ReactDOM from 'react-dom'
import { ApolloClient } from 'apollo-client'
import { createHttpLink } from 'apollo-link-http'
import { InMemoryCache } from 'apollo-cache-inmemory'
import { ApolloProvider } from 'react-apollo'
import { setContext } from 'apollo-link-context'
import gql from 'graphql-tag'
import App from './App'
const httpLink = createHttpLink({ uri: 'https://api.github.com/graphql' })
const authLink = setContext((_, { headers }) => {
const token = '***YOUR_TOKEN***'
return {
headers: {
...headers,
authorization: `Bearer ${token}`
}
}
})
const link = authLink.concat(httpLink)
const client = new ApolloClient({
link: link,
cache: new InMemoryCache()
})
ReactDOM.render(
<ApolloProvider client={client}>
<App />
</ApolloProvider>,
document.getElementById('root')
)
⚠️ 🚧 警告:請記住,此代碼是供教育目的的示例代碼,它在您的前端代碼中公開了您的GitHub GraphQL API令牌。生產代碼需要在後端保持此令牌的私密性。
現在,我們可以在文件底部執行第一個GraphQL請求,此示例查詢請求獲取超過50,000個星星的前10個最熱門存儲庫的名稱和所有者:
const POPULAR_REPOSITORIES_LIST = gql`
{
search(query: "stars:>50000", type: REPOSITORY, first: 10) {
repositoryCount
edges {
node {
... on Repository {
name
owner {
login
}
stargazers {
totalCount
}
}
}
}
}
`
client.query({ query: POPULAR_REPOSITORIES_LIST }).then(console.log)
成功運行此代碼將在瀏覽器控制台中返回我們的查詢結果:
在組件中呈現GraphQL查詢結果集
到目前為止,我們已經做得很好了。更酷的是使用graphql結果集來渲染您的組件。
我們讓Apollo Client負責處理所有數據的提取和處理低層級的工作,我們可以專注於顯示數據,通過使用react-apollo
提供的graphql
組件增強器。
在App.js
文件中添加以下內容:
import React from 'react'
import { graphql } from 'react-apollo'
import { gql } from 'apollo-boost'
const POPULAR_REPOSITORIES_LIST = gql`
{
search(query: "stars:>50000", type: REPOSITORY, first: 10) {
repositoryCount
edges {
node {
... on Repository {
name
owner {
login
}
stargazers {
totalCount
}
}
}
}
}
}
`
const App = graphql(POPULAR_REPOSITORIES_LIST)(props =>
<ul>
{props.data.loading ? '' : props.data.search.edges.map((row, i) =>
<li key={row.node.owner.login + '-' + row.node.name}>
{row.node.owner.login} / {row.node.name}: {' '}
<strong>
{row.node.stargazers.totalCount}
</strong>
</li>
)}
</ul>
)
export default App
這是我們的查詢結果在組件中呈現的結果。
Apollo Server
GraphQL服務器的工作是在一個端點上接受傳入的請求,解釋請求並查找滿足客戶端需求的任何數據。
不同的GraphQL服務器實現有數以百計,適用於每種可能的語言。
Apollo Server是JavaScript的GraphQL服務器實現,特別是對於Node.js平台。
它支持許多流行的Node.js框架,包括:
Apollo Server基本上提供了3個功能:
- 提供一種描述數據的模式
- 提供解析器的框架,這些解析器是我們為了查找用於滿足請求所需的數據而編寫的函數。
- 便於處理API的身份驗證。
首先,創建一個名為appserver
的文件夾,並進入其中,運行npm init --yes
來初始化package.json
文件。
然後運行npm install apollo-server graphql
。
Apollo Playgrounds
如果您喜歡在線遊戲場,大家有兩個很棒的Apollo playground可以使用。
首先,有一個在Glitch上託管的playground,第二個是在CodeSandbox上的playground。
您可以fork/複制這些初始項目,以創建自己的Apollo Server。
Apollo Server Hello World
創建一個index.js
文件。
首先,您需要從apollo-server
中導入ApolloServer
和gql
:
const { ApolloServer, gql } = require('apollo-server');
我們使用gql
標籤創建一個模式定義。模式定義是一個模板字面量字符串,其中包含我們的查詢的描述以及與每個字段關聯的類型:
const typeDefs = gql`
type Query {
hello: String
}
`
解析器是一個將模式中的字段映射到解析器函數的對象,該函數能夠查找數據以回應查詢。
這是一個簡單的解析器,包含hello
字段的解析器函數,該函數返回Hello world!
字符串:
const resolvers = {
Query: {
hello: (root, args, context) => {
return 'Hello world!'
}
}
}
有了這兩個元素,模式定義和解析器,我們初始化一個新的ApolloServer對象:
const server = new ApolloServer({ typeDefs, resolvers })
然後調用服務器對象上的listen()方法,並等待Promise解析,這表示服務器已就緒:
server.listen().then(({ url }) => {
console.log(`🚀 Server ready at ${url}`)
})
下面是簡單“Hello World”示例的完整代碼:
const { ApolloServer, gql } = require('apollo-server');
// 創建模式,使用GraphQL模式語言
const typeDefs = gql`
type Query {
hello: String
}
`
// 為模式字段提供解析器函數
const resolvers = {
Query: {
hello: (root, args, context) => {
return 'Hello world!'
}
}
}
const server = new ApolloServer({ typeDefs, resolvers })
server.listen().then(({ url }) => {
console.log(`🚀 Server ready at ${url}`)
})
現在運行node index.js
,然後在控制台窗口中運行以下命令:
$ curl \
-X POST \
-H "Content-Type: application/json" \
--data '{ "query": "{ hello }" }' \
http://localhost:4000/graphql
這應該返回數據:
{
"data": {
"hello": "Hello world!"
}
}
您可以使用此簡單的App.js示例使客戶端與之接口,您可以從上面的GitHub API示例直接使用:
import React from 'react'
import { gql } from 'apollo-boost'
import { Query } from 'react-apollo'
const App = () => (
<Query
query={gql`
{
hello
}
`}
>
{({ loading, error, data }) => {
if (loading) return <p>Loading...</p>
if (error) return <p>Error :(</p>
return data.hello
}}
</Query>
)
export default App
您需要更改index.js
文件中的httpLink
URI如下:
const httpLink = createHttpLink({ uri: 'http://localhost:4000/graphql' })