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计算机入门到高级架构师开发资料超级大礼包免费送!
相关文章:
GraphQL在现代Web应用中的应用与优势
GraphQL是一种现代的API查询语言,它在现代Web应用中得到了广泛的应用,因为它提供了一种高效、灵活且强大的方式来获取数据 GraphQL基础快速应用示例: 1. 后端设置(使用graphql-yoga) 首先,我们需要创建一…...
socket编程 学习笔记 理解
在使用socket(也就是套接字)编程的时候,其实是工作于应用层和传输层之间 如果使用的是基于TCP的socket,那每个数据包的发送的过程大致为: 数据通过socket套接字构造符合TCP协议的数据包在屏蔽底层协议的情况下&#…...
SC-Lego-LOAM建图与ndt_localization的实车实现
参考:https://blog.csdn.net/weixin_44303829/article/details/121524380 https://github.com/AbangLZU/SC-LeGO-LOAM.git https://github.com/AbangLZU/ndt_localizer.git 将建图和定位分别使用lego-loam和ndt来进行,实车上的效果非常不错,…...
vs code中如何使用git
由于本地代码有了一些储备,所以想通过网址托管形式,之前一直使用了github,但是鉴于一直被墙,无法登录账号,所以选择了国内的gitee来作为托管网站。 gitee的网址:Gitee - 基于 Git 的代码托管和研发协作平台…...
Vue项目中如何通过配置修改项目名称
Vue项目中如何通过配置修改项目名称 前言 部分vue项目中为了不直接修改 index.html 文件而使用 config 配置文件进行修改,好处就是项目配置比较集中好管理、可实现动态化修改。 具体配置和使用 项目中 index.html 配置标题名,可以看到 <title>…...
ThinkPHP5.1 创建控制器类
在ThinkPHP中,控制器是MVC模式中的核心组件之一,负责接收用户请求并处理相应的业务逻辑。在本篇技术博客中,我们将深入探讨ThinkPHP5.1中的控制器操作,包括创建控制器、路由绑定、请求参数获取等方面的知识点。 1.创建控制器 在T…...
完全背包问题(c++)
完全背包问题 当前有 N 种物品,第 i 种物品的体积是 ci,价值是 wi。 每种物品的数量都是无限的,可以选择任意数量放入背包。 现有容量为 V 的背包,请你放入若干物品,使总体积不超过 V,并且总价值尽可…...
综合性练习(验证码案例)
目录 一、需求 二、准备工作 三、约定前后端交互接口 1、需求分析 2、接口定义 四、Hutool工具介绍 1、引入依赖 2、测试使用Hutool生成验证码 五、实现服务器端代码 代码解读: 六、调整前端页面代码 七、运行测试 随着安全性的要求越来越高,…...
实用的Chrome命令 帮你打开Chrome浏览器的隐藏功能
前言 Chrome作为主力浏览器,支持相当丰富的第三方扩展,其实浏览器本身也内置了大量实用的命令。许多实用的功能并没有直接显示在Chrome的菜单上。在这篇文章中,我们将介绍几个实用的chrome:// commands。 通过下面整理的 Chrome 命令&#x…...
Linux提权--定时任务--打包配合 SUID(本地)文件权限配置不当(WEB+本地)
免责声明:本文仅做技术交流与学习... 目录 定时任务 打包配合 SUID-本地 原理: 背景: 操作演示: 分析: 实战发现: 定时任务 文件权限配置不当-WEB&本地 操作演示: 定时任务 打包配合 SUID-本地 原理: 提权通过获取计划任务执行文件信息进行提权 . 1、相对路径和…...
CSS-盒子模型
盒子模型的重要组成部分 内容区域content:width , height 内边距:内边框和内容区域的距离Padding边框线:Border外边距:Margin Border (边框线) 属性:Border 属性值:边框线粗细px 线条样式 颜色(不区分…...
WPF之页的使用
1,Page介绍。 Page直接从FrameworkElement中派生出来,WIndow从ContentControl中派生。 [Localizability(LocalizationCategory.Ignore)]public class Window : ContentControl, IWindowService{....} [ContentProperty("Content")]public class Page : Fr…...
【FFmpeg】Filter 过滤器 ② ( 裁剪过滤器 Crop Filter | 裁剪过滤器语法 | 裁剪过滤器内置变量 | 裁剪过滤器常用用法 )
文章目录 一、裁剪过滤器1、裁剪过滤器简介2、裁剪过滤器语法3、裁剪过滤器内置变量4、裁剪过滤器示例5、裁剪过滤器应用6、裁剪过滤器图示 二、裁剪过滤器常用用法1、裁剪指定像素的视频区域2、裁剪视频区域中心正方形 - 默认裁剪3、裁剪视频区域中心正方形 - 手动计算4、裁剪…...
thinkphp5 中控制器的创建和使用方法
在 ThinkPHP 5 中,控制器(Controller)是用于处理请求、执行逻辑操作并返回响应的类。以下是在 ThinkPHP 5 中创建和使用控制器的基本方法: 1. 创建控制器 在 ThinkPHP 5 中,控制器通常位于 application/index/contro…...
[Linux] 常用服务器命令(持续更新)
文件操作 # 显示文件系统的磁盘空间使用情况 df -h全局查找文件 find / -type f -iname "java"find / -name libncurses*拷贝整个文件夹 cp -r /home/a/ /home/b/ 解压,撤销解压 撤销zip解压 zipinfo -1 path/xx.zip | xargs rm -rf 撤销tar解压 tar …...
编译官方原版的openwrt并加入第三方软件包
最近又重新编译了最新的官方原版openwrt-2305(2024.3.22),此处记录一下以待日后参考。 目录 1.源码下载 1.1 通过官网直接下载 1.2 映射github加速下载 1.2.1 使用github账号fork源码 1.2.2 创建gitee账号映射github openwrt 2.编译准…...
PC适配移动端
**手机端适配** 媒体查询 组件统一样式 媒体查询写四套样式 手机 屏幕宽小于768px 平板 屏幕宽 大于等于768px 小于992px 桌面显示器 屏幕宽大于等于992px 小于1200px 大屏幕 屏幕宽大于等于1200px **页面整体及页面内容** 页面看是需要主PC还是主移动端 主移动端的话…...
springboot+vue+mybatis灵活就业服务平台+PPT+论文+讲解+售后
随着网络科技的不断发展以及人们经济水平的逐步提高,网络技术如今已成为人们生活中不可缺少的一部分,而微信小程序是通过计算机技术,针对用户需求开发与设计,该技术尤其在各行业领域发挥了巨大的作用,有效地促进了灵活…...
Android 13 系统自定义安全水印
效果 源码实现 frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java public final void showSafeModeOverlay() {View v LayoutInflater.from(mContext).inflate(com.android.internal.R.layout.safe_mode, null);WindowManager.Layout…...
C# WCF服务(由于内部错误,服务器无法处理该请求。)
由于内部错误,服务器无法处理该请求。有关该错误的详细信息,请打开服务器上的 IncludeExceptionDetailInFaults (从 ServiceBehaviorAttribute 或从 <serviceDebug> 配置行为)以便将异常信息发送回客户端,或打开对每个 Microsoft .NET …...
【杂谈】-递归进化:人工智能的自我改进与监管挑战
递归进化:人工智能的自我改进与监管挑战 文章目录 递归进化:人工智能的自我改进与监管挑战1、自我改进型人工智能的崛起2、人工智能如何挑战人类监管?3、确保人工智能受控的策略4、人类在人工智能发展中的角色5、平衡自主性与控制力6、总结与…...
java_网络服务相关_gateway_nacos_feign区别联系
1. spring-cloud-starter-gateway 作用:作为微服务架构的网关,统一入口,处理所有外部请求。 核心能力: 路由转发(基于路径、服务名等)过滤器(鉴权、限流、日志、Header 处理)支持负…...
Linux简单的操作
ls ls 查看当前目录 ll 查看详细内容 ls -a 查看所有的内容 ls --help 查看方法文档 pwd pwd 查看当前路径 cd cd 转路径 cd .. 转上一级路径 cd 名 转换路径 …...
1.3 VSCode安装与环境配置
进入网址Visual Studio Code - Code Editing. Redefined下载.deb文件,然后打开终端,进入下载文件夹,键入命令 sudo dpkg -i code_1.100.3-1748872405_amd64.deb 在终端键入命令code即启动vscode 需要安装插件列表 1.Chinese简化 2.ros …...
【Go】3、Go语言进阶与依赖管理
前言 本系列文章参考自稀土掘金上的 【字节内部课】公开课,做自我学习总结整理。 Go语言并发编程 Go语言原生支持并发编程,它的核心机制是 Goroutine 协程、Channel 通道,并基于CSP(Communicating Sequential Processes࿰…...
pikachu靶场通关笔记22-1 SQL注入05-1-insert注入(报错法)
目录 一、SQL注入 二、insert注入 三、报错型注入 四、updatexml函数 五、源码审计 六、insert渗透实战 1、渗透准备 2、获取数据库名database 3、获取表名table 4、获取列名column 5、获取字段 本系列为通过《pikachu靶场通关笔记》的SQL注入关卡(共10关࿰…...
Fabric V2.5 通用溯源系统——增加图片上传与下载功能
fabric-trace项目在发布一年后,部署量已突破1000次,为支持更多场景,现新增支持图片信息上链,本文对图片上传、下载功能代码进行梳理,包含智能合约、后端、前端部分。 一、智能合约修改 为了增加图片信息上链溯源,需要对底层数据结构进行修改,在此对智能合约中的农产品数…...
AI病理诊断七剑下天山,医疗未来触手可及
一、病理诊断困局:刀尖上的医学艺术 1.1 金标准背后的隐痛 病理诊断被誉为"诊断的诊断",医生需通过显微镜观察组织切片,在细胞迷宫中捕捉癌变信号。某省病理质控报告显示,基层医院误诊率达12%-15%,专家会诊…...
Java求职者面试指南:Spring、Spring Boot、MyBatis框架与计算机基础问题解析
Java求职者面试指南:Spring、Spring Boot、MyBatis框架与计算机基础问题解析 一、第一轮提问(基础概念问题) 1. 请解释Spring框架的核心容器是什么?它在Spring中起到什么作用? Spring框架的核心容器是IoC容器&#…...
协议转换利器,profinet转ethercat网关的两大派系,各有千秋
随着工业以太网的发展,其高效、便捷、协议开放、易于冗余等诸多优点,被越来越多的工业现场所采用。西门子SIMATIC S7-1200/1500系列PLC集成有Profinet接口,具有实时性、开放性,使用TCP/IP和IT标准,符合基于工业以太网的…...
