
如何快速實(shí)現(xiàn)REST API集成以優(yōu)化業(yè)務(wù)流程
Nexus 是一個(gè)最初由?Tim Griesser?編寫的庫(kù),它允許開發(fā)人員構(gòu)建代碼優(yōu)先和類型安全的 GraphQL API。在過(guò)去的兩年多時(shí)間里,Prisma 作為該庫(kù)的核心貢獻(xiàn)者,一直在推動(dòng)其發(fā)展與成型。
今天,我們非常榮幸地宣布 Nexus 1.0 版本的發(fā)布。
這一版本是社區(qū)寶貴反饋與貢獻(xiàn)、多年實(shí)戰(zhàn)生產(chǎn)中 Nexus 的經(jīng)驗(yàn)積累,以及致力于為 GraphQL API 構(gòu)建者打造卓越開發(fā)體驗(yàn)所提煉出的結(jié)晶。
請(qǐng)注意:Prisma 的產(chǎn)品已不再局限于 GraphQL。您可以在 REST API、GraphQL API 中,或任何需要在 Node 或 Go 中訪問(wèn)數(shù)據(jù)庫(kù)的場(chǎng)景下使用 Prisma。盡管我們?yōu)?Nexus 做出了貢獻(xiàn),但它并不必須與 Prisma 配套使用。更多關(guān)于 Prisma 提供的功能及其使用方法的信息,請(qǐng)查閱相關(guān)文檔。
Nexus提供了一種在Node.js環(huán)境中構(gòu)建代碼優(yōu)先GraphQL API的途徑。這種方法與(可能更為普遍的)架構(gòu)優(yōu)先方法形成了鮮明的對(duì)比。
許多剛開始構(gòu)建GraphQL API的開發(fā)人員通常會(huì)首先選擇架構(gòu)優(yōu)先的方法,這種方法已被諸如Apollo及其Apollo Server產(chǎn)品等公司廣泛推廣。
在采用架構(gòu)優(yōu)先的方法時(shí),構(gòu)建GraphQL API需要定義一組類型以及相應(yīng)的解析器。一個(gè)簡(jiǎn)單的架構(gòu)優(yōu)先服務(wù)器可能呈現(xiàn)如下形式:
type Post {
id: ID!
title: String!
body: String!
}
type Query {
posts: [Post]!
}
const Query = {
posts: () => [
{
id: '1',
title: 'My first GraphQL server',
body: 'How I wrote my first GraphQL server',
},
],
}
雖然架構(gòu)優(yōu)先方法很容易上手,但它也存在一些固有的缺點(diǎn),隨著應(yīng)用程序規(guī)模的擴(kuò)大,這些缺陷可能會(huì)讓開發(fā)工作變得棘手。
Nexus則采用了截然不同的方法來(lái)構(gòu)建GraphQL API。在使用Nexus時(shí),架構(gòu)和解析器是通過(guò)代碼在同一位置編寫的,而不是將它們分別保存在獨(dú)立的架構(gòu)和解析器集合中。
如果將上面的Post示例用Nexus進(jìn)行重構(gòu),將會(huì)呈現(xiàn)如下形式:
import { objectType, queryType, makeSchema } from 'nexus'
const Post = objectType({
name: 'Post',
definition(t) {
t.id('id')
t.string('title')
t.string('body')
},
})
const Query = queryType({
definition(t) {
t.list.field('posts', {
resolve: () => [
{
id: '1',
title: 'My first GraphQL server',
body: 'How I wrote my first GraphQL server',
},
],
})
},
})
const schema = makeSchema({
types: [Post, Query],
})
使用 Nexus 采用代碼優(yōu)先方法有很多好處,包括:
在構(gòu)建以架構(gòu)為核心的 GraphQL API 時(shí),一個(gè)常見的做法是起初將所有類型定義與解析器置于同一文件中。當(dāng)架構(gòu)與解析器相鄰配置時(shí),同時(shí)在兩者間進(jìn)行操作顯得相對(duì)直觀便捷。
然而,隨著應(yīng)用程序規(guī)模的擴(kuò)大,通常需要將架構(gòu)的不同部分拆分到各自的獨(dú)立模塊和文件中。正是在這一環(huán)節(jié),GraphQL API 的處理變得更為繁瑣。這種模塊化操作要求在 GraphQL Schema Definition Language(SDL)與 JavaScript/TypeScript 之間頻繁切換以編寫解析器。這不僅僅意味著需要在多個(gè)文件間不斷跳轉(zhuǎn),還需要在心理上進(jìn)行上下文轉(zhuǎn)換,以適應(yīng)在兩種不同語(yǔ)言間的工作。
借助 Nexus,我們的架構(gòu)及其解析器總是協(xié)同定義。Nexus 還允許我們使用同一種編程語(yǔ)言來(lái)編寫所有內(nèi)容。這使我們能夠完全避免位置/上下文切換的問(wèn)題,并在我們的應(yīng)用程序規(guī)模不斷擴(kuò)大的情況下,依然能夠保持高效的工作狀態(tài)。
使用Nexus的一個(gè)顯著優(yōu)勢(shì)在于它能夠自動(dòng)地生成TypeScript類型以及GraphQL架構(gòu)定義語(yǔ)言(SDL)文件。這些自動(dòng)生成的類型可以為支持GraphQL API的代碼提供額外的類型安全保障。同時(shí),生成的SDL文件也具備多種用途,例如,我們可以配置編輯器以了解API的結(jié)構(gòu),從而便于對(duì)編寫的查詢和變更進(jìn)行自省。
Nexus免費(fèi)提供類型和SDL的生成功能,只需在調(diào)用makeSchema
時(shí)提供相應(yīng)配置即可啟用。
import path from 'path'
const schema = makeSchema({
types: [Post, Query],
outputs: {
schema: path.join(__dirname, 'generated/schema.gen.graphql'),
typegen: path.join(__dirname, 'generated/nexusTypes.gen.ts'),
},
})
Nexus 1.0 版有許多變化。閱讀完整的更新日志并按照下面的內(nèi)容進(jìn)行操作,看看有什么新內(nèi)容!
Nexus 1.0 現(xiàn)已采用新的軟件包名稱。現(xiàn)在,所有導(dǎo)入操作均需來(lái)自新的路徑,而非原先的 .nexus/schema
,而是改為使用 nexus
下的相應(yīng)名稱。
import { makeSchema } from 'nexus'
// ...
在早期的Nexus版本中,字段默認(rèn)被視為不可為空,這與其他GraphQL API框架的做法有所不同,后者通常默認(rèn)將字段視為可為null,除非另有指定。Nexus的開發(fā)者之所以采取這種默認(rèn)策略,是因?yàn)樗麄冋J(rèn)為默認(rèn)允許字段不可為空可能會(huì)給API的開發(fā)帶來(lái)一些長(zhǎng)期的風(fēng)險(xiǎn)。
然而,在Nexus 1.0中,字段的默認(rèn)可空性已經(jīng)進(jìn)行了調(diào)整,以與GraphQL的最佳實(shí)踐和期望保持一致,特別是與GraphQL官方推薦的實(shí)踐相符?,F(xiàn)在,在Nexus 1.0中,如果需要將字段設(shè)為非null,則需要顯式地進(jìn)行聲明。
const Post = objectType({
name: 'Post',
definition(t) {
t.nonNull.id('id')
t.nonNull.string('title')
t.nonNull.string('body')
},
})
此類型的 SDL 將如下所示:
type Post {
id: ID!
title: String!
body: String!
}
上述對(duì)象類型的代碼包含一個(gè)名為 property
的屬性,該屬性為指定字段必須為非空(non-null)提供了更高的靈活性。在 API 設(shè)計(jì)面臨挑戰(zhàn)時(shí),比如表示深度嵌套的類型結(jié)構(gòu),或者需要以編程方式構(gòu)建不可為空(non-nullable)的類型,這個(gè)屬性就顯得尤為有用。例如,可以創(chuàng)建一個(gè)名為 PostNonNull
的類型。
import { queryType, stringArg, nonNull } from 'nexus'
queryType({
definition(t) {
t.field('tags', {
type: nonNull('String') // => String!
args: {
id: nonNull(stringArg()) // or nonNull('String') => String!
},
resolve() {
// ...
}
})
}
})
該函數(shù)接受一個(gè)參數(shù),該參數(shù)可用于指定類型或參數(shù)的非空性(nonNull
)。
盡管字段現(xiàn)在默認(rèn)允許為null,但在Nexus API中,您仍然可以選擇全局或在類型級(jí)別更改這一默認(rèn)行為。
queryType({
nonNullDefaults: {
output: true,
},
definition(t) {
t.string('echo', {
args: {
message: 'String',
},
resolve(_root, args) {
return args.message
},
})
},
})
在此示例中,Nexus 現(xiàn)在要求所有查詢類型字段默認(rèn)應(yīng)為非空(non-null)。
如果您希望將某些字段的默認(rèn)類型更改為可為空(nullable),則可以使用 nullable
函數(shù)來(lái)實(shí)現(xiàn)。
import { queryType, stringArg, nullable } from 'nexus'
queryType({
nonNullDefaults: {
input: true,
output: true,
},
definition(t) {
t.field('echo', {
type: nullable('String'),
args: {
message: nullable(stringArg()),
},
resolve(_root, args) {
return args.message
},
})
},
})
要深入了解Nexus如何處理可為null性,包括與API進(jìn)行交互的其他相關(guān)方式,請(qǐng)查閱可為null性指南。
Nexus 1.0引入了一個(gè)新功能,專門用于處理列表類型。這個(gè)功能既可以應(yīng)用于輸入類型,也可以應(yīng)用于輸出類型,其使用方式與某些其他函數(shù)類似(例如list
、nonNull
和nullable
等函數(shù))。
import { queryType, stringArg, list } from 'nexus'
queryType({
definition(t) {
t.field('tags', {
type: list('String') // -> [String]
args: {
ids: list(stringArg()) // or list('String') -> [String]
},
resolve() {
// ...
}
})
}
})
用于創(chuàng)建列表的相同鏈接 API 依然保留,但新增的函數(shù)在處理某些不理想鏈接情況時(shí)提供了幫助。list
函數(shù)即為此類工具之一。
在 GraphQL 中,抽象類型是指 Union 和 Interface 類型。
Union 類型能夠表示多態(tài)字段,其成員類型可以截然不同。
Interface 類型則允許表示多態(tài)字段,這些字段可能返回多種不同的對(duì)象類型,但它們都共享某些字段的子集。
官方 GraphQL JavaScript 包提供了三種實(shí)現(xiàn)抽象類型的策略,而 Nexus 1.0 現(xiàn)如今通過(guò)一個(gè) API 支持了這三種策略,并在此過(guò)程中確保了類型安全。
請(qǐng)注意,以下示例雖以 union 類型為例,但同樣適用于 interface 類型。
Centralized 策略允許您通過(guò)一種集中化(針對(duì)聯(lián)合類型)的方式來(lái)區(qū)分聯(lián)合中的不同成員類型。例如:
const SearchResult = unionType({
name: 'SearchResult',
resolveType(data) {
const __typename = data.album ? 'Song' : data.rating ? 'Movie' : data.width ? 'Photo' : null
if (!__typename) {
throw new Error(Could not resolve the type of data passed to union type "SearchResult"
)
}
return __typename
},
definition(t) {
t.members('Photo', 'Movie', 'Song')
},
})
判別模型字段(DMF)策略使您能夠以潛在的模塊化方式來(lái)區(qū)分聯(lián)合類型的成員。該策略基于在由類型化為抽象類型的字段解析器返回的數(shù)據(jù)中包含的__typename
字段。以下是一個(gè)示例:
const Query = queryType({
definition(t) {
t.field('search', {
type: 'SearchResult',
args: {
pattern: stringArg(),
},
resolve(root, args, ctx) {
return ctx.db.search(args.pattern).map(result => {
const __typename = result.album ? 'Song' : result.rating ? 'Movie' : result.width ? 'Photo' : null
if (!__typename) {
throw new Error(Could not resolve the type of data passed to union type "SearchResult"
)
}
return {
...result,
__typename,
}
})
},
})
},
})
模塊化策略使您能夠以模塊化的方式區(qū)分聯(lián)合類型的成員。它依賴于您實(shí)現(xiàn)的謂詞函數(shù),該函數(shù)使Nexus(以及背后的GraphQL.js)能夠在運(yùn)行時(shí)判斷發(fā)送給客戶端的數(shù)據(jù)是否屬于特定的類型。以下是一個(gè)示例:
const Movie = objectType({
name: 'Movie',
isTypeOf(data) {
return Boolean(data.rating)
},
definition(t) {
t.string('url')
t.field('rating', {
type: 'MovieRating',
})
},
})
const Photo = objectType({
name: 'Photo',
isTypeOf(data) {
return Boolean(data.width)
},
definition(t) {
t.string('url')
t.int('width')
t.int('height')
},
})
const Song = objectType({
name: 'Song',
isTypeOf(data) {
return Boolean(data.album)
},
definition(t) {
t.string('url')
t.string('album')
},
})
閱讀抽象類型指南,您將深入了解這些策略的工作原理、如何啟用或禁用它們、以及它們?nèi)绾未_保類型安全等詳細(xì)信息。
在初步構(gòu)建架構(gòu)時(shí),您可能會(huì)注意到一些起初并不顯而易見的現(xiàn)象。客戶端在數(shù)據(jù)圖中所見的數(shù)據(jù)與內(nèi)部解析器處理的數(shù)據(jù)存在差異??蛻舳私佑|的是 API 類型,而 API 設(shè)計(jì)者則處理其他內(nèi)容,這些內(nèi)容在 Nexus 中傳統(tǒng)上被稱為“支持”或“根”類型。在 Nexus 1.0 中,這些類型現(xiàn)在被全局統(tǒng)一稱為“Source Types”。
請(qǐng)查閱源類型指南,以獲取更多關(guān)于它們是什么、以及如何使用它們的信息。
Nexus 1.0 帶來(lái)了文檔體驗(yàn)的提升,包括新增的指南、更優(yōu)化的導(dǎo)航、JSDoc 支持,以及 Nexus Playground 的改進(jìn)。
JSDoc 支持改進(jìn)了開發(fā)人員體驗(yàn)。文檔內(nèi)容包括:
Nexus的playground已經(jīng)轉(zhuǎn)變?yōu)橐幌盗蓄A(yù)先準(zhǔn)備好的Codesandbox示例。新的Playground提供了一個(gè)預(yù)配置的Nexus API環(huán)境,您可以輕松進(jìn)行fork和擴(kuò)展。
Nexus 1.0是該庫(kù)發(fā)展歷程中的一個(gè)重要里程碑。在過(guò)去的兩年多里,社區(qū)在其成長(zhǎng)和成功中扮演了至關(guān)重要的角色。我們衷心感謝所有試用Nexus、提交問(wèn)題、貢獻(xiàn)代碼并將其投入生產(chǎn)使用的朋友們!
請(qǐng)?jiān)?a href="http://cnzze.cn/provider/uid20241128320605c6dda2">Twitter上關(guān)注@nexusgql,并關(guān)注我們的倉(cāng)庫(kù),以便獲取關(guān)于Nexus未來(lái)更新的最新信息。
原文鏈接:https://www.prisma.io/blog/announcing-the-release-of-nexus-schema-v1-b5eno5g08d0b
對(duì)比大模型API的內(nèi)容創(chuàng)意新穎性、情感共鳴力、商業(yè)轉(zhuǎn)化潛力
一鍵對(duì)比試用API 限時(shí)免費(fèi)