<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??一站式輕松地調用各大LLM模型接口,支持GPT4、智譜、豆包、星火、月之暗面及文生圖、文生視頻 廣告
                # GraphQL > 原文:[https://docs.gitlab.com/ee/development/fe_guide/graphql.html](https://docs.gitlab.com/ee/development/fe_guide/graphql.html) * [Getting Started](#getting-started) * [Helpful Resources](#helpful-resources) * [Libraries](#libraries) * [Tooling](#tooling) * [Apollo GraphQL VS Code extension](#apollo-graphql-vs-code-extension) * [Exploring the GraphQL API](#exploring-the-graphql-api) * [Apollo Client](#apollo-client) * [GraphQL Queries](#graphql-queries) * [Fragments](#fragments) * [Usage in Vue](#usage-in-vue) * [Local state with Apollo](#local-state-with-apollo) * [Mocking API response with local Apollo cache](#mocking-api-response-with-local-apollo-cache) * [Using with Vuex](#using-with-vuex) * [Feature flags in queries](#feature-flags-in-queries) * [Manually triggering queries](#manually-triggering-queries) * [Working with pagination](#working-with-pagination) * [Using `fetchMore` method in components](#using-fetchmore-method-in-components) * [Testing](#testing) * [Mocking response as component data](#mocking-response-as-component-data) * [Testing loading state](#testing-loading-state) * [Testing Apollo components](#testing-apollo-components) * [Handling errors](#handling-errors) * [Top-level errors](#top-level-errors) * [Handling top-level errors](#handling-top-level-errors) * [Errors-as-data](#errors-as-data) * [Handling errors-as-data](#handling-errors-as-data) * [Usage outside of Vue](#usage-outside-of-vue) # GraphQL[](#graphql "Permalink") ## Getting Started[](#getting-started "Permalink") ### Helpful Resources[](#helpful-resources "Permalink") **一般資源**: * [?? Official Introduction to GraphQL](https://s0graphql0org.icopy.site/learn/) * [?? Official Introduction to Apollo](https://www.apollographql.com/docs/tutorial/introduction/) **GitLab 上的 GraphQL**: * [?? GitLab Unfiltered GraphQL playlist](https://www.youtube.com/watch?v=wHPKZBDMfxE&list=PL05JrBw4t0KpcjeHjaRMB7IGB2oDWyJzv) * [GitLab 上的 GraphQL:深潛](../api_graphql_styleguide.html#deep-dive) (視頻)作者 Nick Thomas * GitLab 上 GraphQL 的歷史概述(不是特定于前端的) * [使用 GraphQL 和 Vue Apollo 進行 GitLab 功能演練](https://www.youtube.com/watch?v=6yYp2zB7FrM) (視頻),作者 Natalia Tepluhina * 使用 GraphQL 在 GitLab 中實現前端功能的真實示例 * [GitLab 上的客戶端 GraphQL 的歷史](https://www.youtube.com/watch?v=mCKRJxvMnf0) (視頻)Illya Klymov 和 Natalia Tepluhina * Natalia Tepluhina [從 Vuex 到 Apollo](https://www.youtube.com/watch?v=9knwu87IfU8) (視頻) * 關于何時阿波羅可能比 Vuex 更好的選擇以及如何進行過渡的有用概述 * [?? Vuex -> Apollo Migration: a proof-of-concept project](https://gitlab.com/ntepluhina/vuex-to-apollo/blob/master/README.md) * 一系列示例展示了使用 Vue + GraphQL +(Vuex 或 Apollo)應用進行狀態管理的可能方法 ### Libraries[](#libraries "Permalink") 當使用 GraphQL 進行前端開發時,我們使用[Apollo](https://www.apollographql.com/) (特別是[Apollo Client](https://www.apollographql.com/docs/react/) )和[Vue Apollo](https://github.com/vuejs/vue-apollo) . 如果在 Vue 應用程序中使用 GraphQL,則" Vue 中的[用法"](#usage-in-vue)部分可以幫助您學習如何集成 Vue Apollo. 對于其他用例,請查看[Vue 外部](#usage-outside-of-vue)的[用法](#usage-outside-of-vue)部分. ### Tooling[](#tooling "Permalink") * [Apollo Client Devtools](https://github.com/apollographql/apollo-client-devtools) #### [Apollo GraphQL VS Code extension](https://marketplace.visualstudio.com/items?itemName=apollographql.vscode-apollo)[](#apollo-graphql-vs-code-extension "Permalink") 如果使用 VS Code,則 Apollo GraphQL 擴展名支持`.graphql`文件中的自動完成. 若要設置 GraphQL 擴展,請按照下列步驟操作: 1. 將`apollo.config.js`文件添加到`gitlab`本地目錄的根目錄中. 2. 用以下內容填充文件: ``` module.exports = { client: { includes: ['./app/assets/javascripts/**/*.graphql', './ee/app/assets/javascripts/**/*.graphql'], service: { name: 'GitLab', localSchemaFile: './doc/api/graphql/reference/gitlab_schema.graphql', }, }, }; ``` 3. 重新啟動 VS Code. ### Exploring the GraphQL API[](#exploring-the-graphql-api "Permalink") 我們 GraphQL API 可以通過 GraphiQL 在您的實例的探索`/-/graphql-explorer`或[GitLab.com](https://gitlab.com/-/graphql-explorer) . 如有需要,請查閱《 [GitLab GraphQL API 參考》文檔](../../api/graphql/reference) . 您可以在 GraphiQL 的**文檔瀏覽器**的右側檢查所有現有的查詢和變異. 也可以直接在左選項卡上編寫查詢和變異,然后單擊左上角的**執行查詢**按鈕來檢查其執行情況: [![GraphiQL interface](https://img.kancloud.cn/36/9f/369fd46a4e971599eae8ef53240e6594_2872x1600.png)](img/graphiql_explorer_v12_4.png) ## Apollo Client[](#apollo-client "Permalink") 為了保存在不同的應用程序中創建的重復客戶端,我們使用[默認客戶端](https://gitlab.com/gitlab-org/gitlab/blob/master/app/assets/javascripts/lib/graphql.js) . 這將使用正確的 URL 設置 Apollo 客戶端,并設置 CSRF 標頭. 默認客戶端接受兩個參數: `resolvers`和`config` . * 創建`resolvers`參數以接受用于[本地狀態管理](#local-state-with-apollo)查詢和突變的 resolvers 對象 * `config`參數采用配置設置的對象: * `cacheConfig`字段接受設置的可選對象以[自定義 Apollo 緩存](https://www.apollographql.com/docs/react/caching/cache-configuration/#configuring-the-cache) * `baseUrl`允許我們傳遞與主端點不同的 GraphQL 端點的 URL(即`${gon.relative_url_root}/api/graphql` ) * `assumeImmutableResults` (默認設置為`false` )-此設置為`true` ,將假定更新 Apollo Cache 時的每個操作都是不可變的. 它還將`freezeResults`設置為`true` ,因此任何嘗試`freezeResults` Apollo Cache 的嘗試都會在開發環境中引發控制臺警告. 在將此選項設置為`true`之前,請確保在緩存更新操作中遵循不變性模式. ## GraphQL Queries[](#graphql-queries "Permalink") 為了在運行時保存查詢編譯,webpack 可以直接導入`.graphql`文件. 這使 webpack 可以在編譯時對查詢進行預處理,而不是由客戶端進行查詢的編譯. 為了將查詢與突變和片段區分開來,建議使用以下命名約定: * `all_users.query.graphql`用于查詢; * `add_user.mutation.graphql`進行突變; * 片段的`basic_user.fragment.graphql` . ### Fragments[](#fragments "Permalink") [片段](https://s0graphql0org.icopy.site/learn/queries/)是使復雜的 GraphQL 查詢更具可讀性和可重用性的一種方式. 這是 GraphQL 片段的示例: ``` fragment DesignListItem on Design { id image event filename notesCount } ``` 片段可以存儲在單獨的文件中,可以導入并用于查詢,突變或其他片段. ``` #import "./design_list.fragment.graphql" #import "./diff_refs.fragment.graphql" fragment DesignItem on Design { ...DesignListItem fullPath diffRefs { ...DesignDiffRefs } } ``` 有關片段的更多信息: [GraphQL Docs](https://s0graphql0org.icopy.site/learn/queries/) ## Usage in Vue[](#usage-in-vue "Permalink") 要使用 Vue Apollo,請導入[Vue Apollo](https://github.com/vuejs/vue-apollo)插件以及默認客戶端. 這應該在安裝 Vue 應用程序的同一時間創建. ``` import Vue from 'vue'; import VueApollo from 'vue-apollo'; import createDefaultClient from '~/lib/graphql'; Vue.use(VueApollo); const apolloProvider = new VueApollo({ defaultClient: createDefaultClient(), }); new Vue({ ..., apolloProvider, ... }); ``` 在[Vue Apollo 文檔中](https://vue-apollo.netlify.app/guide/)閱讀有關[Vue Apollo 的](https://github.com/vuejs/vue-apollo)更多信息. ### Local state with Apollo[](#local-state-with-apollo "Permalink") 創建默認客戶端時,可以通過傳入 resolvers 對象來使用 Apollo 管理應用程序狀態. 設置默認客戶端后,可以通過寫入緩存來設置默認狀態. ``` import Vue from 'vue'; import VueApollo from 'vue-apollo'; import createDefaultClient from '~/lib/graphql'; Vue.use(VueApollo); const defaultClient = createDefaultClient({ resolvers: {} }); defaultClient.cache.writeData({ data: { user: { name: 'John', surname: 'Doe', age: 30 }, }, }); const apolloProvider = new VueApollo({ defaultClient, }); ``` 我們可以使用`@client` Apollo 指令查詢本地數據: ``` // user.query.graphql query User { user @client { name surname age } } ``` 除了創建本地數據,我們還可以使用`@client`字段擴展現有的 GraphQL 類型. 當我們需要為尚未添加到 GraphQL API 中的字段模擬 API 響應時,這非常有用. #### Mocking API response with local Apollo cache[](#mocking-api-response-with-local-apollo-cache "Permalink") 當我們需要在本地模擬某些 GraphQL API 響應,查詢或變異時(例如,當它們仍未添加到我們的實際 API 中時),使用本地 Apollo 緩存非常方便. 例如,我們在查詢中使用了有關`DesignVersion`的[片段](#fragments) : ``` fragment VersionListItem on DesignVersion { id sha } ``` 我們還需要獲取版本作者和'created at'屬性,以在版本下拉列表中顯示它們,但這些更改仍未在我們的 API 中實現. 我們可以更改現有片段,以針對這些新字段獲得模擬的響應: ``` fragment VersionListItem on DesignVersion { id sha author @client { avatarUrl name } createdAt @client } ``` 現在,Apollo 將嘗試為每個標有`@client`指令的字段查找*解析器* . 讓我們為`DesignVersion`類型創建一個解析器(為什么要使用`DesignVersion` ?,因為我們的片段是在這種類型上創建的). ``` // resolvers.js const resolvers = { DesignVersion: { author: () => ({ avatarUrl: 'https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon', name: 'Administrator', __typename: 'User', }), createdAt: () => '2019-11-13T16:08:11Z', }, }; export default resolvers; ``` 我們需要將解析器對象傳遞給我們現有的 Apollo Client: ``` // graphql.js import createDefaultClient from '~/lib/graphql'; import resolvers from './graphql/resolvers'; const defaultClient = createDefaultClient( {}, resolvers, ); ``` 現在,每次嘗試獲取版本時,我們的客戶端都會從遠程 API 端點獲取`id`和`sha` ,并將我們的硬編碼值分配給`author`和`createdAt`版本屬性. 有了這些數據,前端開發人員就可以在 UI 部件上工作,而不會被后端阻塞. 將實際響應添加到 API 后,可以快速刪除自定義本地解析器,并且對查詢/片段的唯一更改是`@client`指令刪除. 在[Vue Apollo 文檔中](https://vue-apollo.netlify.app/guide/local-state.html#local-state)閱讀有關使用 Apollo 進行本地狀態管理的更多信息. ### Using with Vuex[](#using-with-vuex "Permalink") When Apollo Client is used within Vuex and fetched data is stored in the Vuex store, there is no need in keeping Apollo Client cache enabled. Otherwise we would have data from the API stored in two places - Vuex store and Apollo Client cache. More to say, with Apollo’s default settings, a subsequent fetch from the GraphQL API could result in fetching data from Apollo cache (in the case where we have the same query and variables). To prevent this behavior, we need to disable Apollo Client cache passing a valid `fetchPolicy` option to its constructor: ``` import fetchPolicies from '~/graphql_shared/fetch_policy_constants'; export const gqClient = createGqClient( {}, { fetchPolicy: fetchPolicies.NO_CACHE, }, ); ``` ### Feature flags in queries[](#feature-flags-in-queries "Permalink") 有時在 GraphQL 查詢中的功能標志后面放置一個實體可能會很有用. 例如,當處理后端已經合并但前端沒有合并的功能時,您可能希望將 GraphQL 實體放在功能標記后面,以允許創建和合并較小的合并請求. 為此, `if`語句通過,我們可以使用`@include`指令排除實體. ``` query getAuthorData($authorNameEnabled: Boolean = false) { username name @include(if: $authorNameEnabled) } ``` 然后,在對查詢的 Vue(或 JavaScript)調用中,我們可以傳遞功能標記. 此功能標志將需要已經正確設置. 有關正確方法,請參閱[功能部件標志文檔](../feature_flags/development.html) . ``` export default { apollo: { user: { query: QUERY_IMPORT, variables() { return { authorNameEnabled: gon?.features?.authorNameEnabled, }; }, } }, }; ``` ### Manually triggering queries[](#manually-triggering-queries "Permalink") 創建組件時,將自動對組件的`apollo`屬性進行查詢. 某些組件反而希望按需發出網絡請求,例如,帶有延遲加載項的下拉列表. 有兩種方法可以做到這一點: 1. Use the `skip` property ``` export default { apollo: { user: { query: QUERY_IMPORT, skip() { // only make the query when dropdown is open return !this.isOpen; }, } }, }; ``` 1. Using `addSmartQuery` 您可以在您的方法中手動創建智能查詢. ``` handleClick() { this.$apollo.addSmartQuery('user', { // this takes the same values as you'd have in the `apollo` section query: QUERY_IMPORT, }), }; ``` ### Working with pagination[](#working-with-pagination "Permalink") GitLab 的 GraphQL API 對連接類型使用[中繼樣式的游標分頁](https://www.apollographql.com/docs/react/data/pagination/#cursor-based) . 這意味著使用"游標"來跟蹤應從中提取下一項的數據集中的位置. [GraphQL Ruby Connection Concepts](https://graphql-ruby.org/pagination/connection_concepts.html)是對連接的良好概述和介紹. 每個連接類型(例如`DesignConnection`和`DiscussionConnection` )都有一個字段`pageInfo` ,其中包含分頁所需的信息: ``` pageInfo { endCursor hasNextPage hasPreviousPage startCursor } ``` Here: * `startCursor`和`endCursor`顯示第一項和最后一項的光標. * `hasPreviousPage`和`hasNextPage`允許我們檢查當前頁面之前或之后是否還有更多頁面可用. 當我們以連接類型獲取數據時,我們可以`before`參數的`after`或`before`傳遞游標,以指示分頁的起點或終點. 應該分別在它們的后跟`first`或`last`參數,以指示我們要在給定端點之后或之前獲取*多少個*項目. 例如,這里我們在光標之后獲取 10 個設計: ``` query { project(fullPath: "root/my-project") { id issue(iid: "42") { designCollection { designs(atVersion: null, after: "Ihwffmde0i", first: 10) { edges { node { id } } } } } } } ``` #### Using `fetchMore` method in components[](#using-fetchmore-method-in-components "Permalink") 進行初始抓取時,我們通常希望從頭開始進行分頁. 在這種情況下,我們可以: * 跳過傳遞光標. * 將`null`明確傳遞給`after` . 提取數據后,我們應該保存一個`pageInfo`對象. 假設我們將其存儲到 Vue 組件`data` : ``` data() { return { pageInfo: null, } }, apollo: { designs: { query: projectQuery, variables() { return { // rest of design variables ... first: 10, }; }, result(res) { this.pageInfo = res.data?.project?.issue?.designCollection?.designs?.pageInfo; }, }, }, ``` 當我們想移至下一頁時,我們使用 Apollo `fetchMore`方法,在該方法中傳遞一個新的游標(以及可選的新變量). 在`updateQuery`掛鉤中,我們必須在獲取下一頁之后返回要在 Apollo 緩存中看到的結果. ``` fetchNextPage() { // as a first step, we're checking if we have more pages to move forward if (this.pageInfo?.hasNextPage) { this.$apollo.queries.designs.fetchMore({ variables: { // rest of design variables ... first: 10, after: this.pageInfo?.endCursor, }, updateQuery(previousResult, { fetchMoreResult }) { // here we can implement the logic of adding new designs to fetched one (for example, if we use infinite scroll) // or replacing old result with the new one if we use numbered pages const newDesigns = fetchMoreResult.project.issue.designCollection.designs; previousResult.project.issue.designCollection.designs.push(...newDesigns) return previousResult; }, }); } } ``` 請注意,我們不必再保存`pageInfo`了; `fetchMore`觸發查詢`result`掛鉤. ### Testing[](#testing "Permalink") #### Mocking response as component data[](#mocking-response-as-component-data "Permalink") 使用[Vue 測試工具](https://vue-test-utils.vuejs.org/) ,可以輕松快速地測試獲取 GraphQL 查詢的組件. 最簡單的方法是使用`shallowMount` ,然后在組件上設置數據 ``` it('tests apollo component', () => { const vm = shallowMount(App); vm.setData({ ...mock data }); }); ``` #### Testing loading state[](#testing-loading-state "Permalink") 如果需要測試當 GraphQL API 的結果仍在加載時組件的呈現方式,我們可以將加載狀態模擬到相應的 Apollo 查詢/突變中: ``` function createComponent({ loading = false, } = {}) { const $apollo = { queries: { designs: { loading, }, }; wrapper = shallowMount(Index, { sync: false, mocks: { $apollo } }); } it('renders loading icon', () => { createComponent({ loading: true }); expect(wrapper.element).toMatchSnapshot(); }) ``` #### Testing Apollo components[](#testing-apollo-components "Permalink") 如果我們在組件中使用`ApolloQuery`或`ApolloMutation` ,為了測試其功能,我們需要先添加一個存根: ``` import { ApolloMutation } from 'vue-apollo'; function createComponent(props = {}) { wrapper = shallowMount(MyComponent, { sync: false, propsData: { ...props, }, stubs: { ApolloMutation, }, }); } ``` `ApolloMutation`組件通過作用域插槽公開了`mutate`方法. 如果要測試此方法,則需要將其添加到模擬中: ``` const mutate = jest.fn().mockResolvedValue(); const $apollo = { mutate, }; function createComponent(props = {}) { wrapper = shallowMount(MyComponent, { sync: false, propsData: { ...props, }, stubs: { ApolloMutation, }, mocks: { $apollo: } }); } ``` 然后我們可以檢查是否使用正確的變量調用了`mutate` : ``` const mutationVariables = { mutation: createNoteMutation, update: expect.anything(), variables: { input: { noteableId: 'noteable-id', body: 'test', discussionId: '0', }, }, }; it('calls mutation on submitting form ', () => { createComponent() findReplyForm().vm.$emit('submitForm'); expect(mutate).toHaveBeenCalledWith(mutationVariables); }); ``` ## Handling errors[](#handling-errors "Permalink") 目前,GitLab 的 GraphQL 突變具有兩種不同的錯誤模式: [頂級](#top-level-errors)和[數據錯誤](#errors-as-data) . 利用 GraphQL 突變時,我們必須考慮處理**這兩種錯誤模式,**以確保用戶在發生錯誤時能夠收到適當的反饋. ### Top-level errors[](#top-level-errors "Permalink") 這些錯誤位于 GraphQL 響應的"頂級". 這些是不可恢復的錯誤,包括參數錯誤和語法錯誤,因此不應直接呈現給用戶. #### Handling top-level errors[](#handling-top-level-errors "Permalink") Apollo 意識到頂級錯誤,因此我們能夠利用 Apollo 的各種錯誤處理機制來處理這些錯誤(例如,在調用[`mutate`](https://www.apollographql.com/docs/react/api/apollo-client/#ApolloClient.mutate)方法之后處理 Promise 拒絕,或處理從[`ApolloMutation`](https://apollo.vuejs.org/api/apollo-mutation.html#events)組件發出的`error`事件). 由于這些錯誤不是針對用戶的,因此應在客戶端定義頂級錯誤的錯誤消息. ### Errors-as-data[](#errors-as-data "Permalink") 這些錯誤嵌套在 GraphQL 響應的`data`對象中. 這些是可恢復的錯誤,理想情況下,可以直接向用戶顯示. #### Handling errors-as-data[](#handling-errors-as-data "Permalink") 首先,我們必須向我們的變異對象添加`errors` : ``` mutation createNoteMutation($input: String!) { createNoteMutation(input: $input) { note { id + errors } } ``` 現在,當我們提交此突變并發生錯誤時,響應中將包含`errors`供我們處理: ``` { data: { mutationName: { errors: ["Sorry, we were not able to update the note."] } } } ``` 處理數據錯誤時,請根據您的最佳判斷來確定是將錯誤消息顯示在響應中,還是將另一條客戶端定義的消息顯示給用戶. ## Usage outside of Vue[](#usage-outside-of-vue "Permalink") 通過直接導入默認客戶端并將其與查詢一起使用,還可以在 Vue 之外使用 GraphQL. ``` import createDefaultClient from '~/lib/graphql'; import query from './query.graphql'; const defaultClient = createDefaultClient(); defaultClient.query({ query }) .then(result => console.log(result)); ``` [使用 Vuex 時](#Using-with-Vuex) ,在以下情況下禁用緩存: * 數據正在其他地方緩存 * 如果數據正在其他地方緩存,或者對于給定的用例完全不需要,則用例不需要緩存. ``` import createDefaultClient from '~/lib/graphql'; import fetchPolicies from '~/graphql_shared/fetch_policy_constants'; const defaultClient = createDefaultClient( {}, { fetchPolicy: fetchPolicies.NO_CACHE, }, ); ```
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看