Apollo GraphQL Server 是一個將GraphQL的標準轉化為實際可用的工具和框架,可以在Node.js 常用的中介軟體像是 Express 或 Fastify 所建立的伺服器中,輕鬆加入和設定 Apollo GraphQL Server 來處理 GraphQL 請求。它是一個強大的 GraphQL 引擎,可以連接資料庫、RESTful API 或其他 GraphQL 服務,作為服務的整合介面。Apollo GraphQL Server 提供了許多實用的功能和工具,使開發者能夠輕鬆建立和管理 GraphQL API,並與各種資料源連接。
Apollo GraphQL Server 的主要特點包括:
npm install apollo-server graphql
這些特性使得Apollo GraphQL Server能夠高效地處理和管理GraphQL查詢,並提供強大的數據訪問能力。
typeDefs
和 resolvers
是兩個非常重要的參數,它們共同定義了你的 GraphQL API 的結構和行為。★
typeDefs
:用來定義 GraphQL schema ,目的是描述數據結構和查詢操作。
例如:
這段代碼展示了如何使用 typeDefs
來定義 GraphQL schema,包括查詢、變更和輸入/輸出類型。
const typeDefs = gql`
type User {
id: ID!
email(text: String): String
name: String
}
type Query {
user: User
}
input UpdateUserInputType {
id: ID!
name: String
}
type UpdateUserPayload {
payload: User
status: String
message:String
errors: [String]
}
type Mutation {
updateUser(input: UpdateUserInputType): UpdateUserPayload
}
`
★
resolvers
:是用來處理實際查詢的函數。每個 resolver 函數負責填充 schema 中對應字段的數據。它可以從數據庫、第三方 API 或其他來源獲取數據。
例如:
這段代碼展示了如何使用 resolvers
來處理查詢和變更操作。
const resolvers = {
Query: {
user: (root, args, context, info) => {
return context.database.user
},
},
Mutation: {
updateUser: (root, args, context, info) => {
const {auth} = context
if (!auth) {
return {
status: 401,
message: "unauthorization"
}
}
const {id, name} = args.input
if (parseInt(id, 10) === user.id) {
user['name'] = name
}
return {
payload: user,
status: 200,
message: "Success",
errors: null
}
}
},
User: {
email: (parent, args, context, info) => {
const {text} = args
if (user.email.indexOf(text) >= 0) {
return parent.email + text
}
return null
}
}
}
typeDefs
負責定義所有的 GraphQL 類型,包括查詢(Query)和變更(Mutation)。這些類型定義了你的 GraphQL API 的結構和操作。通常,typeDefs
會搭配 Apollo GraphQL Server 提供的 gql
標籤模板字面量來撰寫。gql
標籤模板字面量(tagged template literal)來定義 typeDefs
是一種常見的做法。主要原因:gql
標籤模板字面量可以讓編輯器識別出這段代碼是 GraphQL schema。編輯器可對代碼進行不同顏色標示,以提高代碼的可讀性和編寫效率。gql
標籤模板字面量會在編譯時對 GraphQL schema 進行語法檢查,及早發現並修正語法錯誤。gql
標籤模板字面量將 GraphQL schema 與其他 JavaScript 代碼區分開來,方便閱讀。updateUser
這樣的變更操作時,必須在 typeDefs
中定義對應的 Mutation
類型,並在解析器中實現具體的變更邏輯。這樣,伺服器才能正確處理和響應這個變更請求。以下這段程式碼展示了如何定義一個變更操作 updateUser
,包括輸入類型 UpdateUserInputType
和返回類型 UpdateUserPayload
。這樣的設計可以讓客戶端發送變更請求來更新使用者數據,並獲取操作的結果和相關訊息。
Mutation
和 updateUser
解析器函數的主要目的是處理客戶端發送的變更請求,並更新伺服器上的數據。在這個範例中:
const resolvers = {
Mutation: {
updateUser: (root, args, context, info) => {
const { auth } = context;
if (!auth) {
return {
status: 401,
message: "unauthorization",
};
}
const { id, name } = args.input;
if (parseInt(id, 10) === user.id) {
user['name'] = name;
}
return {
payload: user,
status: 200,
message: "Success",
errors: null,
};
},
},
};
updateUser
變更請求時,伺服器會調用 updateUser
解析器。context
中的 auth
狀態,如果未授權則返回 401 狀態。id
和 name
更新對應的使用者數據。updateUser: (root, args, context, info)
是一個解析器函數,用於處理 updateUser
變更操作。解析這個函數的參數:
null
或 undefined
一個。例如,如果你查詢 user
,返回一個 User
對象,那麼在 User
類型的解析器函數中,root
就是這個 User
對象。args.input
包含了 UpdateUserInputType
類型的數據。context.auth
來檢查用戶是否已經授權。apollo-server
:首先需要安裝並引用 apollo-server
套件。ApolloServer
創建伺服器實例,並將 Schema 和 Resolvers 傳遞給伺服器。const { ApolloServer, gql } = require('apollo-server');
// 定義 schema
const typeDefs = gql`
type Query {
hello: String
}
`;
// 定義 resolvers
const resolvers = {
Query: {
hello: () => 'Hello world!',
},
};
// 創建伺服器實例
const server = new ApolloServer({ typeDefs, resolvers });
// 指定端口並啟動伺服器
server.listen({ port: 4000 }).then(({ url }) => {
console.log(`🚀 Server ready at ${url}`);
});
const { ApolloServer, gql } = require('apollo-server');
// 模擬的資料庫
const database = {
user: {
id: 1,
name: 'Whien',
email: '[email protected]',
friends: ['Bob', 'Tom'],
work_state: 1,
created_at: new Date(),
updated_at: new Date()
}
};
// 模擬的使用者資料
const user = {
id: 1,
name: 'Whien',
email: '[email protected]',
friends: ['Bob', 'Tom'],
work_state: 1,
created_at: new Date(),
updated_at: new Date()
};
// 定義 GraphQL schema
const typeDefs = gql`
type User {
id: ID!
email(text: String): String
name: String
}
type Query {
user: User
}
input UpdateUserInputType {
id: ID!
name: String
}
type UpdateUserPayload {
payload: User
status: String
message: String
errors: [String]
}
type Mutation {
updateUser(input: UpdateUserInputType): UpdateUserPayload
}
`;
// 定義 resolvers
const resolvers = {
Query: {
user: (root, args, context, info) => {
return context.database.user;
},
},
Mutation: {
updateUser: (root, args, context, info) => {
const { auth } = context;
if (!auth) {
return {
status: 401,
message: "unauthorization"
};
}
const { id, name } = args.input;
if (parseInt(id, 10) === user.id) {
user['name'] = name;
}
return {
payload: user,
status: 200,
message: "Success",
errors: null
};
}
},
User: {
email: (parent, args, context, info) => {
const { text } = args;
if (user.email.indexOf(text) >= 0) {
return parent.email + text;
}
return null;
}
}
};
// 創建 Apollo 伺服器實例
const server = new ApolloServer({
typeDefs,
resolvers,
context: () => {
return {
auth: false,
database
};
}
});
// 指定端口並啟動伺服器
server.listen(8891, () => {
console.log('Apollo GraphQL Server run on port 8891');
});