How can I return a Decimal type from my backend GraphQL server and then parse it on my frontend client?
I have a backend that returns a product with a price. The price is a custom scalar of Decimal type.
The schema is like so:
scalar Decimal
type Product {
id: ID!
price: Decimal
}
I have a custom resolver for Decimal types in my backend that looks like this:
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;
}
});
My backend then returns JSON like so:
[
{
id: "product_1",
price: "12.22" // should this be returning a `__typename: Decimal` some how?
},
{
id: "product_2",
price: "18.05"
}
]
The problem is my front end app recieves this data and thinks price is a string. I would like to parse price back to Decimal type.
I have included a Decimal scalar in my apollo client in order to try parse the value:
// 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
])
});
This doesn’t seem to parse the value at all:
console.log(typeof data?.getProducts?.[0].price) // string (price is of type any according to TypeScript)
Since my price
value has no __typename
, how is Apollo supposed to know to parse price as a DecimalScalar?
Is it correct that the JSON value returned for price is just a string or should it include some __typename: "Decimal"
or something?
Have I got the correct implementation of decimalScalar parser in my Apollo client?
Any help would be greatly appreciated, thanks.