How can I parse a custom scalar in Apollo Client?

How can I parse a custom scalar in Apollo Client?


0

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.


Load 6 more related questions


Show fewer related questions

0



Leave a Reply

Your email address will not be published. Required fields are marked *