如何自定义 GraphQL 请求

在开发过程中,有时需要自定义 GraphQL 请求来实现更灵活的数据查询和操作。本文将介绍两种主要的自定义 GraphQL 请求方式:手写 GraphQL 请求和调用平台 API。

方式一:手写 GraphQL 请求

手写 GraphQL 请求是一种直接编写查询或变更语句的方式,适用于更复杂或特定的业务需求。以下分别是 querymutation 请求的示例。

1. 手写 Query 请求

以下是一个自定义 query 请求的示例,用于查询某个资源的语言信息列表。

const customQuery = async () => {
  const query = `{
    resourceLangQuery {
      queryListByEntity(query: {active: ACTIVE, installState: true}) {
        id
        name
        active
        installState
        code
        isoCode
      }
    }
  }`;

  const result = await http.query('resource', query);
  this.list = result.data['resourceLangQuery']['queryListByEntity'];
};

说明:

  • query 语句定义了一个请求,查询 resourceLangQuery 下的语言信息。
  • 查询的条件是 activeinstallState,只返回符合条件的结果。
  • 查询结果包括 id、name、active、installState 等字段。

2. 手写 Mutation 请求

以下是一个 mutation 请求的示例,用于创建新的资源分类信息。


const customMutation = async () => {
  const code = Date.now()
  const name = `测试${code}`

  const mutation = `mutation {
    resourceTaxKindMutation {
      create(data: {code: "${code}", name: "${name}"}) {
        id
        code
        name
        createDate
        writeDate
        createUid
        writeUid
      }
    }
  }`;

  const res = await http.mutate('resource', mutation);
  console.log(res);
};

说明:

  • mutation 语句用于创建一个新的资源分类。
  • create 操作的参数是一个对象,包含 code 和 name 字段。
  • 返回值包括 id、createDate 等字段。

方式二:调用平台的 API

平台 API 提供了简化的 GraphQL 调用方法,可以通过封装的函数来发送 query 和 mutation 请求。这种方式减少了手写 GraphQL 语句的复杂性,更加简洁和易于维护。

1. 调用平台的 Mutation API

使用平台的 customMutation 方法可以简化 Mutation 请求。

/**
 * 自定义请求方法
 * @param modelModel 模型编码
 * @param method 方法名或方法对象
 * @param records 请求参数,可以是单体对象或者对象的列表
 * @param requestFields 请求的字段配置,不传就是解析record内的所有字段
 * @param responseFields 响应的字段配置,不传就是所有字段都返回
 * @param variables 变量参数
 * @param context 上下文,其中的maxDepth属性表示查询的最大深度
 */
const customMutation = async (
  modelModel: string,
  method: string | { name: string; argumentName: string },
  records: ObjectValue | ListValue,
  requestFields?: IModelField[],
  responseFields?: IModelField[],
  variables?: ObjectValue,
  context: ObjectValue = {}
): Promise<any>
调用代码示例
// 1.customMutation 调用示例
const createTaxKind = async () => {
  const response = await customMutation(
    '模型编码',
    '模型方法',
    { code: '003', name: '测试3' }
  );
  console.log(response);
};

const createTaxKind2 = async () => {
  const response = await customMutation(
    '模型编码',
    {name:  '方法名', argumentName: '参数名'},
    { code: '003', name: '测试3' }
  );
  console.log(response);
};

2. 调用平台的 Query API

普通查询数据方法customQuery

/**
 * 自定义查询方法
 * @param modelModel 模型编码
 * @param method 方法名
 * @param record 请求参数,可以是单体对象或者对象的列表
 * @param requestFields 请求的字段配置,不传就是解析record内的所有字段
 * @param responseFields 响应的字段配置,不传就是所有字段都返回
 * @param variables 变量参数
 * @param context 上下文,其中的maxDepth属性表示查询的最大深度
 */
const customQuery = async <T>(
  modelModel: string,
  method: string,
  record: ObjectValue | ListValue | string = {},
  requestFields?: IModelField[],
  responseFields?: IModelField[],
  variables?: ObjectValue,
  context: ObjectValue = {}
): Promise<T>
调用代码示例
const fetchResourceLanguages = async () => {
  const response = await customQuery(
    '模型编码',
    '模型方法',
    { active: true },
  );
  console.log(response);
};

自定义分页类型接口查询方法

/**
 * 自定义分页类型接口查询方法
 * @param modelModel 模型编码
 * @param methodName 方法名
 * @param option 查询条件
 * @param requestFields 请求的字段配置,不传就是解析record内的所有字段
 * @param responseFields 响应的字段配置,不传就是所有字段都返回
 * @param variables 变量参数
 * @param context 上下文,其中的maxDepth属性表示查询的最大深度
 */
const customQueryPage = async <T = Record<string, unknown>>(
  modelModel: string,
  methodName: string,
  option: IQueryPageOption,
  requestFields?: IModelField[],
  responseFields?: IModelField[],
  variables?: ObjectValue,
  context: ObjectValue = {}
): Promise<IQueryPageResult<T>>
调用代码示例
// 存储字段的rsql查询条件
const rsql = `num > 1 and name =like='关键字'`;
// 查询条件对象
const condition = new Condition(rsql);
// 非存储字段的queryData查询条件
const queryData = { type: 'B2C' };
condition.setConditionBodyData(queryData)
const option = {
  // 当前页码
  currentPage: 1,
  // 每页条数
  pageSize: 20,
  // 查询条件对象,也可以是rsql字符串
  condition,
  // 自定义排序
  sort: [{sortField: 'id', direction: EDirection.ASC} as ISort]
} as IQueryPageOption;

const variables = {
  // 当调用的接口有权限相关提示可以设置该属性
  path: getSessionPath()
};
const page = await customQueryPage(
  'demo.demoItem',
  'queryPage',
  option,
  [],
  undefined,
  variables,
  { maxDepth: 1 }
);

标准分页接口查询方法

/**
 * 标准分页接口查询方法
 * @param modelModel 模型编码
 * @param option 查询条件
 * @param fields 请求和响应字段配置,不传就取当前模型内的所有字段
 * @param variables 变量参数
 * @param context 上下文,其中的maxDepth属性表示查询的最大深度
 */
const queryPage = async <T = Record<string, unknown>>(
  modelModel: string,
  option: IQueryPageOption,
  fields?: IModelField[],
  variables?: ObjectValue,
  context: ObjectValue = {}
): Promise<IQueryPageResult<T>> => {
  // 内部实际调用的也是customQueryPage
  return customQueryPage(modelModel, 'queryPage', option, fields, fields, variables, context);
};
调用方法示例

参考customQueryPage的调用示例

查询方法关键类型的定义

/**
 * 分页查询条件
 */
interface IQueryPageOption {
  pageSize?: number;
  currentPage?: number;
  sort?: ISort | ISort[];
  condition?: Condition | string;
  // condition 和 record 只能二选一
  record?: ObjectValue | ListValue;
  maxDepth?: number;
}

interface IQueryPageResult<T> {
  content: T[];
  totalElements: number;
  size: number;
  totalPages: number;
}

通用注意事项

默认情况下,平台 API 请求只会查询两层,如果要查询第三层,则需要传递往下查询深度的context.maxDepth属性,maxDepth=1为一共查询两层,maxDepth=2为一共查询三层;在平台底层maxDepth是从0开始的,0代表了第一层级,所以为1的时候,就是查两层。

/**
 * 响应字段的配置,不配置会返回模型下所有字段,
 * 建议按需求配置需要返回哪些字段,
 * 下面的配置等同于手写gql的
 * user {
 *   id
 *   name
 * }
 */
const responseFields = [
      {
        name: 'user',
        ttype: ModelFieldType.ManyToOne,
        modelFields: [
          { name: 'id', ttype: ModelFieldType.Long },
          { name: 'name', ttype: ModelFieldType.String }
        ] as IModelField[]
      }
    ] as IModelField[];

customMutation(
    '模型编码',
    '模型方法',
    { code: '003', name: '测试3' },
    undefined,
    responseFields,
    undefined,
    {
      maxDepth: 2
    }
  )

customQuery(
    '模型编码',
    '模型方法',
    { active: true },
    undefined,
    responseFields,
    undefined,
    {
      maxDepth: 2
    }
  )

对比

  • 手写 GraphQL 请求适用于请求参数比较简单的请求
  • 调用平台 API 适用于请求参数过于复杂、手动很难写

调用平台 API的弊端

调用平台 API会导致gql的请求体很大,因为底层会把当前模型所有的字段都作为响应体返回。如果请求的层级越深,那么gql请求体越大。

如果想通过手写Graphql的方法拼接复杂的请求参数,可以参考这边文章,里面有详细的讲解

Oinone社区 作者:汤乾华原创文章,如若转载,请注明出处:https://doc.oinone.top/frontend/17638.html

访问Oinone官网:https://www.oinone.top获取数式Oinone低代码应用平台体验

Like (0)
汤乾华's avatar汤乾华数式员工
Previous 2024年9月21日 pm4:17
Next 2024年9月26日 am9:19

相关推荐

  • 【前端】移动端工程结构最佳实践(v4/v5)

    阅读之前 你应该: 了解node与npm相关内容 了解lerna包管理工具的相关内容 官方文档 了解git仓库的相关内容 了解rollup的相关内容 工程结构包示例 Vue项目结构包下载-v4.7.xVue项目结构包下载-v5.2.x 工程结构详解 工程结构 ├── packages │   ├── kunlun-mobile-boot │   │   ├── package.json │   │   ├── public │   │   │   ├── favicon.ico │   │   │   └── index.html │   │   ├── src │   │   │   ├── main.ts │   │   │   └── shim-vue.d.ts │   │   ├── tsconfig.json │   │   └── vue.config.js │   ├── kunlun-module-mobile-demo │   │   ├── scripts │   │   │   ├── postpublish.js │   │   │   └── prepublish-only.js │   │   ├── src │   │   │   ├── index.ts │   │   │   └── shim-vue.d.ts │   │   ├── index.ts │   │   ├── package.json │   │   ├── rollup.config.js │   │   └── tsconfig.json │   └── kunlun-modules-mobile-demo │   ├── scripts │   │   ├── build.config.js │   │   ├── postpublish.js │   │   └── prepublish-only.js │   ├── packages │   │   ├── module-demo1 │   │   │   ├── index.ts │   │   │   ├── package.json │   │   │   ├── rollup.config.js │   │   │   └── src │   │   │   ├── index.ts │   │   │   └── shim-vue.d.ts │   │   ├── module-demo2 │   │   │   ├── index.ts │   │   │   ├── package.json │   │   │   ├── rollup.config.js │   │   │  …

    前端 2023年11月1日
    2.1K00
  • 自定义mutation时出现校验不过时,如何排查

    场景描述 用户在自定义接口提供给前端调用时 @Action(displayName = "注册", bindingType = ViewTypeEnum.CUSTOM) public BaseResponse register(UserZhgl data) { //…逻辑 return result; } import java.io.Serializable; public class BaseResponse implements Serializable { private String code; private String msg; public BaseResponse() { } public BaseResponse(String code, String msg) { this.code = code; this.msg = msg; } public String getCode() { return code; } public void setCode(String code) { this.code = code; } public String getMsg() { return msg; } public void setMsg(String msg) { this.msg = msg; } } gql执行时出现报错 { "errors":[ { "message":"Validation error of type SubSelectionNotAllowed: Sub selection not allowed on leaf type Object of field register @ 'zhglMutation/register'", "locations":[ { "line":3, "column":3 } ], "extensions":{ "classification":"ValidationError" } } ] } 解决方案 1.返回对象不为空时,对象必须是模型,否则无法解析返回参数2.前端调用GQL异常时,可以用Insomnia工具对GQL进行测试,根据错误提示对GQL进行修改和排查3.GQL正常情况下,执行以后可根据后端日志进行错误排查

    2023年11月1日
    2.1K00
  • GraphQL请求详解(v4)

    阅读之前 什么是GraphQL? Oinone官方解读GraphQL入门 可视化请求工具 insomnia下载 概述 (以下内容简称GQL) 众所周知,平台的所有功能都是通过一系列元数据定义来驱动的,而GQL作为服务端和客户端交互协议,其重要性不言而喻。下面会从以下几个方面介绍GQL在平台中是如何运作的: 服务端定义元数据生成GQL对应的schema 通过HttpClient发起一个GQL请求 通过window.open使用GET方式发起一个GQL请求 客户端泛化调用任意API服务 客户端通过运行时上下文RuntimeContext发起GQL请求 准备工作 在开始介绍GQL之前,我们需要定义一个可以被GQL请求的服务端函数,以此来介绍我们的相关内容。(对服务端不感兴趣的同学可以跳过代码部分) DemoModel.java @Model.model(DemoModel.MODEL_MODEL) @Model(displayName = "演示模型", labelFields = {"name"}) public class DemoModel extends IdModel { private static final long serialVersionUID = -7211802945795866154L; public static final String MODEL_MODEL = "demo.DemoModel"; @Field(displayName = "名称") private String name; @Field(displayName = "是否启用") private Boolean isEnabled; } DemoModelAction.java @Model.model(DemoModel.MODEL_MODEL) public class DemoModelAction { @Action(displayName = "启用") public DemoModel enable(DemoModel data) { data.setIsEnabled(true); data.updateById(); return data; } @Action(displayName = "禁用") public DemoModel disable(DemoModel data) { data.setIsEnabled(false); data.updateById(); return data; } } 上面的java代码定义了演示模型的字段和动作: 字段 field id:ID 整数 Integer name:名称 字符串 String isEnabled:是否启用 布尔 Boolean 动作 action enable:启用 提交动作 ServerAction disable:禁用 提交动作 ServerAction 服务端定义元数据生成GQL对应的schema 模型和字段 type DemoModel { id: Long name: String isEnabled: Boolean } 动作 type DemoModelInput { id: Long name: String isEnabled: Boolean } type DemoModelQuery { queryOne(query: DemoModelInput): DemoModel …… } type DemoModelMutation { enable(data: DemoModelInput): DemoModel disable(data: DemoModelInput): DemoModel …… } PS:平台内置了多种Query和Mutation定义,通过模型继承关系将自动生成,无需手动定义。比如Query定义包括queryOne、queryPage等;Mutation定义包括create、update等。特殊情况下,默认逻辑无法满足时,服务端通常采用函数重载的方式进行替换,客户端则无需关心。 生成规则 type DemoModel:通过模型编码demo.DemoModel取.分隔后的最后一位,并转换为大驼峰格式。字段与声明类型一致。 type DemoModelInput:动作入参定义,未做特殊声明的情况下与模型定义一致。 type DemoModelQuery和type DemoModelMutation:Query和Mutation为固定后缀,分别生成动作相关类型。当函数类型为QUERY时,使用Query后缀,其他情况使用Mutation后缀。 (此处仅做简单解释,详细生成规则过于复杂,客户端无需关心) Query类型的GQL示例 query { demoModelQuery { queryOne(query: { id: ${id} }) { id name isEnabled } } } Mutation类型的GQL示例 mutation…

    2023年11月1日
    2.5K00
  • 移动端端默认布局模板

    默认布局 表格视图(TABLE) <view type="TABLE"> <view type="SEARCH"> <element widget="search" slot="search" slotSupport="field"> <xslot name="searchFields" slotSupport="field" /> </element> </view> <pack widget="group" class="oio-m-default-view-element" style="height: 100%;flex: 1;overflow-y: hidden;" wrapperStyle="height: 100%;box-sizing:border-box;"> <pack widget="row" style="height: 100%;"> <pack widget="col" mode="full" style="min-height: 234px;height: 100%;"> <element widget="table" slot="table" slotSupport="field" checkbox="false"> <xslot name="fields" slotSupport="field" /> <element widget="rowActions" slot="rowActions" /> </element> </pack> </pack> </pack> <element widget="actionBar" slot="actionBar" slotSupport="action"> <xslot name="actions" slotSupport="action" /> </element> </view> 表单视图(FORM) <view type="FORM"> <element widget="form" slot="form"> <xslot name="fields" slotSupport="pack,field" /> </element> <element widget="actionBar" slot="actionBar" slotSupport="action"> <xslot name="actions" slotSupport="action" /> </element> </view> 详情视图(DETAIL) <view type="DETAIL"> <element widget="detail" slot="detail"> <xslot name="fields" slotSupport="pack,field" /> </element> <element widget="actionBar" slot="actionBar" slotSupport="action"> <xslot name="actions" slotSupport="action" /> </element> </view> 画廊视图(GALLERY) 默认内嵌布局(inline=true) 内嵌表格视图(TABLE) 内嵌表单视图(FORM) 内嵌详情视图(DETAIL) <view type="DETAIL"> <element widget="detail" slot="detail"> <xslot name="fields" slotSupport="pack,field" /> </element> </view>`

    2024年12月11日
    2.9K00
  • 前端graphql拼接复杂的数据类型结构

    在前端开发中,有时需要自定义视图,但手写 GraphQL 查询语句非常繁琐,特别是当查询很复杂时。本文将介绍如何使用平台内置的API buildSingleItemParam 来简化这个过程。 使用方法 buildSingleItemParam 方法接受两个参数: 字段结构 数据 下面是一个示例代码: import { IModelField, buildSingleItemParam } from '@kunlun/dependencies'; const onSaveViewData = async (data) => { // 定义字段的数据结构 const modelFields = [ { name: 'conversationId', ttype: ModelFieldType.String }, { name: 'msgId', ttype: ModelFieldType.String }, { name: 'rating', ttype: ModelFieldType.Integer }, { name: 'tags', ttype: ModelFieldType.OneToMany, modelFields: [ { name: 'id', ttype: ModelFieldType.String }, { name: 'name', ttype: ModelFieldType.String } ] }, { name: 'text', ttype: ModelFieldType.String } ] as IModelField[]; // 构建 GraphQL 查询语句 const gqlStr = await buildSingleItemParam(modelFields, data); const gqlBody = `mutation { chatMessageFeedbackMutation { create( data: ${gqlStr} ) { conversationId msgId rating tags { id } text } } }`; // 向服务器发送请求 const rst = await http.query('ModuleName', gqlBody) // todo }; // 调用示例 onSaveViewData({ conversationId: '12', msgId: '123', tags: [ { id: '122', name: '222' }, { id: '122', name: '222' } ] }); 以上是使用 buildSingleItemParam 简化 GraphQL 查询语句的示例代码。通过这种方式,我们可以更高效地构建复杂的查询语句,提高开发效率。

    2023年11月1日
    3.1K00

Leave a Reply

Please Login to Comment