golang底层深入_带有Golang的GraphQL:从基础到高级的深入研究
golang底層深入
by Ridham Tarpara
由里德姆·塔帕拉(Ridham Tarpara)
帶有Golang的GraphQL:從基礎(chǔ)到高級(jí)的深入研究 (GraphQL with Golang: A Deep Dive From Basics To Advanced)
GraphQL has become a buzzword over the last few years after Facebook made it open-source. I have tried GraphQL with the Node.js, and I agree with all the buzz about the advantages and simplicity of GraphQL.
在Facebook開源之后的最近幾年里,GraphQL已經(jīng)成為流行語。 我已經(jīng)使用Node.js嘗試了GraphQL,并且我對(duì)GraphQL的優(yōu)點(diǎn)和簡單性一事都表示贊同。
So what is GraphQL? This is what the official GraphQL definition says:
那么,GraphQL是什么? 官方的GraphQL定義是這樣的:
GraphQL is a query language for APIs and runtime for fulfilling those queries with your existing data. GraphQL provides a complete and understandable description of the data in your API, gives clients the power to ask for exactly what they need and nothing more, makes it easier to evolve APIs over time, and enables powerful developer tools.GraphQL是用于API和運(yùn)行時(shí)的查詢語言,用于使用現(xiàn)有數(shù)據(jù)來完成這些查詢。 GraphQL為您的API中的數(shù)據(jù)提供完整且易于理解的描述,使客戶能夠準(zhǔn)確地詢問他們所需的內(nèi)容,僅此而已,使隨著時(shí)間的推移更易于開發(fā)API并啟用強(qiáng)大的開發(fā)人員工具。I recently switched to Golang for a new project I’m working on (from Node.js) and I decided to try GraphQL with it. There are not many library options with Golang but I have tried it with Thunder, graphql, graphql-go, and gqlgen. And I have to say that gqlgen is winning among all the libraries I have tried.
我最近切換到Golang從事我正在研究的新項(xiàng)目(來自Node.js),我決定嘗試使用GraphQL。 Golang的庫選項(xiàng)不多,但我已使用Thunder , graphql , graphql-go和gqlgen對(duì)其進(jìn)行了嘗試 。 我不得不說, gqlgen在我嘗試過的所有庫中勝出。
gqlgen is still in beta with latest version 0.7.2 at the time of writing this article, and it’s rapidly evolving. You can find their road-map here. And now 99designs is officially sponsoring them, so we will see even better development speed for this awesome open source project. vektah and neelance are major contributors, and neelance also wrote graphql-go.
在撰寫本文時(shí), gqlgen仍處于beta版,最新版本為0.7.2 ,并且它正在Swift發(fā)展。 您可以在此處找到他們的路線圖。 現(xiàn)在99designs正式贊助了它們,因此我們將為這個(gè)很棒的開源項(xiàng)目看到更快的開發(fā)速度。 vektah和neelance是主要貢獻(xiàn)者, neelance還寫了graphql-go 。
So let’s dive into the library semantics assuming you have basic GraphQL knowledge.
因此,假設(shè)您具有基本的GraphQL知識(shí),讓我們深入研究庫語義。
強(qiáng)調(diào) (Highlights)
As their headline states,
作為他們的標(biāo)題,
This is a library for quickly creating strictly typed GraphQL servers in Golang.這是一個(gè)用于在Golang中快速創(chuàng)建嚴(yán)格類型的GraphQL服務(wù)器的庫。I think this is the most promising thing about the library: you will never see map[string]interface{} here, as it uses a strictly typed approach.
我認(rèn)為這是庫中最有前途的事情:在這里您永遠(yuǎn)不會(huì)看到map[string]interface{} ,因?yàn)樗褂脟?yán)格類型化的方法。
Apart from that, it uses a Schema first Approach: so you define your API using the graphql Schema Definition Language. This has its own powerful code generation tools which will auto-generate all of your GraphQL code and you will just need to implement the core logic of that interface method.
除此之外,它使用Schema first方法 :因此,您可以使用graphql Schema Definition Language定義API。 它具有自己強(qiáng)大的代碼生成工具,可以自動(dòng)生成所有GraphQL代碼,您只需要實(shí)現(xiàn)該接口方法的核心邏輯即可。
I have divided this article into two phases:
我將本文分為兩個(gè)階段:
- The basics: Configuration, Mutations, Queries, and Subscription 基礎(chǔ)知識(shí):配置,突變,查詢和訂閱
- The advanced: Authentication, Dataloaders, and Query Complexity 高級(jí):身份驗(yàn)證,數(shù)據(jù)加載器和查詢復(fù)雜性
階段1:基礎(chǔ)知識(shí)-配置,變異,查詢和訂閱 (Phase 1: The Basics - Configuration, Mutations, Queries, and Subscriptions)
We will use a video publishing site as an example in which a user can publish a video, add screenshots, add a review, and get videos and related videos.
我們將以視頻發(fā)布網(wǎng)站為例,用戶可以在其中發(fā)布視頻,添加屏幕截圖,添加評(píng)論以及獲取視頻和相關(guān)視頻。
mkdir -p $GOPATH/src/github.com/ridhamtarpara/go-graphql-demo/Create the following schema in the project root:
在項(xiàng)目根目錄中創(chuàng)建以下架構(gòu):
Here we have defined our basic models and one mutation to publish new videos, and one query to get all videos. You can read more about the graphql schema here. We have also defined one custom type (scalar), as by default graphql has only 5 scalar types that include Int, Float, String, Boolean and ID.
在這里,我們定義了基本模型,定義了一種版本來發(fā)布新視頻,并定義了一種查詢來獲取所有視頻。 您可以在此處閱讀有關(guān)graphql 模式的更多信息。 我們還定義了一種自定義類型(標(biāo)量),因?yàn)槟J(rèn)情況下graphql只有5種標(biāo)量類型 ,包括Int,Float,String,Boolean和ID。
So if you want to use custom type, then you can define a custom scalar in schema.graphql (like we have defined Timestamp) and provide its definition in code. In gqlgen, you need to provide marshal and unmarshal methods for all custom scalars and map them to gqlgen.yml.
因此,如果要使用自定義類型,則可以在schema.graphql定義自定義標(biāo)量(就像我們已經(jīng)定義了Timestamp ),并在代碼中提供其定義。 在gqlgen中,您需要為所有自定義標(biāo)量提供編組和解編方法,并將它們映射到gqlgen.yml 。
Another major change in gqlgen in the last version is that they have removed the dependency on compiled binaries. So add the following file to your project under scripts/gqlgen.go.
最新版本中g(shù)qlgen的另一個(gè)主要變化是,它們刪除了對(duì)已編譯二進(jìn)制文件的依賴。 因此,將以下文件添加到腳本/gqlgen.go下的項(xiàng)目中。
and initialize dep with:
并使用以下命令初始化dep:
dep initNow it’s time to take advantage of the library’s codegen feature which generates all the boring (but interesting for a few) skeleton code.
現(xiàn)在是時(shí)候利用該庫的codegen功能,該功能生成所有無聊的(但有一些有趣的)骨架代碼。
go run scripts/gqlgen.go initwhich will create the following files:
這將創(chuàng)建以下文件:
gqlgen.yml — Config file to control code generation.generated.go — The generated code which you might not want to see.models_gen.go — All the models for input and type of your provided schema.resolver.go — You need to write your implementations.server/server.go — entry point with an http.Handler to start the GraphQL server.
gqlgen.yml —用于控制代碼生成的配置文件。 created.go —您可能不想看到的生成的代碼。 models_gen.go —用于提供的模式的輸入和類型的所有模型。 resolver.go-您需要編寫實(shí)現(xiàn)。 server / server.go —帶有http.Handler的入口點(diǎn),用于啟動(dòng)GraphQL服務(wù)器。
Let’s have a look at one of the generated models of the Video type:
讓我們看一下Video類型的生成模型之一:
Here, as you can see, ID is defined as a string and CreatedAt is also a string. Other related models are mapped accordingly, but in the real world you don’t want this — if you are using any SQL data type you want your ID field as int or int64, depending on your database.
如您所見,此處ID定義為字符串,CreatedAt也是字符串。 其他相關(guān)的模型也進(jìn)行了相應(yīng)的映射,但是在現(xiàn)實(shí)世界中,您不需要這樣做-如果您使用任何SQL數(shù)據(jù)類型,則希望ID字段為int或int64,具體取決于數(shù)據(jù)庫。
For example I am using PostgreSQL for demo so of course I want ID as an int and CreatedAt as a time.Time. So we need to define our own model and instruct gqlgen to use our model instead of generating a new one.
例如,我正在使用PostgreSQL進(jìn)行演示,因此我當(dāng)然希望ID為int且CreatedAt為time.Time 。 因此,我們需要定義自己的模型,并指示gqlgen使用我們的模型,而不是生成新模型。
and update gqlgen to use these models like this:
并更新gqlgen以使用以下模型:
So, the focal point is the custom definitions for ID and Timestamp with the marshal and unmarshal methods and their mapping in a gqlgen.yml file. Now when the user provides a string as ID, UnmarshalID will convert a string into an int. While sending the response, MarshalID will convert int to string. The same goes for Timestamp or any other custom scalar you define.
因此,重點(diǎn)是具有marshal和unmarshal方法的ID和Timestamp的自定義定義,以及它們?cè)趃qlgen.yml文件中的映射。 現(xiàn)在,當(dāng)用戶提供字符串作為ID時(shí),UnmarshalID會(huì)將字符串轉(zhuǎn)換為int。 發(fā)送響應(yīng)時(shí),MarshalID會(huì)將int轉(zhuǎn)換為字符串。 時(shí)間戳或您定義的任何其他自定義標(biāo)量也是如此。
Now it’s time to implement real logic. Open resolver.go and provide the definition to mutation and queries. The stubs are already auto-generated with a not implemented panic statement so let’s override that.
現(xiàn)在該實(shí)現(xiàn)真正的邏輯了。 打開resolver.go并提供突變和查詢的定義。 存根已經(jīng)通過未實(shí)現(xiàn)的panic語句自動(dòng)生成,因此我們將其覆蓋。
and hit the mutation:
并擊中突變:
Ohh it worked….. but wait, why is my user empty ?? So here there is a similar concept like lazy and eager loading. As graphQL is extensible, you need to define which fields you want to populate eagerly and which ones lazily.
哦,行得通……..但是,為什么我的用戶為空? 因此,這里有類似的概念,例如延遲加載和渴望加載。 由于graphQL是可擴(kuò)展的,因此您需要定義要急切填充的字段和懶散地填充的字段。
I have created this golden rule for my organization team working with gqlgen:
我為與gqlgen合作的組織團(tuán)隊(duì)創(chuàng)建了這一黃金法則:
Don’t include the fields in a model which you want to load only when requested by the client.
不要僅在客戶要求時(shí)才在要加載的模型中包括字段。
For our use-case, I want to load Related Videos (and even users) only if a client asks for those fields. But as we have included those fields in the models, gqlgen will assume that you will provide those values while resolving video — so currently we are getting an empty struct.
對(duì)于我們的用例,僅當(dāng)客戶要求這些字段時(shí),我才想加載相關(guān)視頻(甚至用戶)。 但是,由于我們已將這些字段包括在模型中,因此gqlgen會(huì)假設(shè)您在解析視頻時(shí)會(huì)提供這些值-因此當(dāng)前我們得到的是一個(gè)空結(jié)構(gòu)。
Sometimes you need a certain type of data every time, so you don’t want to load it with another query. Rather you can use something like SQL joins to improve performance. For one use-case (not included in the article), I needed video metadata every time with the video which is stored in a different place. So if I loaded it when requested, I would need another query. But as I knew my requirements (that I need it everywhere on the client side), I preferred it to load eagerly to improve the performance.
有時(shí)您每次都需要某種類型的數(shù)據(jù),因此您不想使用其他查詢來加載它。 而是可以使用諸如SQL連接之類的方法來提高性能。 對(duì)于一個(gè)用例(本文未包含),每次將視頻存儲(chǔ)在不同位置時(shí),我都需要視頻元數(shù)據(jù)。 因此,如果我在請(qǐng)求時(shí)加載了它,則需要另一個(gè)查詢。 但是,由于我知道自己的要求(在客戶端的任何地方都需要它),所以我希望它能夠熱切地加載以提高性能。
So let’s rewrite the model and regenerate the gqlgen code. For the sake of simplicity, we will only define methods for the user.
因此,讓我們重寫模型并重新生成gqlgen代碼。 為了簡單起見,我們將只為用戶定義方法。
So we have added UserID and removed User struct and regenerated the code:
因此,我們添加了UserID并刪除了User結(jié)構(gòu)并重新生成了代碼:
go run scripts/gqlgen.go -vThis will generate the following interface methods to resolve the undefined structs and you need to define those in your resolver:
這將生成以下接口方法來解析未定義的結(jié)構(gòu),您需要在解析器中定義它們:
And here is our definition:
這是我們的定義:
Now the result should look something like this:
現(xiàn)在結(jié)果應(yīng)如下所示:
So this covers the very basics of graphql and should get you started. Try a few things with graphql and the power of Golang! But before that, let’s have a look at subscription which should be included in the scope of this article.
因此,這涵蓋了graphql的基礎(chǔ)知識(shí),應(yīng)該可以幫助您入門。 嘗試使用graphql和Golang的強(qiáng)大功能! 但是在此之前,讓我們看一下應(yīng)該包含在本文范圍內(nèi)的訂閱。
訂閱內(nèi)容 (Subscriptions)
Graphql provides subscription as an operation type which allows you to subscribe to real tile data in GraphQL. gqlgen provides web socket-based real-time subscription events.
Graphql提供訂閱作為一種操作類型,使您可以訂閱GraphQL中的實(shí)際切片數(shù)據(jù)。 gqlgen提供基于Web套接字的實(shí)時(shí)訂閱事件。
You need to define your subscription in the schema.graphql file. Here we are subscribing to the video publishing event.
您需要在schema.graphql文件中定義您的訂閱。 在這里,我們正在訂閱視頻發(fā)布活動(dòng)。
Regenerate the code by running: go run scripts/gqlgen.go -v.
通過運(yùn)行以下命令來重新生成代碼: go run scripts/gqlgen.go -v 。
As explained earlier, it will make one interface in generated.go which you need to implement in your resolver. In our case, it looks like this:
如前所述,它將在generate.go中創(chuàng)建一個(gè)接口,您需要在解析器中實(shí)現(xiàn)該接口。 在我們的例子中,它看起來像這樣:
Now, you need to emit events when a new video is created. As you can see on line 23 we have done that.
現(xiàn)在,您需要在創(chuàng)建新視頻時(shí)發(fā)出事件。 如您在第23行所看到的,我們已經(jīng)做到了。
And it’s time to test the subscription:
現(xiàn)在可以測試訂閱了:
GraphQL comes with certain advantages, but everything that glitters is not gold. You need to take care of a few things like authorizations, query complexity, caching, N+1 query problem, rate limiting, and a few more issues — otherwise it will put you in performance jeopardy.
GraphQL具有某些優(yōu)勢(shì),但所有閃閃發(fā)光的東西都不是金子。 您需要注意一些事情,例如授權(quán),查詢復(fù)雜性,緩存,N + 1查詢問題,速率限制以及其他一些問題,否則將使您陷入性能危機(jī)。
階段2:高級(jí)-身份驗(yàn)證,數(shù)據(jù)加載器和查詢復(fù)雜性 (Phase 2: The advanced - Authentication, Dataloaders, and Query Complexity)
Every time I read a tutorial like this, I feel like I know everything I need to know and can get my all problems solved.
每次閱讀這樣的教程時(shí),我都會(huì)感覺自己知道需要知道的一切,并且可以解決所有問題。
But when I start working on things on my own, I usually end up getting an internal server error or never-ending requests or dead ends and I have to dig deep into that to carve my way out. Hopefully we can help prevent that here.
但是,當(dāng)我自己開始工作時(shí),通常會(huì)遇到內(nèi)部服務(wù)器錯(cuò)誤或永無休止的請(qǐng)求或死胡同,而我必須深入研究該問題以找出出路。 希望我們可以在這里幫助防止這種情況。
Let’s take a look at a few advanced concepts starting with basic authentication.
讓我們看一些從基本身份驗(yàn)證開始的高級(jí)概念。
認(rèn)證方式 (Authentication)
In a REST API, you have a sort of authentication system and some out of the box authorizations on particular endpoints. But in GraphQL, only one endpoint is exposed so you can achieve this with schema directives.You need to edit your schema.graphql as follows:
在REST API中,您具有某種身份驗(yàn)證系統(tǒng),并且在特定端點(diǎn)上具有一些現(xiàn)成的授權(quán)。 但是在GraphQL中,僅公開了一個(gè)端點(diǎn),因此您可以使用架構(gòu)指令來實(shí)現(xiàn)此目的。您需要按如下方式編輯schema.graphql:
We have created an isAuthenticated directive and now we have applied that directive to createVideo subscription. After you regenerate code you need to give a definition of the directive. Currently, directives are implemented as struct methods instead of the interface so we have to give a definition.I have updated the generated code of server.go and created a method to return graphql config for server.go as follows:
我們已經(jīng)創(chuàng)建了一個(gè)isAuthenticated指令,現(xiàn)在已經(jīng)將該指令應(yīng)用于createVideo訂閱。 重新生成代碼后,需要提供指令的定義。 當(dāng)前,指令是作為struct方法而不是接口實(shí)現(xiàn)的,因此我們必須給出一個(gè)定義。我已經(jīng)更新了server.go的生成代碼,并創(chuàng)建了一種方法來返回server.go的graphql config,如下所示:
We have read the userId from the context. Looks strange right? How was userId inserted in the context and why in context? Ok, so gqlgen only provides you the request contexts at the implementation level, so you can not read any of the HTTP request data like headers or cookies in graphql resolvers or directives. Therefore, you need to add your middleware and fetch those data and put the data in your context.
我們已經(jīng)從上下文中讀取了userId。 看起來很奇怪吧? 如何將userId插入上下文中,為什么要插入上下文中? 好的,因此gqlgen僅在實(shí)現(xiàn)級(jí)別為您提供請(qǐng)求上下文,因此您無法讀取任何HTTP請(qǐng)求數(shù)據(jù),例如graphql解析器或指令中的標(biāo)頭或cookie。 因此,您需要添加中間件并獲取這些數(shù)據(jù)并將數(shù)據(jù)放入您的上下文中。
So we need to define auth middleware to fetch auth data from the request and validate.
因此,我們需要定義身份驗(yàn)證中間件,以從請(qǐng)求中獲取身份驗(yàn)證數(shù)據(jù)并進(jìn)行驗(yàn)證。
I haven’t defined any logic there, but instead I passed the userId as authorization for demo purposes. Then chain this middleware in server.go along with the new config loading method.
我在那里沒有定義任何邏輯,但是我出于演示目的將userId作為授權(quán)傳遞。 然后將此中間件與新的配置加載方法鏈接到server.go 。
Now, the directive definition makes sense. Don’t handle unauthorized users in your middleware as it will be handled by your directive.
現(xiàn)在,指令定義變得有意義了。 不要處理中間件中未經(jīng)授權(quán)的用戶,因?yàn)樗鼘⒂赡闹噶钐幚怼?
Demo time:
演示時(shí)間:
You can even pass arguments in the schema directives like this:
您甚至可以在模式指令中傳遞參數(shù),如下所示:
directive @hasRole(role: Role!) on FIELD_DEFINITIONenum Role { ADMIN USER }數(shù)據(jù)加載器 (Dataloaders)
This all looks fancy, doesn’t it? You are loading data when needed. Clients have control of the data, there is no under-fetching and no over-fetching. But everything comes with a cost.
這一切看起來都不錯(cuò),不是嗎? 您將在需要時(shí)加載數(shù)據(jù)。 客戶端可以控制數(shù)據(jù),不會(huì)出現(xiàn)數(shù)據(jù)提取不足和過度提取的情況。 但是,一切都是有代價(jià)的。
So what’s the cost here? Let’s take a look at the logs while fetching all the videos. We have 8 video entries and there are 5 users.
那這里的費(fèi)用是多少? 在獲取所有視頻時(shí),讓我們看一下日志。 我們有8個(gè)視頻條目,有5個(gè)用戶。
query{ Videos(limit: 10){ name user{ name } }}Query: Videos : SELECT id, name, description, url, created_at, user_id FROM videos ORDER BY created_at desc limit $1 offset $2Resolver: User : SELECT id, name, email FROM users where id = $1Resolver: User : SELECT id, name, email FROM users where id = $1Resolver: User : SELECT id, name, email FROM users where id = $1Resolver: User : SELECT id, name, email FROM users where id = $1Resolver: User : SELECT id, name, email FROM users where id = $1Resolver: User : SELECT id, name, email FROM users where id = $1Resolver: User : SELECT id, name, email FROM users where id = $1Resolver: User : SELECT id, name, email FROM users where id = $1Why 9 queries (1 videos table and 8 users table)? It looks horrible. I was just about to have a heart attack when I thought about replacing our current REST API servers with this…but dataloaders came as a complete cure for it!
為什么要查詢9個(gè)(1個(gè)視頻表和8個(gè)用戶表)? 看起來太恐怖了。 當(dāng)我想到用此替換當(dāng)前的REST API服務(wù)器時(shí),我正要心臟病發(fā)作……但是數(shù)據(jù)加載器可以完全治愈它!
This is known as the N+1 problem, There will be one query to get all the data and for each data (N) there will be another database query.
這稱為N + 1問題,將有一個(gè)查詢來獲取所有數(shù)據(jù),對(duì)于每個(gè)數(shù)據(jù)(N),將有另一個(gè)數(shù)據(jù)庫查詢。
This is a very serious issue in terms of performance and resources: although these queries are parallel, they will use your resources up.
就性能和資源而言,這是一個(gè)非常嚴(yán)重的問題:盡管這些查詢是并行的,但它們會(huì)耗盡您的資源。
We will use the dataloaden library from the author of gqlgen. It is a Go- generated library. We will generate the dataloader for the user first.
我們將使用gqlgen的作者的dataloaden庫。 這是一個(gè)Go生成的庫。 我們將首先為用戶生成數(shù)據(jù)加載器。
go get github.com/vektah/dataloadendataloaden github.com/ridhamtarpara/go-graphql-demo/api.UserThis will generate a file userloader_gen.go which has methods like Fetch, LoadAll, and Prime.
這將生成一個(gè)文件userloader_gen.go ,該文件具有Fetch, userloader_gen.go和Prime等方法。
Now, we need to define the Fetch method to get the result in bulk.
現(xiàn)在,我們需要定義Fetch方法來批量獲取結(jié)果。
Here, we are waiting for 1ms for a user to load queries and we have kept a maximum batch of 100 queries. So now, instead of firing a query for each user, dataloader will wait for either 1 millisecond for 100 users before hitting the database. We need to change our user resolver logic to use dataloader instead of the previous query logic.
在這里,我們等待用戶加載查詢的時(shí)間為1毫秒,并且我們最多保留了100個(gè)查詢。 因此,現(xiàn)在,數(shù)據(jù)加載器將不再為每個(gè)用戶觸發(fā)查詢,而是會(huì)在100個(gè)用戶之前等待1毫秒,然后再命中數(shù)據(jù)庫。 我們需要更改用戶解析器邏輯以使用數(shù)據(jù)加載器,而不是先前的查詢邏輯。
After this, my logs look like this for similar data:
在此之后,我的日志如下所示:
Query: Videos : SELECT id, name, description, url, created_at, user_id FROM videos ORDER BY created_at desc limit $1 offset $2Dataloader: User : SELECT id, name, email from users WHERE id IN ($1, $2, $3, $4, $5)Now only two queries are fired, so everyone is happy. The interesting thing is that only five user keys are given to query even though 8 videos are there. So dataloader removed duplicate entries.
現(xiàn)在僅觸發(fā)兩個(gè)查詢,因此每個(gè)人都很高興。 有趣的是,即使有8個(gè)視頻,也只有五個(gè)用戶鍵可以查詢。 因此,數(shù)據(jù)加載器刪除了重復(fù)的條目。
查詢復(fù)雜度 (Query Complexity)
In GraphQL you are giving a powerful way for the client to fetch whatever they need, but this exposes you to the risk of denial of service attacks.
在GraphQL中,您為客戶端提供了一種獲取所需內(nèi)容的強(qiáng)大方法,但這使您面臨拒絕服務(wù)攻擊的風(fēng)險(xiǎn)。
Let’s understand this through an example which we’ve been referring to for this whole article.
讓我們通過一個(gè)在整篇文章中一直引用的示例來理解這一點(diǎn)。
Now we have a related field in video type which returns related videos. And each related video is of the graphql video type so they all have related videos too…and this goes on.
現(xiàn)在,我們?cè)谝曨l類型中有一個(gè)相關(guān)字段,該字段返回相關(guān)視頻。 每個(gè)相關(guān)視頻都是graphql視頻類型,因此它們也都具有相關(guān)視頻……而且這種情況還在繼續(xù)。
Consider the following query to understand the severity of the situation:
考慮以下查詢以了解情況的嚴(yán)重性:
{ Videos(limit: 10, offset: 0){ name url related(limit: 10, offset: 0){ name url related(limit: 10, offset: 0){ name url related(limit: 100, offset: 0){ name url } } } }}If I add one more subobject or increase the limit to 100, then it will be millions of videos loading in one call. Perhaps (or rather definitely) this will make your database and service unresponsive.
如果我再添加一個(gè)子對(duì)象或?qū)⑾拗圃黾拥?00,則一次調(diào)用將加載數(shù)百萬個(gè)視頻。 也許(或者絕對(duì)是肯定的)這會(huì)使您的數(shù)據(jù)庫和服務(wù)無響應(yīng)。
gqlgen provides a way to define the maximum query complexity allowed in one call. You just need to add one line (Line 5 in the following snippet) in your graphql handler and define the maximum complexity (300 in our case).
gqlgen提供了一種定義一次調(diào)用中允許的最大查詢復(fù)雜度的方法。 您只需要在graphql處理程序中添加一行(以下代碼段中的第5行),然后定義最大復(fù)雜度(本例中為300)。
gqlgen assigns fix complexity weight for each field so it will consider struct, array, and string all as equals. So for this query, complexity will be 12. But we know that nested fields weigh too much, so we need to tell gqlgen to calculate accordingly (in simple terms, use multiplication instead of just sum).
gqlgen為每個(gè)字段分配固定復(fù)雜度權(quán)重,因此它將結(jié)構(gòu),數(shù)組和字符串都視為相等。 因此,對(duì)于該查詢,復(fù)雜度將為12。但是我們知道嵌套字段的權(quán)重太大,因此我們需要告訴gqlgen進(jìn)行相應(yīng)的計(jì)算(簡單來說,請(qǐng)使用乘法而不是求和)。
Just like directives, complexity is also defined as struct, so we have changed our config method accordingly.
就像指令一樣,復(fù)雜度也定義為struct,因此我們相應(yīng)地更改了config方法。
I haven’t defined the related method logic and just returned the empty array. So related is empty in the output, but this should give you a clear idea about how to use the query complexity.
我還沒有定義相關(guān)的方法邏輯,只是返回了空數(shù)組。 因此,輸出中的related是空的,但這應(yīng)該使您對(duì)如何使用查詢復(fù)雜度有一個(gè)清晰的了解。
最后說明 (Final Notes)
This code is on Github. You can play around with it, and if you have any questions or concerns let me know in the comment section.
這段代碼在Github上 。 您可以嘗試一下,如果有任何疑問或疑慮,請(qǐng)?jiān)谠u(píng)論部分告訴我。
Thanks for reading! A few (hopefully 50) claps? are always appreciated. I write about JavaScript, the Go Language, DevOps, and Computer Science. Follow me and share this article if you like it.
謝謝閱讀! 拍手(希望有50個(gè))? 總是很感激。 我寫有關(guān)JavaScript,Go語言,DevOps和計(jì)算機(jī)科學(xué)的文章。 關(guān)注我,如果您喜歡它,請(qǐng)分享這篇文章。
Reach out to me on @Twitter @Linkedin. Visit www.ridham.me for more.
通過@ Twitter @ Linkedin與我聯(lián)系。 有關(guān)更多信息,請(qǐng)?jiān)L問www.ridham.me 。
翻譯自: https://www.freecodecamp.org/news/deep-dive-into-graphql-with-golang-d3e02a429ac3/
golang底層深入
總結(jié)
以上是生活随笔為你收集整理的golang底层深入_带有Golang的GraphQL:从基础到高级的深入研究的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 做梦梦到身边人怀孕了是什么意思
- 下一篇: pytorch深度学习_在本完整课程中学