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

简介: GraphQL是一种现代的API查询语言,它在现代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) {
   
    name
    email
  }
}

# 突变示例
mutation CreateUser {
   
  createUser(name: "Alice", email: "alice@example.com") {
   
    id
    name
  }
}

# 订阅示例(假设使用WebSocket)
subscription OnNewUser {
   
  newUser {
   
    id
    name
  }
}

在上述代码中,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 {
   
    id
    name
    posts {
   
      id
      title
      content
      author {
   
        id
        name
      }
    }
  }
}

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

客户端代码示例(使用Apollo Client)

import {
    gql, useQuery } from '@apollo/client';

const GET_USERS_AND_POSTS = gql`
  query GetUsersAndPosts {
    users {
      id
      name
      posts {
        id
        title
        content
        author {
          id
          name
        }
      }
    }
  }
`;

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!): User
  allUsers: [User!]!
  post(id: ID!): Post
  allPosts: [Post!]!
}

type Mutation {
   
  createUser(username: String!, email: String!): User
  createPost(title: String!, content: String!, userId: ID!): Post
}

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

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

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

scalar DateTime

directive @auth(requires: Role = ADMIN) on FIELD_DEFINITION

enum Role {
   
  ADMIN
  USER
}

接着,在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: String
  endCursor: 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! @external
  price: Float
}

Service B Schema:

extend schema
  @link(url: "https://specs.apollo.dev/federation/v2.0", import: ["@key"])

type Review {
   
  body: String
  author: User @provides(fields: "username")
}

extend type User @key(fields: "id") {
   
  id: ID! @external
  username: 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端点。

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

相关文章
|
4天前
|
SQL 安全 数据库
如何构建一个安全的Web应用:技术与策略的全面指南
【6月更文挑战第12天】构建安全Web应用的全面指南:了解SQL注入、XSS等威胁,采用输入验证、安全编程语言,配置安全服务器和数据库,使用HTTPS,实施会话管理、访问控制,正确处理错误和日志,定期进行安全审计和漏洞扫描。确保用户数据和应用安全。
|
1天前
|
数据库 Python
Python实践:从零开始构建你的第一个Web应用
使用Python和轻量级Web框架Flask,你可以轻松创建Web应用。先确保安装了Python,然后通过`pip install Flask`安装Flask。在`app.py`中编写基本的&quot;Hello, World!&quot;应用,定义路由`@app.route(&#39;/&#39;)`并运行`python app.py`启动服务器。扩展应用,可添加新路由显示当前时间,展示Flask处理动态内容的能力。开始你的Web开发之旅吧!【6月更文挑战第13天】
12 2
|
5天前
|
开发框架 Dart JavaScript
深入探讨Flutter中的Web支持功能,以及如何利用Flutter构建跨平台Web应用的最佳实践
【6月更文挑战第11天】Flutter,Google的开源跨平台框架,已延伸至Web支持,让开发者能用同一代码库构建移动和Web应用。Flutter Web基于Dart转JavaScript,利用WebAssembly和JavaScript在Web上运行。构建Web应用最佳实践包括选择合适项目、优化性能、进行兼容性测试和利用Flutter的声明式UI、热重载等优势。尽管性能挑战存在,Flutter Web为跨平台开发提供了更多机会和潜力。
33 1
|
5天前
|
运维 Serverless API
Serverless 应用引擎产品使用合集之如何实现一键迁移Web框架
阿里云Serverless 应用引擎(SAE)提供了完整的微服务应用生命周期管理能力,包括应用部署、服务治理、开发运维、资源管理等功能,并通过扩展功能支持多环境管理、API Gateway、事件驱动等高级应用场景,帮助企业快速构建、部署、运维和扩展微服务架构,实现Serverless化的应用部署与运维模式。以下是对SAE产品使用合集的概述,包括应用管理、服务治理、开发运维、资源管理等方面。
|
5天前
|
Java Serverless 应用服务中间件
Serverless 应用引擎产品使用合集之Web函数启动的Spring Boot项目可以通过什么方式配置Nginx
阿里云Serverless 应用引擎(SAE)提供了完整的微服务应用生命周期管理能力,包括应用部署、服务治理、开发运维、资源管理等功能,并通过扩展功能支持多环境管理、API Gateway、事件驱动等高级应用场景,帮助企业快速构建、部署、运维和扩展微服务架构,实现Serverless化的应用部署与运维模式。以下是对SAE产品使用合集的概述,包括应用管理、服务治理、开发运维、资源管理等方面。
|
6天前
|
缓存 前端开发 数据库
构建高性能Web应用的关键技术
本文将介绍构建高性能Web应用所需的关键技术。我们将探讨前端、后端、数据库等多个方面的技术,并提供实用的建议,帮助开发者优化应用性能并提升用户体验。
|
7天前
|
前端开发 测试技术 数据库
Ruby on Rails:快速开发Web应用的秘密
【6月更文挑战第9天】Ruby on Rails,一款基于Ruby的Web开发框架,以其高效、简洁和强大备受青睐。通过“约定优于配置”减少配置工作,内置丰富功能库加速开发,如路由、数据库访问。活跃的社区和海量资源提供支持,MVC架构与RESTful设计确保代码清晰可扩展。高效的数据库迁移和测试工具保证质量。Rails是快速构建Web应用的理想选择,未来将持续影响Web开发领域。
|
11天前
|
存储 数据库 开发者
IndexedDB解密:打开Web应用的数据存储之门
IndexedDB解密:打开Web应用的数据存储之门
39 0
|
15天前
|
XML 网络协议 Java
XML Web 服务技术解析:WSDL 与 SOAP 原理、应用案例一览
XML Web服务是基于WSDL、SOAP、RDF和RSS等标准的网络应用程序组件技术。WSDL描述服务接口和消息格式,SOAP用于结构化信息交换,RDF描述网络资源,RSS则用于发布网站更新。Web服务特点是自包含、自描述,基于开放协议,可重用且能连接现有软件。WSDL文档包含`types`、`message`、`portType`和`binding`元素,定义服务操作和协议。SOAP协议规定消息格式,通过HTTP等传输。
476 1
|
15天前
|
网络协议 开发者 UED
【计算巢】HTTP/2 与 HTTP/3:下一代 Web 协议的优势
【5月更文挑战第31天】HTTP/2 & HTTP/3,两大网络协议超级英雄,通过二进制分帧、多路复用提升效率,QUIC协议让HTTP/3实现更快连接与低延迟。代码示例展示HTTP/2高效请求,它们为用户带来更快加载速度,改善体验,尤其利于高延迟应用。对开发者意味着更高性能,为网站注入超级引擎。未来,它们将在更多领域发挥作用,点亮数字世界。