← Back to lab
Lab

graphql-scalars

A custom scalar should reject what can be judged from the value alone and pass everything else through to the resolver.

↓

Where a scalar runs

A scalar's parse functions run before any resolver, and whatever they do not reject, every resolver receives as valid. graphql-scalars, the shared library of custom scalars, takes no runtime dependencies: when one was proposed for the ULID scalar, the maintainers declined and suggested copying the reference function instead. Four scalars went in under that constraint.

What each checks

  • GeoJSON: an object or a JSON string; all seven geometry types plus Feature and FeatureCollection; positions of two or three numbers with longitude within ±180 and latitude within ±90; a LineString of at least two positions; a Polygon ring of at least four that ends where it starts; a bbox of four or six numbers.
  • CountryName: a fixed list of 246 ISO 3166-1 English short names, matched case-sensitively after trimming.
  • ULID: a regular expression requiring a first character of 0–7 and Crockford base32, matched case-insensitively and uppercased on output.
  • Cuid2: a separate scalar from Cuid, format only.

What they leave out

  • GeoJSON does not check winding order, self-intersection, whether a bbox matches its geometry, or crs. A polygon that crosses itself is valid GeoJSON at the schema boundary.
  • CountryName rejects anything not on a list that is maintained by hand.
  • Two corrections to the GeoJSON scalar, its codegen type and its mock values, are open upstream.

Where it stops holding

Shape validation at the scalar holds for values whose validity is a property of the string: an identifier format, a coordinate range. Where validity depends on the value as a whole, a polygon's geometry, or on a list that changes with the standard, the scalar either takes a dependency the library refuses or passes the value on. A resolver that consumes a GeoJSON polygon checks its geometry itself.

Up next
Slippage tolerance derived from staleness→