graphql学习(四)

简介:

之前的学习,都是使用graphiql或者postman验证后台api.作为全栈工程师,这不能够啊,必须要有前端,必须的

今天学习在vue中使用graphql——vue-apollo.

使用apollo有两个选择:Apollo Boost或者Apollo Client. 这两者的区别是:Apollo Boost更傻瓜化,缺省帮我们做了很多的配置;而Apollo Client需要自己详细的配置.对于我这种二把刀的全栈工程师,还是选择Apollo Boost好了.

安装node.js什么的就不赘述了. 先安装vue cli

1. npm install -g @vue/cli
2. vue create demo

选择缺省模板创建项目就可以了.创建成功后,会有如下输出:

🎉  Successfully created project demo.
👉  Get started with the following commands:

 $ cd demo
 $ npm run serve

按照提示,我们进入demo,执行npm run serve,成功信息

 DONE  Compiled successfully in 2702ms9:47:28 AM

<s> [webpack.Progress] 100%


  App running at:
  - Local:   http://localhost:8080/
  - Network: http://10.5.92.149:8080/

  Note that the development build is not optimized.
  To create a production build, run npm run build.

浏览器里可以看到:
image
准备工作就做好了.

接下来需要增加apollo组件. 执行

npm install --save vue-apollo graphql apollo-boost graphql-tag

在继续前端之前,我们需要后端做点小修改: 因为前端后端都使用8080端口监听,所以我们修改一下后端的端口,改成监听9090.另外,还需要引入新的package "github.com/rs/cors"解决跨域的问题:

// main
func main() {
    h := Register()
    // 解决跨域的问题
    hdl := cors.Default().Handler(h)
    http.Handle("/graphql", hdl)
    fmt.Println("Now server is running on port 9090")
    http.ListenAndServe(":9090", nil)
}

还有,需要改正一个bug, models/article.go里的update()函数,要改成如下:

// Update a article
func UpdateArticle(id int, title, content string) (*Article, error) {
    for k, _ := range articleList {
        if articleList[k].ID == id {
            if title != "" {
                articleList[k].Title = title
            }
            if content != "" {
                articleList[k].Content = content
            }
            return &articleList[k], nil
        }
    }
    return nil, errors.New("Article not found")
}

继续前端的工作. 新建demo/src/utils目录,添加文件apollo.js:

import ApolloClient from 'apollo-boost';
const apolloClient = new ApolloClient({
  // 这里指向后端的地址、端口和URL
  uri: 'http://127.0.0.1:9090/graphql'
})
export default apolloClient;

新建/demo/src/graphql目录,添加文件article.js:

import gql from 'graphql-tag'
import apolloClient from '../utils/apollo'

// 文章列表
export function getArticles(params) {
 return apolloClient.query({
  query: gql `{
   articles{
    id
    title
    content
   }
  }`,
  variables: params
 })
}

// 单篇文章详情
export function getArticle(params) {
  return apolloClient.query({
    query: gql `query ($id : Int) {
      article(id: $id) {
        id
        title
        content
      }
    }`,
    variables: params
  })
}

// 添加新文章
export function createArticle(params) {
 return apolloClient.mutate({
  mutation: gql `mutation ($title: String, $content: String) {
   add(title: $title, content: $content){
    id
    title
    content
   }
  }`,
  variables: params
 })
}

// 编辑文章
export function editArticle(params) {
  return apolloClient.mutate({
   mutation: gql `mutation ($id: Int, $title: String, $content: String) {
    update(id: $id, title: $title, content: $content){
     id
     title
     content
    }
   }`,
   variables: params
  })
 }

// 删除文章
export function deleteArticle(params) {
  return apolloClient.mutate({
   mutation: gql `mutation ($id: Int) {
    delete(id: $id){
     id
     title
     content
    }
   }`,
   variables: params
  })
 }

这里比较难理解的是传入参数的解析,对照一下页面模板传入的参数,多比较就能明白了.
然后在demo/components下新建Article.vue文件,内容如下:

<template>
  <div id="article">
    <div class="list">
      <h1>{{ msg }}</h1>
      <ul>
        <li v-for="(v, k) of list" :key="k">
          文章名称: {{ v.id }}----------------({{ v.title }})
          <button @click="getArticle(v.id)">详情</button>
          <button @click="deleteArticle(v.id)">删除</button>
        </li>
      </ul>
    </div>
    <div v-if="article.id > 0">
      <div>文章id:{{ article.id }}</div>
      标题:<input v-model="article.title" type="text"><br>
      文章内容: <textarea v-model="article.content" name="" id="" cols="30" rows="10"></textarea><br>
      <button @click="editArticle">编辑</button><button @click="article={}">取消</button>
    </div>
    <div class="form">
      <h1>添加文章</h1>
      标题:<input v-model="formData.title" type="text"><br>
      文章内容: <textarea v-model="formData.content" name="" id="" cols="30" rows="10"></textarea><br>
      <button @click="createArticle">添加</button>
    </div>
  </div>
  
</template>

<script>
import { getArticles,getArticle,createArticle,deleteArticle,editArticle } from '../graphql/article'

export default {
  name: 'Article',
  props: {
    msg: String
  },
  data() {
    return {
      list: [],
      formData: {
        title: '',
        content: ''
      },
      article: {
        id: 0,
        title: '',
        content: ''
      }
    }
  },
  methods: {
    initData() {
      getArticles()
      .then(res=>{
        console.log('request success')
        this.list = res.data.articles
      })
      .catch(err=>{
        console.log(err)
      })
    },
    getArticle(id) {
      getArticle({id:id})
      .then(res =>{
        this.article = res.data.article
      })
      .catch(err =>{
        console.log(err)
      })
    },
    createArticle() {
      createArticle(this.formData)
      .then(()=>{
        this.initData()
      })
      .catch(err=>{
        console.log(err)
      })
    },
    deleteArticle(id) {
      deleteArticle({id: id})
      .then(() =>{
        this.initData()
      })
      .catch(err=>{
        console.log(err)
      })
    },
    editArticle() {
      editArticle(this.article)
      .then(() =>{
        this.initData()
      })
      .catch(err=>{
        console.log(err)
      })
    }
  },
  mounted() {
    this.initData()
  }
}
</script>

<style>

</style>

最后修改demo/App.vue:

<template>
  <div id="app">
    <!-- <img alt="Vue logo" src="./assets/logo.png">
    <HelloWorld msg="Welcome to Your Vue.js App"/> -->
    <Article msg="Article List" />
  </div>
</template>

<script>
// import HelloWorld from './components/HelloWorld.vue'
import Article from './components/Article.vue'

export default {
  name: 'App',
  components: {
    // HelloWorld
    Article
  }
}
</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>

因为页面比较丑,而且增删改后要刷新页面才会显示新的数据.就不截图展示了

目录
相关文章
|
6月前
|
SQL 前端开发 API
前端需要学GraphQL 吗?
前端需要学GraphQL 吗?
58 2
|
6月前
|
API 开发者 网络架构
从REST到GraphQL:探究GraphQL的概念与实践
RESTful API曾经是互联网应用程序的主流,但它也存在着一些限制。随着GraphQL的出现,开发者们可以更加自由地定义和查询API,提高了应用程序的灵活性和可扩展性。本文将深入探讨GraphQL的概念和实践,并介绍如何在应用程序中使用GraphQL。
39 6
|
6月前
|
前端开发 API UED
深入浅出GraphQL:理解与实践
本文将以清晰易懂的方式介绍GraphQL的概念及其实际应用。通过对比RESTful API和GraphQL的特点,阐述GraphQL在数据查询和交互方面的优势。同时,将探讨GraphQL在现代软件开发中的实际应用,并提供一些最佳实践指南。无论您是初学者还是有经验的开发者,都能从本文中获得有益的启发和指导。
|
JSON 前端开发 API
如何使用GraphQL进行前端数据交互
如何使用GraphQL进行前端数据交互
|
11月前
|
API
GraphQL
GraphQL
60 0
|
JavaScript Go
搭建GraphQL服务
搭建GraphQL服务
77 0
|
存储 Java API
大厂都在实践的GraphQL,你了解吗?
大厂都在实践的GraphQL,你了解吗?
176 0
GraphQL 是干什么的?底层原理是什么?
GraphQL 是干什么的?底层原理是什么?
398 0
|
SQL 前端开发 JavaScript
关于graphql快速入门
关于graphql快速入门
180 0
|
JSON 前端开发 NoSQL
GraphQL 从入门到实践
本文首先介绍了 GraphQL,再通过 MongoDB + graphql + graph-pack 的组合实战应用 GraphQL,详细阐述如何使用 GraphQL 来进行增删改查和数据订阅推送,并附有使用示例,边用边学印象深刻~ 如果希望将 GraphQL 应用到前后端分离的生产环境,请期待后续文章。 本文实例代码:Github 感兴趣的同学可以加文末的微信群,一起讨论吧~
GraphQL 从入门到实践