<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          GraphQL 實(shí)戰(zhàn)篇之前端Vue+后端Nest

          共 23541字,需瀏覽 48分鐘

           ·

          2021-04-28 22:01

          關(guān)注 程序員成長(zhǎng)指北,回復(fù)“1

          加入我們一起學(xué)習(xí),天天進(jìn)步


          作者:PatWu16

          https://segmentfault.com/a/1190000039087433

          這篇文章記錄使用Vue+GraphQL搭建客戶端。

          客戶端項(xiàng)目目錄結(jié)構(gòu)如下:

          安裝

          首先我們先使用vue-cli新建項(xiàng)目,接著安裝依賴:

          npm install apollo-cache-inmemory apollo-client apollo-link apollo-link-http apollo-link-ws apollo-utilities vue-apollo -S

          引入依賴

          // main.js
          import Vue from 'vue'
          import App from './App.vue'
          import { apolloProvider } from './vue-apollo';

          Vue.config.productionTip = false

          new Vue({
              render: h => h(App),
              // 像 vue-router 或 vuex 一樣注入apolloProvider 
              apolloProvider,
          }).$mount('#app')
          // vue-apollo.js
          // 相關(guān)文檔請(qǐng)查閱 https://apollo.vuejs.org/zh-cn/
          import { ApolloClient } from 'apollo-client'
          import { createHttpLink } from 'apollo-link-http'
          import { InMemoryCache } from 'apollo-cache-inmemory'
          import Vue from 'vue'
          import VueApollo from 'vue-apollo'
          // 新的引入文件
          import { split } from 'apollo-link'
          import { WebSocketLink } from 'apollo-link-ws'
          import { getMainDefinition } from 'apollo-utilities'

          Vue.use(VueApollo)

          // 與 API 的 HTTP 連接
          const httpLink = createHttpLink({ // 你需要在這里使用絕對(duì)路徑 
              uri: 'http://localhost:3001/graphql',
          })
          // 創(chuàng)建訂閱的 websocket 連接
          const wsLink = new WebSocketLink({
              uri: 'ws://localhost:3001/graphql',
              options: {
                  reconnect: true,
              }
          })
          // 使用分割連接的功能
          // 你可以根據(jù)發(fā)送的操作類型將數(shù)據(jù)發(fā)送到不同的連接
          const link = split(({ query }) => {
              const definition = getMainDefinition(query)
              return definition.kind === 'OperationDefinition' && definition.operation === 'subscription'
              },
              wsLink,
              httpLink
          )
          // 創(chuàng)建 apollo 客戶端
          const apolloClient = new ApolloClient({
              link,
              cache: new InMemoryCache(),
              connectToDevTools: true,
          })

          export const apolloProvider = new VueApollo({       
              defaultClient: apolloClient,
          })

          編寫業(yè)務(wù)代碼

          // App.vue
          <template>
           <div id="app"> <img alt="Vue logo" src="./assets/logo.png"> <HelloGraphQL /> </div></template>
          <script>
          import HelloGraphQL from './components/HelloGraphQL.vue'

          export default {
              name: 'app',
              components: {
                  HelloGraphQL
              }
          }
          </script>
          <style>
          #app {
              font-family: 'Avenir',Helvetica, Arial, sans-serif;     -webkit-font-smoothing: antialiased;
              -moz-osx-font-smoothing: grayscale; 
              text-align: center;
              color: #2c3e50;
              margin-top: 60px;
          }
          </style>
          // HelloGraphQL.vue
          <template>
              <div class="hello">
                  作者姓氏:{{author.firstName}}
                  <button @click="changeAuthor">修改作者姓氏</button>
                  <br> <br> 
                  新增標(biāo)題:{{post.title}}
                  <button @click="addPost">添加文章</button>
                  <br> 
                  訂閱成功次數(shù):{{receivedSubscriptionTimes}}
              </div>
          </template>
          <script>
          import gql from 'graphql-tag'
          export default {
              name: 'HelloGraphQL',
              data: function (){
                  return {
                      author: {},
                      post: {},
                      receivedSubscriptionTimes: 0
                  } 
              },
              apollo: {
                  // Apollo 的具體選項(xiàng)
                  author: gql`query author {
                      author(id: 2) {
                          id,
                          firstName,
                          posts {
                              id,
                              title
                          }
                      }
                  }`,
                  $subscribe: {
                      postAdded: {
                          query: gql`subscription postAdded{
                              postAdded {
                                  id, 
                                  title
                              }
                          }`, 
                          // 變更之前的結(jié)果
                          result ({ data }) {
                              // 在這里用之前的結(jié)果和新數(shù)據(jù)組合成新的結(jié)果
                              // eslint-disable-next-line         
                              console.log(data)
                              this.receivedSubscriptionTimes += 1                 }
                      }
                  }
              },
              methods: {
                  // 修改作者
                  changeAuthor() {
                      // 調(diào)用 graphql 變更
                      this.$apollo.mutate({
                          // 查詢語(yǔ)句
                          mutation: gql`mutation changeAuthor {
                              changeAuthor(id: 3, firstName: "firstName" lastName: "lastName") {
                                  id,
                                  firstName,
                                  lastName
                              }
                          }`,
                          // 參數(shù)
                          variables: {
                              firstName: '',
                          },
                      }).then(res => {
                          this.author.firstName = res.data.changeAuthor.firstName;
                      }) 
                  },
                  // 添加文章
                  addPost() {
                      // 調(diào)用 graphql 變更
                      this.$apollo.mutate({
                          // 查詢語(yǔ)句
                          mutation: gql`mutation addPost {
                              post: addPost {
                                  id,
                                  title
                              }
                          }`
                      }).then(res => {
                          this.post = res.data.post;
                      })
                  }
              }
          }
          </script>

          至此,我們便可以請(qǐng)求server端服務(wù)了!??????

          前面我們介紹了GraphQL的概念和基礎(chǔ)知識(shí),這篇文章記錄下使用Nestjs+GraphQL搭建Node服務(wù)。

          安裝

          npm i --save @nestjs/graphql graphql-tools graphql apollo-server-express

          注冊(cè)

          // app.module.ts
          import { Module } from '@nestjs/common';
          import { GraphQLModule } from '@nestjs/graphql';
          import { ConfigModule, ConfigService } from 'nestjs-config';
          @Module({
           imports: [
              ConfigModule.load(path.resolve(__dirname, 'config''**/!(*.d).{ts,js}')),
              GraphQLModule.forRootAsync({
                  imports: [ConfigModule],
                  useFactory: (config: ConfigService) => config.get('graphql'),
                  inject: [ConfigService],
              }) 
           ],})
          export class ApplicationModule {}

          // src/config/graphql.ts
          import * as path from 'path';
          export default {
            autoSchemaFile: path.join(process.cwd(), 'src/schema.gql'), // 最后生成的`Schema 文件,不可修改`
            installSubscriptionHandlers: true, // 啟用訂閱
          };

          啟動(dòng)項(xiàng)目,并訪問 http://localhost:3000/graphql,我們便可以看到graphql頁(yè)面。

          編寫服務(wù)端邏輯

          接下來我們注冊(cè)一個(gè)author模塊,目錄結(jié)構(gòu)如下:

          // author.module.ts
          import { Module } from '@nestjs/common';
          import { AuthorService } from './author.service';
          import { AuthorResolver } from './author.resolver';
          @Module({
            providers: [
              AuthorService, 
              AuthorResolver
            ]
          })
          export class AuthorModule {}
          // author.service.ts
          // 此文件用于寫數(shù)據(jù)庫(kù)查詢等邏輯,我們著重學(xué)習(xí)GraphQL的使用,故此處不做相關(guān)Demo
          import { Injectable } from '@nestjs/common';
          @Injectable()
          export class AuthorService {
            async findOneById() {}
          }
          // author.resolver.ts
          import { Args, Mutation, Query, Resolver, Subscription, ResolveField, Parent, Int } from '@nestjs/graphql';
          import { PubSub } from 'graphql-subscriptions';
          import { Author } from './models/author.model';
          import { Post } from './models/post.model';
          import { AuthorService } from './author.service';
          // import { GetAuthorArgs } from './dto/get-author.args';

          const pubSub = new PubSub();

          @Resolver(() => Author)
          export class AuthorResolver {
            constructor(
               private authorsService: AuthorService
            ) {}
           // 根據(jù)id查詢作者信息
           @Query(returns => Author, {
              name: 'author',
              description: 'get author info by id',
              nullable: false
           })
           async getAuthor(@Args('id', {
               type: () => Int,
               description: 'author id',
               nullable: false
           }) id: number): Promise<any> {
           // return this.authorsService.findOneById(id);
              return {
                  id,
                  firstName: 'wu',
                  lastName: 'pat',
              };
          }
          // 使用DTO接受參數(shù)
          // @Query(returns => Author)
          // async getAuthor(@Args() args: GetAuthorArgs) {
          //   return this.authorsService.findOneById(args);
          // }
           // 修改作者信息
           @Mutation(returns => Author, {
              name: 'changeAuthor',
              description: 'change author info by id',
              nullable: false
           })
           async changeAuthor(
              @Args('id') id: number,
              @Args('firstName') firstName: string,
              @Args('lastName') lastName: string,
           ): Promise<any> {
           // return this.authorsService.findOneById(id);
           return {
              id,
              firstName,
              lastName,
            };
          }

           // 解析posts字段
           @ResolveField()
           async posts(@Parent() author: Author): Promise<any> {
               const { id } = author;
               // return this.postsService.findAll({ authorId: id });
               return [{
                  id: 4,
                  title: 'hello',
                  votes: 2412,
               }];
           }
           
           // 新增文章
           @Mutation(returns => Post)
           async addPost() {
               const newPost = {
                  id: 1,
                  title: '新增文章'
               };
               // 新增成功后,通知更新
               await pubSub.publish('postAdded', { postAdded: newPost });
               return newPost;
           }
           
           // 監(jiān)聽變更
           @Subscription(returns => Post, {
               name: 'postAdded',
               // filter: (payload, variables) => payload.postAdded.title === variables.title,
               // 過濾訂閱
               // resolve(this: AuthorResolver, value) { // 修改payload參數(shù)
               //   return value;
               // } })
           async postAdded(/*@Args('title') title: string*/) {
              return (await pubSub.asyncIterator('postAdded'));
           }}
          // author.model.ts
          import { Field, Int, ObjectType } from '@nestjs/graphql';
          import { Post } from './post.model';

          @ObjectType({ description: 'Author model' })
          export class Author {
           @Field(type => Int, {
              description: '作者id'
           })
           id: number;
           
           @Field({
              nullable: true,
              description: '作者姓姓氏'
           })
           firstName?: string;
           
           @Field({ 
              nullable: true,
              description: '作者姓名字'
           })
           lastName?: string;
           
           // 要聲明數(shù)組的項(xiàng)(而不是數(shù)組本身)是可為空的,請(qǐng)將nullable屬性設(shè)置'items'
           // 如果數(shù)組及其項(xiàng)都是可空的,則設(shè)置nullable為'itemsAndList' 
           @Field(type => [Post], {
              nullable: 'items',
              description: '作者發(fā)表的文章'
           })
           posts: Post[];
          }
          // posts.model.ts
          import { Field, Int, ObjectType } from '@nestjs/graphql';

          @ObjectType()
          export class Post {

           @Field(type => Int)
           id: number;
           
           @Field() title: string;
           
           @Field(type => Int, {
              nullable: true
           })
           votes?: number;
          }

          上面的代碼包含了查詢、變更、訂閱類型,此時(shí)我們會(huì)發(fā)現(xiàn)src下面新增了一個(gè)文件schema.gql,這個(gè)文件就是自動(dòng)生成的類型文件:

          # ------------------------------------------------------
          # THIS FILE WAS AUTOMATICALLY GENERATED (DO NOT MODIFY)
          # ------------------------------------------------------
          type Post {
              id: Int!
              title: String!
              votes: Int
          }

          """Author model"""
          type Author {
              """作者id"""
              id: Int!
              
              """作者姓姓氏"""
              firstName: String
              
              """作者姓名字"""
              lastName: String
              
              """作者發(fā)表的文章"""
              posts: [Post]!
          }

          type Query {
              """get author info by id"""
              author(
                  """author id"""
                  id: Int!
              ): Author!
          }

          type Mutation {
              """change author info by id""" 
              changeAuthor(lastName: String!, firstName: String!, id: Float!): Author!
              addPost: Post!
          }

          type Subscription {
              postAdded: Post!
          }

          執(zhí)行查詢

          這時(shí)我們的服務(wù)已經(jīng)運(yùn)行起來,可以執(zhí)行查詢了。

          # 左下角編寫QUERY VARIABLES
          {
              "id": 1
          }
          # Write your query or mutation here
          # 查詢作者信息
          query author($id: Int!) {
              alias: author(id: $id) {
                  id,
                  firstName,
                  posts {
                      id,
                      title
                  }
              }
          }

          # 修改作者信息
          mutation changeAuthor {
              changeAuthor(id: 3, firstName: "firstName" lastName: "lastName") {
                  id,
                  firstName,
                  lastName
              }
          }

          # 發(fā)布文章
          mutation addPost {
              post: addPost {
                  id,
                  title
              }
          }

          # 訂閱文章新增
          subscription postAdded{
              postAdded {
                  id,
                  title
              }
          }

          // 自省查詢
          query schema{
              __schema {
                  types { 
                      name
                  }
              }
          }

          至此,我們的Nestjs+GraphQL服務(wù)便搭建完成,給自己一個(gè)??!

          如果覺得這篇文章還不錯(cuò)
          點(diǎn)擊下面卡片關(guān)注我
          來個(gè)【分享、點(diǎn)贊、在看】三連支持一下吧

             “分享、點(diǎn)贊、在看” 支持一波  

          瀏覽 51
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  色播五月天 | 99视频免费观看 | TS人妖另类精品视频系列 | 成人网站视频免费在线观看 | 无码内射在线视频 |