Spring GraphQL:构建GraphQL API

好的,各位观众老爷,各位代码界的弄潮儿,欢迎来到今天的“GraphQL那些事儿”专场!今天我们要聊的啊,是Spring GraphQL,这玩意儿就像GraphQL的“官方盖章”版,有了它,你就能在Spring生态里,像开了外挂一样,轻松构建GraphQL API。

准备好了吗?让我们一起踏上这场代码与段子的奇妙旅程!🚀

第一幕:GraphQL,不只是个名字

首先,我们得搞清楚GraphQL是什么玩意儿。别一听名字就觉得高深莫测,其实它就是个API查询语言,简单来说,就是你想要啥,就跟API说啥,API就给你啥,不多给,也不少给。

想象一下,你点外卖,传统REST API就像是“豪华套餐”,不管你爱不爱吃,都给你一股脑端上来。而GraphQL就像是“自助餐”,你想吃啥就拿啥,绝不浪费!😋

特性 REST API GraphQL API
数据获取方式 过度获取/不足获取 精确获取所需数据
查询方式 多个endpoint 单一endpoint
数据格式 通常为JSON JSON
灵活性 较低 较高
版本控制 需要管理多个版本 可以使用类型系统和introspection进行演化

第二幕:Spring GraphQL,GraphQL的“春天”

有了GraphQL,我们还需要一个强大的框架来支撑它,这就是Spring GraphQL闪亮登场的时候了。它就像是GraphQL的“春天”,给GraphQL带来了蓬勃的生命力!🌱

Spring GraphQL是Spring团队官方提供的GraphQL支持,它充分利用了Spring生态系统的优势,比如依赖注入、AOP、事务管理等等,让你能用更优雅、更高效的方式来构建GraphQL API。

Spring GraphQL的优势:

  • Spring Boot集成: 无缝集成Spring Boot,自动配置,开箱即用!
  • 声明式编程: 使用注解和Schema Definition Language (SDL) 来定义GraphQL schema,代码更简洁,可读性更高。
  • 数据访问集成: 轻松集成Spring Data JPA、Spring Data MongoDB等数据访问技术,简化数据获取和处理。
  • 错误处理: 提供灵活的错误处理机制,方便你处理各种异常情况。
  • 安全: 集成Spring Security,保护你的GraphQL API免受恶意攻击。
  • 测试: 提供测试框架,方便你编写单元测试和集成测试。

第三幕:开工!搭建Spring GraphQL项目

废话不多说,让我们撸起袖子,开始搭建一个Spring GraphQL项目!

1. 创建Spring Boot项目

使用Spring Initializr(https://start.spring.io/)创建一个Spring Boot项目,添加以下依赖:

  • spring-boot-starter-web
  • spring-boot-starter-graphql

2. 定义GraphQL Schema

使用Schema Definition Language (SDL) 来定义GraphQL schema,创建一个schema.graphqls文件,放在src/main/resources/graphql目录下。

type Query {
  bookById(id: ID): Book
  allBooks: [Book]
}

type Book {
  id: ID!
  name: String
  author: String
}

这个schema定义了一个Query类型,包含两个查询:

  • bookById(id: ID):根据ID查询书籍
  • allBooks:查询所有书籍

还有一个Book类型,包含idnameauthor字段。

3. 实现GraphQL Resolver

创建GraphQL resolver来处理GraphQL查询,创建一个BookResolver类:

import org.springframework.graphql.data.method.annotation.Argument;
import org.springframework.graphql.data.method.annotation.QueryMapping;
import org.springframework.stereotype.Controller;

import java.util.Arrays;
import java.util.List;

@Controller
public class BookResolver {

    private List<Book> books = Arrays.asList(
            new Book("book-1", "Effective Java", "Joshua Bloch"),
            new Book("book-2", "Clean Code", "Robert C. Martin"),
            new Book("book-3", "The Pragmatic Programmer", "Andrew Hunt & David Thomas")
    );

    @QueryMapping
    public Book bookById(@Argument String id) {
        return books.stream()
                .filter(book -> book.getId().equals(id))
                .findFirst()
                .orElse(null);
    }

    @QueryMapping
    public List<Book> allBooks() {
        return books;
    }
}

class Book {
    private String id;
    private String name;
    private String author;

    public Book(String id, String name, String author) {
        this.id = id;
        this.name = name;
        this.author = author;
    }

    public String getId() {
        return id;
    }

    public String getName() {
        return name;
    }

    public String getAuthor() {
        return author;
    }
}
  • @Controller:标记该类为一个Spring Controller。
  • @QueryMapping:将方法映射到GraphQL schema中的查询。
  • @Argument:获取GraphQL查询中的参数。

4. 运行项目

运行Spring Boot项目,访问http://localhost:8080/graphiql(默认情况下,Spring GraphQL会启用GraphiQL,一个GraphQL IDE),就可以开始使用GraphQL API了!

5. 发送GraphQL查询

在GraphiQL中,输入以下GraphQL查询:

query {
  bookById(id: "book-1") {
    id
    name
    author
  }
  allBooks {
    id
    name
    author
  }
}

点击运行,就可以看到返回的结果了!🎉

第四幕:进阶!GraphQL的“十八般武艺”

掌握了基本用法,让我们来学习一些GraphQL的“十八般武艺”,让你的GraphQL API更加强大!💪

1. Mutations(修改)

除了查询数据,GraphQL还可以修改数据,这就是Mutations。

schema.graphqls中添加一个Mutation类型:

type Mutation {
  addBook(name: String, author: String): Book
}

BookResolver中添加一个addBook方法:

import org.springframework.graphql.data.method.annotation.MutationMapping;

@MutationMapping
public Book addBook(@Argument String name, @Argument String author) {
    Book book = new Book("book-" + (books.size() + 1), name, author);
    books.add(book);
    return book;
}
  • @MutationMapping:将方法映射到GraphQL schema中的Mutation。

2. Subscriptions(订阅)

GraphQL还可以实现实时数据推送,这就是Subscriptions。

首先,你需要添加一个spring-boot-starter-reactor-netty依赖,因为它提供了WebSocket支持。

schema.graphqls中添加一个Subscription类型:

type Subscription {
  bookAdded: Book
}

创建一个BookSubscription类:

import org.springframework.stereotype.Controller;
import reactor.core.publisher.Flux;
import java.time.Duration;
import org.springframework.graphql.data.method.annotation.SubscriptionMapping;

@Controller
public class BookSubscription {

    @SubscriptionMapping
    public Flux<Book> bookAdded() {
        return Flux.interval(Duration.ofSeconds(5))
                .map(i -> new Book("book-" + (i + 4), "New Book " + i, "New Author " + i));
    }
}
  • @SubscriptionMapping:将方法映射到GraphQL schema中的Subscription。
  • Flux:Reactor库中的一个类,用于表示异步数据流。

3. Data Fetchers(数据抓取器)

Data Fetchers用于从不同的数据源获取数据,并将它们组合成GraphQL schema中的类型。

例如,假设Book类型还有一个publisher字段,需要从另一个API获取publisher信息,就可以使用Data Fetchers。

4. Error Handling(错误处理)

Spring GraphQL提供了灵活的错误处理机制,你可以自定义错误处理器,处理各种异常情况。

第五幕:实战!构建一个完整的GraphQL API

现在,让我们用Spring GraphQL构建一个更完整的GraphQL API,例如一个博客系统。

1. 定义Schema

type Query {
  postById(id: ID!): Post
  allPosts: [Post]
  commentsByPostId(postId: ID!): [Comment]
}

type Mutation {
  createPost(title: String!, content: String!): Post
  addComment(postId: ID!, content: String!): Comment
}

type Post {
  id: ID!
  title: String!
  content: String!
  comments: [Comment]
}

type Comment {
  id: ID!
  postId: ID!
  content: String!
}

2. 创建实体类

import javax.persistence.*;
import java.util.List;

@Entity
public class Post {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String title;
    private String content;

    @OneToMany(mappedBy = "post")
    private List<Comment> comments;

    // Getters and setters
}

@Entity
public class Comment {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String content;

    @ManyToOne
    @JoinColumn(name = "post_id")
    private Post post;

    // Getters and setters
}

3. 创建Repository

import org.springframework.data.jpa.repository.JpaRepository;

public interface PostRepository extends JpaRepository<Post, Long> {
}

public interface CommentRepository extends JpaRepository<Comment, Long> {
    List<Comment> findByPostId(Long postId);
}

4. 创建Resolver

import org.springframework.graphql.data.method.annotation.*;
import org.springframework.stereotype.Controller;

import java.util.List;

@Controller
public class BlogResolver {

    private final PostRepository postRepository;
    private final CommentRepository commentRepository;

    public BlogResolver(PostRepository postRepository, CommentRepository commentRepository) {
        this.postRepository = postRepository;
        this.commentRepository = commentRepository;
    }

    @QueryMapping
    public Post postById(@Argument Long id) {
        return postRepository.findById(id).orElse(null);
    }

    @QueryMapping
    public List<Post> allPosts() {
        return postRepository.findAll();
    }

    @QueryMapping
    public List<Comment> commentsByPostId(@Argument Long postId) {
        return commentRepository.findByPostId(postId);
    }

    @MutationMapping
    public Post createPost(@Argument String title, @Argument String content) {
        Post post = new Post();
        post.setTitle(title);
        post.setContent(content);
        return postRepository.save(post);
    }

    @MutationMapping
    public Comment addComment(@Argument Long postId, @Argument String content) {
        Post post = postRepository.findById(postId).orElse(null);
        if (post == null) {
            return null; // Handle error
        }
        Comment comment = new Comment();
        comment.setPost(post);
        comment.setContent(content);
        return commentRepository.save(comment);
    }

    @SchemaMapping(typeName = "Post", field = "comments")
    public List<Comment> getCommentsForPost(Post post) {
        return commentRepository.findByPostId(post.getId());
    }
}
  • @SchemaMapping:将方法映射到GraphQL schema中的类型的字段,用于解决N+1问题。

第六幕:总结!GraphQL,未来可期!

Spring GraphQL作为Spring生态系统中GraphQL的官方支持,为我们构建GraphQL API提供了极大的便利。它简化了开发流程,提高了开发效率,并充分利用了Spring生态系统的优势。

GraphQL作为一种新型的API查询语言,正在被越来越多的开发者所采用。它具有灵活、高效、强大的优点,能够很好地解决传统REST API的各种问题。

所以,各位小伙伴们,赶紧拥抱GraphQL,拥抱Spring GraphQL,让你的API更加强大,让你的代码更加优雅!🎉

希望今天的分享对你有所帮助,咱们下期再见! 👋

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注