Closed lfborjas closed 3 years ago
Unfortunately, this is the case right now, scalars are hard-coded. The main reason is not serving them, which can be extended with IntrospectTypeRef
, but parsing them from the GraphQL file: how would the graphql
template know that DateTime
corresponds to Haskell's LocalDateTime
? 🤔
Maybe we should invent some way to inject that knowledge at GraphQL schema parsing time. I'm sure we can find a solution, we know the information, we just need to send it to the right places! 😀
@lfborjas I've started doing some preliminary investigation on this on #295. Hopefully this will turn into an easy way to extend the set of scalars in GraphQL.
In the meanwhile, what is the interface you expect for DateTime
, is there a spec for it? Apart from adding a way to extend the scalars, I think that adding DateTime
as part of the basic set of scalars would be good!
That's amazing Alejandro, thank you!
You know, I haven't really found anything authoritative for date/time in graphql (though I did run into this fancy thing they do in grandstack.io, which indicates that in their design DateTime
if a fully fledged type, not a simple scalar!). It would seem that the general sentiment is "roll your own"? (EDIT: I'm not sure of how authoritative this resource is, but there's at least one library out there that defines Date and DateTime scalars for graphql using RFC3339 strings: https://www.graphql-scalars.dev/docs/scalars/date-time)
As expanded upon below, by way of a spec, I personally am just imagining the simple ISO8601/RFC3339-looking formatted strings that Haskell's aeson/swagger2 work with; though as I researched a bit to answer you, it does seem that DateTime
opens the pandora's box of "there's a ton of types for all kinds of time representations" 😅
In the service I'm working on, I already have a servant/swagger API, so I'm using as reference the FromJSON/ToJSON/ToSchema instances the underlying libraries provide for LocalTime
; in Haskell's Swagger2, they expect LocalTime
(which in my mind is the target type for the DateTime
scalar, though maybe I should be calling it LocalDateTime
since no timezone information is provided?) to be serialized/deserialized from/to strings as yyyy-mm-ddThh:MM:ss
-- instances for ZonedTime
, LocalTime
, TimeOfDay
, NominalDiffTime
, UTCTime
, etc. also exist, as linked before and also for the ToParamSchema class, which I think hews close to the notion of a gql scalar? I think if some date/time scalars are to be provided, it'd be cool if a reasonable subset of the usual cases of "time with timezone", "local time [i.e. time without timezone]", "date", "time", "utc time", and even "instant in seconds"/"instant in milliseconds or picoseconds" can be supported -- all of which correspond to types in Haskell's Data.Time
and which aeson/swagger2 recognize.
In my particular service I only use UTCTime
for server responses (as linked above, this is serialized as "yyyy-mm-ddThh:MM:ssZ"
) and LocalTime
(for user input, parsed as "yyyy-mm-ddThh:MM:ss"
-- the users also provide their location/IP so I derive the timezone.) I reckon in the more general/sane case, to save oneself from timezone hell, one would probably want to transact in UTCTime
only, or in ZonedTime
if the client can reliably provide the tz offset, or maybe even just an integer instant as a unix epoch or milliseconds, for which I think Haskell's DiffTime
/NominalDiffTime
are applicable 🤔
Hi there. Thank you very much for this excellent collection of libraries! Watching Alejandro's videos about the graphql capabilities inspired me to write my latest service in GraphQL, using
mu-graphql
!However, I'm stuck on something:
In my schema, I'm planning to include a
DateTime
scalar that I would like to map to aLocalTime
in Haskell. As per the graphql spec, here's an example schema:I'm not quite sure what to tell the Haskell side, however; I tried adding a naïve mapping:
Where
LocalDateTime
is anewtype
overLocalTime
(fromData.Time
). If I omit the mapping, the generated type seems to infer that the type of theDateTime
argument in the query is()
.The crux of the matter is: I don't quite know how to wire it up: what to tell my
resolver
so it can actually act on that mapping: should I usemethod
at the top level? That doesn't seem right, since it's a type, not a query/mutation -- and If I do that, I getcould not find method "DateTime"
errors, as well as:No instance for (mu-graphql-0.5.0.2:Mu.GraphQL.Query.Parse.ParseArg
, anyway 😅If I try a wild guess and derive schema instances manually, while keeping the mapping:
I get "cannot find type 'DateTime' in the schema" errors in addition to the previous ones, which seems to point to it not being recognized, maybe? But at this point, I'm just flailing: it's just not clear to me how an arbitrary scalar is supposed to be "wired into" the mechanism, short of writing the schema by hand? I'm happy to write the instances of
FromSchema
andToSchema
by hand, since it would make sense to be responsible for how the Strings that are sent over the wire egress/ingress Haskell-land, but I think I'm stuck at an earlier stage than that.I initially resisted using morpheus because of the proliferation of types it promotes, but I do like how they handle scalars: https://github.com/morpheusgraphql/morpheus-graphql#scalar-types (in Servant-land, I would also have just done a bit of instance carpentry for a custom type, though in the specific case of
LocalTime
, the necessary instances already exist for JSON/HttpApiData.)I see there's a relatively recent PR in which you added
JSON
scalars explicitly to the source, does that indicate that arbitrary scalars are not supported without a similar, explicit, update/extension to internals?