Graphql基本概念和使用

graphql是一什么?

graphql接口调用规范,graphql在框架上通过模型定义文件感知了模型的存在,所以可以动态指定返回值的需要返回哪些,比如有一个接口有100个返回值字段,可以指定需要那几个。

postman里面有对graphql的特殊支持。

image-20250205164956676

其实直接发送post请求也行,只是这样参数不好看,也不好修改
image-20250205164932983

graphql在springboot中的使用

导入依赖,

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    <version>2.7.8</version>
</dependency>


<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-graphql</artifactId>
    <version>2.7.8</version>
</dependency>

修改配置文件(不改也行,这里重要的是graphiql的开启,类似一个调试界面)

## web ##
server:
  servlet:
    context-path: /
  port: 8088
spring:
  graphql:
    graphiql:
      enabled: true
    websocket:
      path: /graphql
    schema:
      printer:
        enabled: true
      locations: classpath:/graphql   #test.graphql文件位置
      file-extensions: .graphql

写几个对象和他们的查询和修改的方法

public class Book {
    private Long id;
    private String name;
    private User owner;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public User getOwner() {
        return owner;
    }

    public void setOwner(User owner) {
        this.owner = owner;
    }
}


public class User {

    private Long id;
    private String name;
    private Integer age;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }
}

对user和book查询和修改的方法
@QueryMapping 对应查询
@MutationMapping 对应的写入

@Controller
public class GraphqlTestController {

    Map<Long, User> users = new HashMap<>();
    Map<Long, Book> books = new HashMap<>();



    @QueryMapping
    public String hello(){
        return "hello graphql";
    }

    @QueryMapping
    public User getUserById(@Argument Long id) {
        System.out.println("id:"+id);
        return users.get(id);
    }

    @MutationMapping
    public int addUser(@Argument Long id) {
        System.out.println("id:"+id);
        User user = new User();
        user.setId( id );
        users.put(user.getId(),user);
        return users.size();
    }

    @MutationMapping
    public User addBook(@Argument Long id,@Argument String name,@Argument Long userId) {
        System.out.println("id:"+id);

        Book book = new Book();
        book.setId(id);
        book.setName("name");
        book.setOwner( users.get(userId) );

        return book.getOwner();
    }


}

创建文件resources\graphql\schema.graphql
这个是定义模板和有哪些接口的约束文件


#  @QueryMapping 标注的方法,里面定义的需要和对应方法参数返回值对应

type Query {
    getUserById(id:String!) : String
    hello:String
}


#  @MutationMapping 标注的方法,里面定义的需要和对应方法参数返回值对应
type Mutation  {
    addUser(id:Int): Int
    addBook(id:String,name:String,userId:String): User!
}


# 这个和Book 对应的GraphqlTestController里面 导入的 xxx.Book,所以只是同名匹配,包名又GraphqlTestController导入决定
type Book {
    id: String
    name: String
    owner: User
}


# 对应 User对象
type User {
    id: String
    name: String
    age: Int
}


graphql的语法

当我们在配置文件中开启以后graphiql以后

spring:
  graphql:
    graphiql:
      enabled: true

可以使用调试界面:http://127.0.0.1:8088/graphiql
image-20250205170943200

点击执行的时候实际上它发送的是一个post请求,请求的地址是:http://127.0.0.1:8088/graphql,也就是前面物品截图postman请求的地址

image-20250205171514716

请求参数格式大概是这样的

# query或者mutation表示查询或者写入
# 参数列表写法类似json,但是外面是是小括号
# 返回值列表是大括号包裹起来的,里面没有逗号分割,一个属性一行,如果只有一个字段的返回值直接不写大括号

query/mutation{
	调用的方法名字(参数1:"参数1的值",参数2:"参数2的值"){
        返回字段1
        返回字段2
    }
}

如果在post里面发送外面还有一层query

{
    "query": "mutation{\n  addAuthor(id:2)\n}"
}

然后看看 schema.graphql文件的定义

模型对象的映射大概是这样的

type 对象名字{
属性1: 类型
属性2: 类型
属性3: 类型
}

# 这个和Book 对应的GraphqlTestController里面 导入的 xxx.Book,所以只是同名匹配,包名又GraphqlTestController导入决定
type Book {
    id: String
    name: String
    owner: User
}


# 对应 User对象
type User {
    id: String
    name: String
    age: Int
}

方法对象的定义,
type Query/Mutation {
方法1(参数1:类型) : 返回值
方法2:返回值
}

# 下面的!表示必填参数,
# 如果返回值是数据组用[类型]括起来,比如[User] 表示User集合

#  @QueryMapping 标注的方法,里面定义的需要和对应方法参数返回值对应

type Query {
    getUserById(id:String!) : String
    hello:String
}


#  @MutationMapping 标注的方法,里面定义的需要和对应方法参数返回值对应
type Mutation  {
    addUser(id:Int): Int
    addBook(id:String,name:String,userId:String): User!
}

graphsql的数据类型没有Long,只有Int和String,float之类的,可以直接使用String代替,并且默认会类型转换,但是不清楚会不会丢精度,了解不深,也没打算大量使用,所以没做 更加深入的了解。

优缺点(个人观点)

优点:很明显graphql这个框架通过模型文件感知了返回值类型,所以他最大的优点在于可以动态指定返回哪些参数,这样在后端提供大而且全的接口的时候前端可以通过指定返回值节省一些服务器的带宽,但是这需要前端知道这个接口有哪些参数。

缺点:这个语法对比restful+json明显更加复杂,不是通用的法语,可读性更低。修改成本也会更高,以前的修改成本是实体类加方法,现在需要多维护实体类模型和方法定义模型。

缺点2:所有的请求都在一个接口,请求地址一样,只是参数不一样我们对浏览器缓存的控制可能会变得更加困难,协商缓存的控制大概也不能用了。在外层有权限控制的系统里面,感觉通过这个接口留后门是不错的方法,因为只用开通一个接口权限就能调用所有graphql的接口,但是,这个接口风险可能会很高,需要慎重使用。

一个技术只要有一个闪光点就有存在的必要,但是如果它要取代现有的技术一定是全方面领先才行,感觉graphql有闪光点,但是和通常使用的restful+json来说并没有太多的优势。

posted on 2025-02-05 18:02  zhangyukun  阅读(318)  评论(0)    收藏  举报

导航