如何在 Apollo 客户端中解析自定义标量?

问题描述 投票:0回答:1

如何从后端 GraphQL 服务器返回 Decimal 类型,然后在前端客户端上解析它?

我有一个返回带有价格的产品的后端。价格是十进制类型的自定义标量。

架构如下:

scalar Decimal

type Product {
  id: ID!
  price: Decimal
}

我的后端有一个用于十进制类型的自定义解析器,如下所示:

const decimalScalar = new GraphQLScalarType({
  name: "Decimal",
  description: "Decimal custom scalar type",
  serialize(value: number) {
    return new Decimal(value);
  },
  parseValue(value: number) {
    return new Decimal(value);
  },
  parseLiteral(ast) {
    if (ast.kind === Kind.FLOAT) {
      return new Decimal(parseFloat(ast.value));
    }
    return null;
  }
});

我的后端返回 JSON,如下所示:

[
  {
    id: "product_1",
    price: "12.22" // should this be returning a `__typename: Decimal` some how?
  },
  {
    id: "product_2",
    price: "18.05"
  }
]

问题是我的前端应用程序收到此数据并认为价格是一个字符串。我想将价格解析回十进制类型。

我在我的 apollo 客户端中包含了一个十进制标量,以便尝试解析该值:

// DecimalScalar.ts
import { GraphQLScalarType, Kind } from 'graphql';
import Decimal from 'decimal.js';

const decimalScalar = new GraphQLScalarType({
  name: 'Decimal',
  description: 'Decimal custom scalar type',
  serialize(value: number) {
    return new Decimal(value);
  },
  parseValue(value: number) {
    return new Decimal(value);
  },
  parseLiteral(ast) {
    if (ast.kind === Kind.FLOAT) {
      return new Decimal(parseFloat(ast.value));
    }
    return null;
  }
});

export default decimalScalar;


// Apollo Client
const retryLink = new RetryLink();
const httpLink = new HttpLink({ uri: config.API_URL })
const apolloLink = new ApolloLink((operation, forward) => {
  operation.setContext({
    customScalars: {
      Decimal: {
        serialize: (value: number) => value.toString(),
        parseValue: (value: number) => new Decimal(value),
        parseLiteral: decimalScalar.parseLiteral,
      },
    },
  });
  return forward(operation);
})

const client = new ApolloClient({
  cache: new InMemoryCache(),
  link: ApolloLink.from([
    retryLink,
    httpLink,
    apolloLink
  ])
});

这似乎根本没有解析该值:

console.log(typeof data?.getProducts?.[0].price) // string (price is of type any according to TypeScript)

由于我的

price
值没有
__typename
,Apollo 应该如何知道将价格解析为 DecimalScalar?

价格返回的 JSON 值只是一个字符串,还是应该包含一些

__typename: "Decimal"
或其他内容,这是否正确?

我的 Apollo 客户端中是否正确实现了 DecimalScalar 解析器?

任何帮助将不胜感激,谢谢。

javascript reactjs typescript graphql apollo
1个回答
0
投票

graphql-scalars 包提供了大量开箱即用的自定义标量。它也是开源的,因此是一个很好的学习资源。

查看其 currency 类型的 implementation,它与您的 decimal 类型有些相似。

  1. 它的根类型是一个字符串,所以你在正确的轨道上
  2. 它没有
    __typename
    ,因为它是自定义标量,并且自定义标量没有类型名称

为了将正确的类型添加到客户端应用程序中,Apollo 发布了这个教程,介绍如何从架构(包括自定义标量)生成类型,以便客户端使用它们。

© www.soinside.com 2019 - 2024. All rights reserved.