Fork me on GitHub
#graphql
<
2019-01-31
>
hiredman01:01:16

oops, sorry, for an update I spent this morning trying to put together a simple example test case, having it not fail, and determining it was something stupid I did

Chris07:01:48

We are making a GraphQL gateway and have got a bit stuck with async. If we use callbacks then it’s difficult to ensure correct error handling, but if we use some async abstraction library we’re stuck making a lot of adapters. I wondered how are other Lacinia users addressing this problem?

stijn14:01:56

@cbowdon we use manifold in our resolvers and wrap each resolver in a function that turns a deferred into a lacinia promise. Manifold has a nice way of handling errors.

oliy14:01:44

there used to be a thing called :decorators in lacinia which i think would give you what you need. according to the changelog they were removed because they'd be more easily expressed in code

👍 5
oliy14:01:29

i don't know what the recommended approach might be now, unless you map over your resolver map and comp the resolver functions with your adapter stuff before attaching them

stijn17:01:16

Yes, that's exactly what we're doing

hiredman17:01:57

I've got a function that takes a core.async channel and returns something that satisfies the ResolverResult protocol, so the body of all my resolve functions starts like (f (go ...))

frank17:01:25

:thinking_face: what do you mean by "correct" error handling? What are the challenges you expect to encounter?

hiredman17:01:29

exceptions don't compose well with a lot of the tools available for async

frank17:01:00

ah I see.

hiredman17:01:42

but exceptions also don't compose well with a lot of other coding styles, and the most common solution is to usually turn errors in to special return values and don't use exceptions

hlship18:01:51

We often follow the pattern of conveying either a result or an exception through the channel, which complicates the code that takes the conveyed value ... sometimes a macro helps to sort that out. It also can cause problems if the channel is part of a pipeline that can be tripped up when a value in the channel isn't the expected map or vector.

frank17:01:07

We've got a middleware stack that wraps our resolvers. One of the middlewares is responsible for invoking the resolver in a claypoole future and returning a lacinia promise. Basically, it takes a synchronous resolver and returns an async one. Another middleware (further "in" the stack) wraps the resolver in a try/`catch` for exception handling. The resolvers themselves do not have any sort of async code, so we don't experience any clashing between exception handling and async