graphql tools_聲明式GraphQL:編寫更少的代碼,并使用graphql-tools完成更多工作

graphql tools

I’ve been working with GraphQL for a few months now, but only recently began using Apollo’s graphql-tools library. After learning a few idioms, I am able to mock up a functional API quickly. This is largely due to its low-code, declarative approach to type definitions.

我已經使用GraphQL已有幾個月了,但是直到最近才開始使用Apollo的graphql-tools庫。 學習了一些習慣用法后,我便能夠快速模擬出功能性的API。 這主要是由于其對類型定義的低代碼聲明性方法。

從他們的例子開始 (Starting with their example)

Apollo has an interactive LaunchPad web site, like the ones covered in my Swagger series. There are several example schemas you can use, and for this article I will use their Post and Authors schema. You can download or fork the code.

阿波羅(Apollo)有一個交互式LaunchPad網站,就像我的Swagger系列文章中介紹的網站一樣。 您可以使用幾種示例模式,在本文中,我將使用其Post and Authors模式 。 您可以下載或分叉代碼。

I will be rearranging the project folders. For this post I’ll download and store it in Github, so I can branch and modify the code through each step. Along the way, I’ll link the branches to this post.

我將重新排列項目文件夾。 對于這篇文章,我將其下載并存儲在Github中,因此我可以在每個步驟中分支和修改代碼。 一路上,我將分支鏈接到該帖子。

基礎 (The basics)

  • declaring schema types

    聲明架構類型

In the Launchpad, you’ll see a typeDefs template literal:

在啟動板中,您將看到typeDefs模板文字:

const typeDefs = `type Author {id: Int!firstName: StringlastName: Stringposts: [Post] # the list of Posts by this author}type Post {id: Int!title: Stringauthor: Authorvotes: Int}# the schema allows the following query:type Query {posts: [Post]author(id: Int!): Author}# this schema allows the following mutation:type Mutation {upvotePost (postId: Int!): Post}
`;

There are two entities defined, Author and Post. In addition, there are two “magic” types: Query and Mutation. The Query type defines the root accessors. In this case, there’s an accessor to fetch all Posts, and another to fetch a single Author by ID.

定義了兩個實體AuthorPost 。 此外,還有兩種“魔術” 類型QueryMutation 。 查詢類型定義根accessors 。 在這種情況下,有一個訪問器來獲取所有Posts ,另一個訪問器是通過ID獲取單個Author

Note there is no way to directly query for a list of authors or for a single post. It is possible to add such queries later.

請注意,無法直接查詢作者列表或單個帖子。 以后可以添加此類查詢。

  • declaring resolvers

    宣布解析器

Resolvers provide the necessary logic to support the schema. They are written as a JavaScript object with keys that match the types defined in the schema. The resolver shown below operates against static data, which I’ll cover in a moment.

解析程序提供了支持架構的必要邏輯。 它們被編寫為具有與模式中定義的類型相匹配的鍵JavaScript對象。 下面顯示的resolver針對靜態數據進行操作,我將在稍后介紹。

const resolvers = {Query: {posts: () => posts,author: (_, { id }) => find(authors, { id: id }),},Mutation: {upvotePost: (_, { postId }) => {const post = find(posts, { id: postId });if (!post) {throw new Error(`Couldn't find post with id ${postId}`);}post.votes += 1;return post;},},Author: {posts: (author) => filter(posts, { authorId: author.id }),},Post: {author: (post) => find(authors, { id: post.authorId }),},
};

To link schema and resolver together, we’ll create an executable schema instance:

要將schemaresolver鏈接在一起,我們將創建一個可執行架構實例:

export const schema = makeExecutableSchema({typeDefs,resolvers,
});
  • the data source

    數據源

For this simple example, the data comes from two arrays of objects defined as constants: authors and posts:

對于此簡單示例,數據來自定義為常量的兩個對象數組: authors posts

const authors = [{ id: 1, firstName: 'Tom', lastName: 'Coleman' },{ id: 2, firstName: 'Sashko', lastName: 'Stubailo' },{ id: 3, firstName: 'Mikhail', lastName: 'Novikov' },
];const posts = [{ id: 1, authorId: 1, title: 'Introduction to GraphQL', votes: 2 },{ id: 2, authorId: 2, title: 'Welcome to Meteor', votes: 3 },{ id: 3, authorId: 2, title: 'Advanced GraphQL', votes: 1 },{ id: 4, authorId: 3, title: 'Launchpad is Cool', votes: 7 },
];
  • the server

    服務器

You can serve up the executable schema through graphql_express, apollo_graphql_express, or graphql-server-express. We see that in this example.

您可以通過graphql_expressapollo_graphql_expressgraphql-server-express提供可執行模式 我們在這個例子中看到了。

The important bits are:

重要的位是:

import { graphqlExpress, graphiqlExpress } from 'graphql-server-express';
import { schema, rootValue, context } from './schema';const PORT = 3000;
const server = express();server.use('/graphql', bodyParser.json(), graphqlExpress(request => ({schema,rootValue,context: context(request.headers, process.env),
})));server.use('/graphiql', graphiqlExpress({endpointURL: '/graphql',
}));server.listen(PORT, () => {console.log(`GraphQL Server is now running on 
http://localhost:${PORT}/graphql`);console.log(`View GraphiQL at 
http://localhost:${PORT}/graphiql`);
});

Note that there are two pieces of GraphQL middleware in use:

請注意,有兩個正在使用的GraphQL中間件:

  • graphqlExpress

    graphqlExpress

    the GraphQL server that handles queries and responses

    處理查詢和響應的GraphQL服務器

  • graphiqlExpress

    graphiqlExpress

    the interactive GraphQL web service that allows interactive queries through an HTML UI

    交互式GraphQL Web服務,該服務允許通過HTML UI進行交互式查詢

改組 (Reorganizing)

For large apps, we suggest splitting your GraphQL server code into 4 components: Schema, Resolvers, Models, and Connectors, which each handle a specific part of the work. (http://dev.apollodata.com/tools/graphql-tools/)

對于大型應用程序,我們建議將GraphQL服務器代碼分成4個組件:架構,解析器,模型和連接器,它們分別處理工作的特定部分。 ( http://dev.apollodata.com/tools/graphql-tools/ )

Putting each type of component in its own file makes sense. I’ll go one better and put each set of components in a its own “domain” folder.

將每種類型的組件放在其自己的文件中是有意義的。 我會做得更好,并將每組組件放在一個自己的“域”文件夾中。

為什么要域名? (Why domains?)

Domains are a convenient way to split up a large system into areas of operation. Within each domain there may be subdomains. In general, subdomains have a bounded context. Within a bounded context the entity names, properties, and processes have precise meaning.

域是將大型系統劃分為多個操作區域的便捷方法。 在每個域中可能有子域。 通常,子域具有有限的上下文。 在有限的上下文中,實體名稱,屬性和過程具有精確的含義。

I find bounded contexts to be helpful during analysis, especially when talking to domain experts.

我發現有限的上下文在分析過程中會有所幫助,特別是在與領域專家交談時。

The fly in the ointment is that GraphQL types occupy a single namespace, so naming conflicts can exist. More on that later.

美中不足的是,GraphQL類型僅占用一個名稱空間,因此可能存在命名沖突。 以后再說。

I’ll call this domain authorposts, and put the related components in the authorposts folder. Within that, I’ll create a file each for datasource, resolvers, and schema. Let’s also toss in an index.js file to simplify importing. The original schema and server files will remain in the root folder, but the schema.js code will be skeletal. The find and filter methods imported from lodash will be removed in favor of synonymous native ES6 methods. The resulting source is here.

我將這個域稱為authorposts ,并將相關組件放入authorposts folder authorposts folder authorposts folder 。 在其中,我將分別為datasourceresolvers和schema創建一個文件。 讓我們也將index.js文件折騰以簡化導入。 原始模式和服務器文件將保留在根文件夾中,但是schema.js代碼將是骨架的。 find lodash導入的filter方法將被刪除,以支持同義的本機ES6方法。 結果來源在這里 。

The main schema file has become simpler. It provides skeletal structure for further extension by schemas in our domains.

主模式文件變得更加簡單。 它為我們的領域中的架構提供了進一步擴展的骨架結構。

A domain schema is imported on lines 7–8, and the base schema on lines 11–23. You’ll note there is a domain property. This is arbitrary but GraphQL, or graphql-tools, insists that one property be defined.

domain模式在第7–8行導入, base模式在第11–23行導入。 您會注意到有一個屬性。 這是任意的,但是GraphQL或graphql-tools堅持要定義一個屬性。

The complete schema is constructed on line 26, and an executableSchema instance is created given the schema and resolvers defined so far on lines 28–33. This is what is imported by the server.js code, which is largely unchanged from the original.

完整的架構在第26行上構建,并根據第28–33行到目前為止定義的schemaresolvers創建了一個executableSchema實例。 這就是server.js代碼導入的內容,與原始代碼基本沒有變化。

There is a trick to splitting up a schema this way. Let’s take a look:

有這樣一種技巧可以拆分模式。 讓我們來看看:

The first listing, authorpostResolvers.js, is pretty much a cut’n’paste job from the original schema.js source from Apollo’s example. Yet in the authorpostSchema.js code, we extend the Query and Mutator definitions that are declared in the the base schema. If you don’t use the extend keyword, the executable schema builder will complain about two Query definitions.

第一個清單authorpostResolvers.js是Apollo示例中原始schema.js源代碼中的一個“剪切”粘貼工作。 但是,在authorpostSchema.js代碼中,我們擴展了在基礎架構中聲明的QueryMutator定義。 如果不使用extend關鍵字,則可執行模式構建器將抱怨兩個查詢定義。

繼續… (Continuing…)

This is a good start for organizing several schemas, one for each domain of interest (so long as you're mindful of the global namespace for types), but a complete schema, even for a single domain, can get huge. Fortunately, you can break down each schema even further, right down to the entity level, if necessary.

這是組織多個模式的一個良好的開始,一個模式用于每個感興趣的域(只要您注意類型的全局名稱空間),但是即使是單個域,一個完整的模式也會變得龐大。 幸運的是,您可以根據需要甚至進一步細分每個架構,直至實體級別 。

Here’s a modified directory structure, and listings of the new contents:

這是修改后的目錄結構,并列出了新內容:

We can achieve granularity by defining two component files, then importing them into a domain schema.

我們可以通過定義兩個組件文件,然后將它們導入域模式來實現粒度。

You don’t have to do one component per file. But you do want to be sure that the schema exports those components along with the schema itself as shown on line 20 of schema.js. Otherwise you’ll likely wind up missing a dependency further down the inclusion chain.

您不必為每個文件做一個組件。 但是您確實要確保該模式將這些組件與模式本身一起導出,如schema.js的第20行所示。 否則,您很可能最終會在包含鏈的下方錯過一個依賴項。

多個架構和解析器 (Multiple schemas and resolvers)

Adding a new schema for a new domain is simple. Create a new domain folder and add dataSource, resolvers, schema, and index.js files. You can also add an optional component folder with component type definitions.

為新域添加新架構很簡單。 創建一個新的域文件夾,并添加dataSource,解析器,架構和index.js文件。 您還可以添加帶有組件類型定義的可選組件文件夾。

Finally, the root schema.js file must combine the schemas and resolvers from both domains:

最后,根schema.js文件必須結合兩個域中的模式和解析器:

//...
import {schema as myLittleTypoSchema,resolvers as myLittleTypeResolvers
} from './myLittleDomain';import {merge
} from 'lodash';
//...
const schema = [...baseSchema, ...authorpostsSchema, ...myLittleTypoSchema]const options = {typeDefs: schema,resolvers: merge(authorpostsResolvers, myLittleTypeResolvers)
}

Note that I had to include lodash merge here because of the need for a deep merge of the two resolvers imports.

請注意,由于必須深度合并兩個解析器 ,因此我必須在此處包括lodash 合并 進口。

處理命名空間沖突 (Dealing with Namespace Collisions)

If you are on a large project, you will encounter type name collisions. You might think that Account in one domain would mean the same as Account in another. Yet even if they do mean more or less similar things, chances are the properties and relationships will be different. So technically they are not the same type.

如果您在大型項目中,則會遇到類型名稱沖突。 您可能會認為一個域中的帳戶與另一個域中的帳戶含義相同。 然而,即使它們確實或多或少地意味著相似的事物,屬性和關系也有可能會不同。 因此,從技術上講,它們不是同一類型。

At the time of this writing, GraphQL uses a single namespace for types.

在撰寫本文時,GraphQL對類型使用單個名稱空間。

How to work around this? Facebook apparently uses a naming convention for their 10,000 types. As awkward as that seems, it works for them.

如何解決這個問題? Facebook顯然為其10,000種類型使用命名約定 。 看起來很尷尬,但對他們有用。

The Apollo graphql-tools stack appears to catch type name duplications. So you should be good there.

Apollo graphql-tools堆棧似乎捕獲類型名稱重復項。 所以你在那里應該很好。

There is an ongoing discussion on whether to include namespaces in GraphQL. It isn’t a simple decision . I remember the complexities caused by the introduction of XML Namespaces 10 years ago.

關于是否在GraphQL中包括名稱空間的討論正在進行中。 這不是一個簡單的決定。 我記得10年前引入XML命名空間引起的復雜性。

然后去哪兒? (Where to go from here?)

This post only scratches the surface of how one might organize a large set of GraphQL schemas. The next post will be about mocking GraphQL resolvers, and how it’s possible to mix both real and mocked values in query responses.

這篇文章只是對如何組織一大套GraphQL模式的表述。 下一篇文章將關于模擬GraphQL解析器,以及如何在查詢響應中混合使用真實值和模擬值。

翻譯自: https://www.freecodecamp.org/news/declarative-graphql-with-graphql-tools-cd1645f94fc/

graphql tools

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/395290.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/395290.shtml
英文地址,請注明出處:http://en.pswp.cn/news/395290.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

用idea搭建SSM項目,原來這么簡單

目錄 前言軟件環境創建項目數據庫文件配置文件pom.xmllog4j.propertiesjdbc.propertiesapplicationContext.xmlspring-mvc.xmlweb.xml運行項目編寫代碼前言 前陣子突發奇想,想學習下SpringMVC的源碼,于是打算用idea搭建一個簡易的maven版SSM案例&#xf…

浙江理工大學計算機組成原理試卷,浙江理工大學計算機組成原理設計試題.doc...

計算機組成原理課程設計報告2013/2014第二學期指導教師:許建龍 張芳班級:12計科2班姓名:學號: 計算機組成原理大型實驗任務書(計算機12級1、2、3班和實驗班)實驗目的:深入了解計算機各種指令的執行過程,以及…

mac vagrant 虛擬機nfs掛載點

需求:在mac 上安裝了虛擬機,虛擬機系統為centos6.5,現在希望講虛擬機上點目錄通過nfs共享給mac使用 下面主要描述通過nfs共享目錄給mac調用的過程 過程參考網址: http://www.moqifei.com/archives/1534 (我主要參考的這…

nodejs中require的路徑是一個文件夾時發生了什么

node中使用require的時候如果路徑是一個文件夾時,或者特殊的情況require(..);require(.); 這是node實戰這本書里說的情況,但是我在node6.9版本中發現不完全是這樣,可能是后來做了修改。下面說說在6.9下require路徑的過程。 這里以require(.)說…

python調用ctypes中windll中的方法超時處理_python中使用ctypes調用MinGW生成的動態鏈接庫(dll)...

關于gcc編譯dll的我就不說了,網上舉例一大堆,下面以g為例。假設有一個test.cpp文件如下:extern "C" {__declspec(dllexport) double add(double x,double y);}double add(double x,double y){return xy;}在MinGW中使用g編譯&#x…

慣用過程模型_慣用的Ruby:編寫漂亮的代碼

慣用過程模型Ruby is a beautiful programming language.Ruby是一種美麗的編程語言。 According to Ruby’s official web page, Ruby is a:根據Ruby的官方網頁,Ruby是: “dynamic, open source programming language with a focus on simplicity and …

采用晶體管為基本元件的計算機發展階段是,計算機應用基礎知識點

第一章 計算機基礎知識1、計算機發展階段第一代:電子管計算機采用電子管為基本元件,設計使用機器語言或匯編語言。要用于科學和工程計算 第二代:晶體管計算機采用晶體管為基本元件,程序設計采用高級語言,出現了操作系統…

springcloud系列三 搭建服務模塊

搭建服務模塊為了模擬正式開發環境,只是少寫了service層直接在controller里面直接引用,直接上圖和代碼:更為方便: 創建完成之后加入配置: pom.xml文件: <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM…

P1801 黑匣子_NOI導刊2010提高(06)

題目描述 Black Box是一種原始的數據庫。它可以儲存一個整數數組&#xff0c;還有一個特別的變量i。最開始的時候Black Box是空的&#xff0e;而i等于0。這個Black Box要處理一串命令。 命令只有兩種&#xff1a; ADD(x):把x元素放進BlackBox; GET:i加1&#xff0c;然后輸出Bla…

MySql模糊查詢

常規like的使用限制&#xff1a; 1. like %keyword &#xff1a;索引失效&#xff0c;使用全表掃描。但可以通過翻轉函數like前模糊查詢建立翻轉函數索引走翻轉函數索引&#xff0c;不走全表掃描。 2. like keyword% &#xff1a;索引有效。 3. like %keyword% &#xff1a;索引…

python psycopg2使用_python?操作數據庫:psycopg2的使用

1 conn psycopg2.connect(database"testdb", user"postgres",password"cohondob", host"127.0.0.1", port"5432")這個API打開一個連接到PostgreSQL數據庫。如果成功打開數據庫時&#xff0c;它返回一個連接對象。2cursor c…

軟件測試人員棘手的問題,èí?t2aê?μ???ê??êìa£oè?o?±ü?a???′ìá??è±?Y...

¡¡¡¡£££©£¡££¡££££©©£¡¡¡¡¡BUG£££¢¡£££¡££¡£¡£——£…

機器學習實用指南_機器學習方法:實用指南

機器學習實用指南by Karlijn Willems通過Karlijn Willems 機器學習方法&#xff1a;實用指南 (How Machines Learn: A Practical Guide) You may have heard about machine learning from interesting applications like spam filtering, optical character recognition, and …

本地倉庫settings.xml中使用阿里的倉庫

背景 當前使用eclipse自帶的maven碰到兩個蛋疼的問題&#xff1a; maven在國內使用如果不進行FQ則會痛苦不堪如便秘。maven下載大量jar包導致某盤不夠用&#xff0c;需要換大的分區。因此為了解決這個問題就介紹兩個eclipse配置&#xff1a;maven本地路徑配置和maven外部路徑配…

day6_python之md5加密

#md5是不可逆的&#xff0c;就是沒有辦法解密的 Python內置哈希庫對字符串進行MD5加密的方法-hashlibimport hashlib def my_md5(s,salt): #用函數&#xff0c;為了提高代碼的復用率s ssalt #1.必須是字符串news str(s).encode() #2.字符串需要encode編碼后&#xff0…

異步服務_微服務全鏈路異步化實踐

1. 背景隨著公司業務的發展&#xff0c;核心服務流量越來越大&#xff0c;使用到的資源也越來越多。在微服務架構體系中&#xff0c;大部分的業務是基于Java 語言實現的&#xff0c;受限于Java 的線程實現&#xff0c;一個Java 線程映射到一個kernel 線程&#xff0c;造成了高并…

win7打開計算機死機,怎么樣解決Win7系統運行程序引起的死機問題

Win7系統不僅需要使用到電腦中自帶的一些程序&#xff0c;同時&#xff0c;也需要在win7旗艦版電腦中有選擇的自己去安裝一些程序。但是經常有用戶會碰到Win7電腦突然跳出運行程序未響應&#xff0c;出現電腦死機的情況&#xff0c;特別是開的瀏覽器窗口多的時候更是死機的頻繁…

(poj)1064 Cable master 二分+精度

題目鏈接&#xff1a;http://poj.org/problem?id1064 DescriptionInhabitants of the Wonderland have decided to hold a regional programming contest. The Judging Committee has volunteered and has promised to organize the most honest contest ever. It was decided…

PHP中如何解決高并發

PHP中如何解決高并發 1&#xff1a;硬件方面 普通的一個p4的服務器每天最多能支持大約10萬左右的IP&#xff0c;如果訪問量超過10W那么需要專用的服務器才能解決&#xff0c;如果硬件不給力 軟件怎么優化都是于事無補的。主要影響服務器的速度 有&#xff1a;網絡-硬盤讀寫速度…

es6 迭代器_揭秘ES6迭代器和迭代器

es6 迭代器by Tiago Lopes Ferreira由Tiago Lopes Ferreira 揭秘ES6迭代器和迭代器 (Demystifying ES6 Iterables & Iterators) ES6 introduces a new way to interact with JavaScript data structures — iteration. Let’s demystify it.ES6引入了一種與JavaScript數據…