GraphQL在现代Web应用中的应用与优势

GraphQL是一种现代的API查询语言,它在现代Web应用中得到了广泛的应用,因为它提供了一种高效、灵活且强大的方式来获取数据

GraphQL基础快速应用示例:

1. 后端设置(使用graphql-yoga)

首先,我们需要创建一个GraphQL服务器。安装graphql-yoga并创建一个简单的GraphQL schema:

npm init -y
npm install graphql yoga graphql-yoga# server.js
const { GraphQLServer } = require('graphql-yoga');const typeDefs = `type Query {hello: String}type Mutation {addMessage(message: String!): String}
`;const resolvers = {Query: {hello: () => 'Hello world!',},Mutation: {addMessage: (_, { message }) => `You added the message "${message}"`,},
};const server = new GraphQLServer({ typeDefs, resolvers });
server.start(() => console.log(`Server is running on http://localhost:4000`));
2. 前端设置(使用Apollo Client)

接着,我们需要在前端应用中配置Apollo Client,与我们的GraphQL服务器通信:

npm install apollo-boost @apollo/client graphql# client.js
import ApolloClient from 'apollo-boost';
import { InMemoryCache } from '@apollo/client';const client = new ApolloClient({uri: 'http://localhost:4000/graphql',cache: new InMemoryCache(),
});export default client;
3. 编写前端组件

现在,我们在React组件中使用Apollo Client执行查询和变更:

// App.js
import React from 'react';
import { gql, useQuery, useMutation } from '@apollo/client';
import client from './client';const GET_HELLO = gql`query GetHello {hello}
`;const ADD_MESSAGE_MUTATION = gql`mutation AddMessage($message: String!) {addMessage(message: $message)}
`;function App() {const { loading, error, data } = useQuery(GET_HELLO);const [addMessage, { data: mutationData }] = useMutation(ADD_MESSAGE_MUTATION);if (loading) return <p>Loading...</p>;if (error) return <p>Error :(</p>;return (<div><h1>{data.hello}</h1><button onClick={() => addMessage({ variables: { message: 'Hello from frontend!' } })}>Add Message</button>{mutationData && <p>New message: {mutationData.addMessage}</p>}</div>);
}
export default App;

我们创建了一个GET_HELLO查询来获取服务器的问候语,并在页面上显示。同时,我们定义了一个ADD_MESSAGE_MUTATION变更操作,当用户点击按钮时,它将向服务器发送一个新消息。

4. 运行应用

启动后端服务器:

node server.js

然后启动前端应用,假设使用Create React App:

npm start

GraphQL基本查询

1. 查询语言:查询、突变、订阅

在GraphQL中,查询和突变是通过JSON-like结构表示的字符串。这里有一个简单的示例:

# 查询示例
query GetUser {user(id: 1) {nameemail}
}# 突变示例
mutation CreateUser {createUser(name: "Alice", email: "alice@example.com") {idname}
}# 订阅示例(假设使用WebSocket)
subscription OnNewUser {newUser {idname}
}

在上述代码中,GetUser查询请求了用户ID为1的用户姓名和电子邮件。CreateUser突变创建了一个新用户并返回新用户的ID和姓名。OnNewUser订阅等待新用户被创建时触发,返回新用户的信息。

2. 类型系统

在后端,我们定义GraphQL schema来描述这些类型:

type User {id: ID!name: String!email: String!
}type Mutation {createUser(name: String!, email: String!): User
}type Subscription {newUser: User
}

这里定义了一个User对象类型,一个Mutation类型用于突变操作,和一个Subscription类型用于订阅操作。

3. 查询结构:字段和参数

查询结构由字段和参数组成。在上面的查询示例中,user是字段,id和email是user字段的子字段。参数如id: 1用于定制查询。

4. 层次结构和嵌套

GraphQL查询可以嵌套,以下是一个更复杂的例子:

query GetUsersAndPosts {users {idnameposts {idtitlecontentauthor {idname}}}
}

此查询请求所有用户及其各自的帖子,帖子还包含了作者的信息。层次结构允许一次请求获取多个级别的数据。

客户端代码示例(使用Apollo Client)
import { gql, useQuery } from '@apollo/client';const GET_USERS_AND_POSTS = gql`query GetUsersAndPosts {users {idnameposts {idtitlecontentauthor {idname}}}}
`;function App() {const { loading, error, data } = useQuery(GET_USERS_AND_POSTS);if (loading) return <p>Loading...</p>;if (error) return <p>Error :-(</p>;return (<div>{data.users.map(user => (<div key={user.id}><h2>{user.name}</h2><ul>{user.posts.map(post => (<li key={post.id}><h3>{post.title}</h3><p>{post.content}</p><p>Author: {post.author.name}</p></li>))}</ul></div>))}</div>);
}export default App;

在这个React组件中,我们使用useQuery从GraphQL服务器获取数据,并渲染用户和他们的帖子信息。这就是GraphQL查询、类型系统和层次结构在实际应用中的体现。

GraphQL Schema

GraphQL Schema Definition Language(SDL)是一种用于描述GraphQL schema的语言,它以简洁的人类可读格式定义了数据类型、查询、突变和指令等。

定义类型
首先,我们定义一些基本的数据类型。比如,定义一个User类型和一个Post类型。

type User {id: ID!username: String!email: String!posts: [Post!]!
}type Post {id: ID!title: String!content: String!author: User!
}

这里,User类型有id、username、email字段,以及一个关联到多个Post的posts字段。而Post类型包含id、title、content字段,还有一个指向User的author字段。

查询根和突变根
接下来,定义GraphQL的查询根(Query)和突变根(Mutation)类型,它们是客户端请求数据和修改数据的入口点。

type Query {user(id: ID!): UserallUsers: [User!]!post(id: ID!): PostallPosts: [Post!]!
}type Mutation {createUser(username: String!, email: String!): UsercreatePost(title: String!, content: String!, userId: ID!): Post
}

在Query类型中,我们定义了获取单个用户、所有用户、单篇帖子和所有帖子的查询。而在Mutation类型中,我们定义了创建新用户和新帖子的操作。

Directives的理解和使用
Directives是GraphQL schema中用于改变执行行为的指令。它们可以被应用到类型系统定义的任何部分,比如字段、输入类型、对象类型等。下面展示如何使用一个自定义的@auth指令来控制访问权限。

首先,假设我们定义了一个@auth指令,用于限制对某些字段的访问,要求用户必须登录。

scalar DateTimedirective @auth(requires: Role = ADMIN) on FIELD_DEFINITIONenum Role {ADMINUSER
}

接着,在schema中应用这个指令:

type Query {me: User @auth(requires: USER)
}type User {id: ID!username: String!email: String! @auth(requires: ADMIN)posts: [Post!]!
}

在上面的例子中,me查询和username字段无需特殊权限即可访问,但访问用户的email字段则需要管理员权限(通过@auth(requires: ADMIN)指令指定)。

GraphQL 高级应用

1. 分页

使用GraphQL Cursor-based分页,以提高性能和用户体验。

Schema定义:

type PageInfo {hasNextPage: Boolean!hasPreviousPage: Boolean!startCursor: StringendCursor: String
}extend type Query {users(first: Int, after: String, last: Int, before: String): [User!]!usersConnection(first: Int, after: String, last: Int, before: String): UserConnection!
}type UserConnection {edges: [UserEdge!]!pageInfo: PageInfo!
}type UserEdge {cursor: String!node: User!
}

Resolver示例:

const resolvers = {Query: {users: (parent, args, context, info) => {// 实现逻辑,根据args.first, args.after等参数进行分页查询},usersConnection: (parent, args, context, info) => {// 实现逻辑,返回带有分页信息的UserConnection对象},},
};
2. 错误处理

自定义错误处理,提升客户端对错误的处理能力。

Resolver示例:

const resolvers = {Mutation: {createUser: async (parent, args, context, info) => {try {// 创建用户逻辑} catch (error) {throw new Error("Failed to create user", { extensions: { code: "USER_CREATION_FAILED" } });}},},
};
3. 自定义指令

创建自定义指令以实现特定业务逻辑或安全需求。

Schema定义:

directive @log on FIELD_DEFINITION
Resolver示例:javascript
const directiveResolvers = {log: (next, source, args, context, info) => {console.log(`Executing field: ${info.fieldName}`);return next();},
};

确保在GraphQL服务器配置中注册此指令处理器。

4. GraphQL Federation

Federation允许构建由多个服务组成的单一GraphQL API。

Service A Schema:

extend schema@link(url: "https://specs.apollo.dev/federation/v2.0", import: ["@key", "@shareable"])type Product @key(fields: "upc") {upc: String! @externalprice: Float
}

Service B Schema:

extend schema@link(url: "https://specs.apollo.dev/federation/v2.0", import: ["@key"])type Review {body: Stringauthor: User @provides(fields: "username")
}extend type User @key(fields: "id") {id: ID! @externalusername: String
}
5. 复杂查询优化

利用GraphQL的字段解析器和数据加载器进行性能优化。

Data Loader示例:

const dataLoader = new DataLoader(keys => db.batchLoadUsers(keys));const resolvers = {User: {friends: (parent, args, context, info) => {return dataLoader.load(parent.id);},},
};

GraphQL 特点与优势

  • 性能优化:通过按需获取数据,减少了网络传输开销,提高了页面加载速度。
  • 减少错误:客户端定义查询结构,服务器返回预期的形状,降低了由于接口不匹配导致的错误。
  • 更好的API设计:强类型系统确保了数据的一致性和正确性,使得API更加易于理解和维护。
  • 客户端控制:客户端可以决定获取多少数据,何时获取,提高了用户体验。
  • 缓存优化:客户端可以根据返回的数据结构更容易地进行缓存策略的实施。
  • 减少后端复杂性:后端不再需要为了适应不同客户端的需求而创建多个API端点。

2024年礼包2500G计算机入门到高级架构师开发资料超级大礼包免费送!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/835805.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

fatal: fetch-pack: invalid index-pack output

解决方案&#xff1a;git clone --depth1 要克隆的git地址 下载最近一次提交的代码 其他分支的内容都不下载 这样整体下载体量就变小了 执行命令&#xff1a;git clone --depth 1 https://gitlab.scm321.com/ufx/xxxx.git

android 蓝牙技术 学习记录

一 。蓝牙介绍 蓝牙可以分为 经典蓝牙-----》传统蓝牙(BT 1.0/2.0/2.1)和高速蓝牙(BT3.0) 低功耗蓝牙 ----》BLE(BLE 4.0/4.1/4.2/5.0./5.1/5.2)和 Bluetooth Mesh 关于蓝牙协议。除开Mesh大致可以分为3层: App:上层协议有很多,例如ANP,HOGP,FTMP 等等 host:中…

Mac idea gradle解决异常: SSL peer shut down incorrectly

系统&#xff1a;mac 软件&#xff1a;idea 解决异常: SSL peer shut down incorrectly 查看有没有安装 gradle -v安装 根据项目gradle提示安装版本 brew install gradle7idea的配置 在settings搜索gradle&#xff0c;配置Local installation&#xff0c;选择自己的安装目录…

机器学习入门到放弃2:朴素贝叶斯

1. 算法介绍 1.1 算法定义 朴素贝叶斯分类&#xff08;NBC&#xff09;是以贝叶斯定理为基础并且假设特征条件之间相互独立的方法&#xff0c;先通过已给定的训练集&#xff0c;以特征词之间独立作为前提假设&#xff0c;学习从输入到输出的联合概率分布&#xff0c;再基于学习…

【Java代码审计】越权篇

【Java代码审计】越权篇 越权漏洞概述 越权漏洞概述 失效的访问控制是指未对通过身份验证的用户实施恰当的访问控制。攻击者可以利用这些缺陷访问未经授权的功能或数据&#xff0c;例如访问其他用户的账户、查看敏感文件、修改其他用户的数据、更改访问权限等。业界常将典型的…

YOLOv9独家改进系列-可改变核卷积

一、改进点介绍 AKConv是一种具有任意数量的参数和任意采样形状的可变卷积核,对不规则特征有更好的提取效果。 论文速览::AKConv是2023年11月发表的一种可变卷积核,赋予卷积核任意数量的参数和任意采样形状,以解决具有固定样本形状和正方形的卷积核不能很好地适应…

物联网SCI期刊,潜力新刊,审稿速度快,收稿范围广泛!

一、期刊名称 Internet of Things 二、期刊简介概况 期刊类型&#xff1a;SCI 学科领域&#xff1a;物联网 影响因子&#xff1a;5.9 中科院分区&#xff1a;3区 出版方式&#xff1a;订阅模式/开放出版 版面费&#xff1a;选择开放出版需支付$2310 三、期刊征稿范围 I…

PTP 对时协议 IEEE1588 网络对时 计算原理

前言 本文将阐述 PTP 对时协议的原理&#xff0c;slave 节点如何根据获取的时间来纠正和更新自己的时间。 协议概述 整个通讯过程中会发送 4 种类型的数据包&#xff0c;用来支撑对时。下面是 4 个包的解释 Sync message: 由 master 发送&#xff0c;发起对时事务, slave 接…

Java - Json字符串转List<LinkedHashMap<String,String>>

需求&#xff1a;在处理数据时&#xff0c;需要将一个Object类型对象集合转为有序的Map类型集合。 一、问题 1.原代码&#xff1a; 但在使用时出现报错&#xff1a; Incompatible equality constraint: LinkedHashMap<String, String> and LinkedHashMap 不兼容的相等…

关于SpringBoot MVC接口超时时间的分析

前言 如果在网上搜索&#xff0c;SpringBoot接口超时时间&#xff0c;很多人会说是配置&#xff1a;spring.mvc.async.request-timeout&#xff0c;这个回答对也不对。主要是这个问题问的就不清不楚&#xff0c;所以这个答案也就不清不楚了。 结论 同步接口没有超时时间一说…

副产物四氯化硅综合利用满足可持续发展需求 行业发展意义重大

副产物四氯化硅综合利用满足可持续发展需求 行业发展意义重大 副产物四氯化硅综合利用&#xff0c;是以工业&#xff08;主要是多晶硅行业&#xff09;副产物四氯化硅为原料&#xff0c;制备高价值化学品的过程&#xff0c;可保护环境不受污染&#xff0c;同时实现废物资源化再…

JavaScript APIs

控制网页元素交互等各种网页交互效果。 一、Web API基本认知 声明数组和变量优先使用const 使用let声明变量的情况&#xff1a; 1、如果基本数据类型的值或者引用类型的地址发生变化的时候&#xff0c;需要用let 2、比如 一个变量进行加减运算&#xff0c;比如 for循环中的…

flutter 嵌套 StatefulWidget 不刷新

widget1 中有一个按钮和 widget2 , 点击一次按钮 数字i1,调用 widget2(i); widget1 widget2 都是 StatefulWidget import package:flutter/material.dart; import package:stack_trace/stack_trace.dart; import dart:developer as dev;void main() {runApp(MaterialApp(tit…

单例模式如何实现?

单例模式是一种创建型设计模式&#xff0c;它确保一个类只有一个实例&#xff0c;并提供一个全局访问点来访问这个唯一实例。在 C 中&#xff0c;可以通过将构造函数设为私有&#xff0c;并提供一个静态方法来获取或创建类的实例来实现单例模式。 下面是一个简单的 C 单例模式的…

Linux日常管理和服务器配置(二)

一、在系统中配置FTP服务器&#xff1a; 准备工作&#xff1a; a.下载ftp命令 sudo apt install vsftpd 可以先用命令更新一下库 sudo apt-get update 接着输入 systemctl status vsftpd 检查ftp运行状态 然后进入vsftpd.conf文件中修改write为 vim /etc/vsftpdf.conf …

深入理解指针(1)

在之前我们学习了许多c语言的基础知识&#xff0c;让我们初步了解了c语言&#xff0c;接下来将来到c语言中一个重点的知识章节--指针&#xff0c;学习完指针后将会让我们对c语言有更深入的理解&#xff0c;接下来就开始指针的讲解 1.内存与地址 1.指针 在了解内存与地址前&am…

vue开发网站—①调用$notify弹窗、②$notify弹窗层级问题、③js判断两个数组是否相同等。

一、vue中如何使用vant的 $notify&#xff08;展示通知&#xff09; 在Vue中使用Vant组件库的$notify方法来展示通知&#xff0c;首先确保正确安装了Vant并在项目中引入了Notify组件。 1.安装vant npm install vant --save# 或者使用yarn yarn add vant2.引入&#xff1a;在ma…

词令蚂蚁新村今日答案:微信小程序怎么查看蚂蚁新村今天问题的正确答案?

微信小程序怎么查看蚂蚁新村今天问题的正确答案&#xff1f; 1、打开微信&#xff0c;点击搜索框&#xff1b; 2、打开搜索页面&#xff0c;选择小程序搜索&#xff1b; 3、在搜索框&#xff0c;输入词令搜索点击进入词令微信小程序&#xff1b; 4、打开词令微信小程序关键词口…

Python专题:九、元组

append&#xff08;&#xff09;函数添加列表元素 remove&#xff08;&#xff09;函数移除列表元素 数据存储知识 变量保存的就是数据在内存中的地址 id()函数查看变量存储地址 动态分配 内存地址是动态分配的&#xff0c;每次的数值不一致 copy&#xff08;&#xff09;函…

学习Vue3中reactive

学习Vue3中reactive 一、前言1、响应式对象2、对象属性的访问3、嵌套响应式对象4、避免直接修改响应式对象5、ref vs reactive 一、前言 在 Vue 3 中&#xff0c;reactive 是一个用于创建响应式对象的函数。响应式对象是 Vue 3 中数据驱动视图的核心&#xff0c;它们的属性的变…