GraphQL in Reason


#1

Hi :wave:

First of all: I am really new to Reason and its ecosystem but I already really like its philosophy and efforts. Thank you all for that!

I currently am debating, if I should use Reason for one of my projects. I already made my first steps in integrating it into my existing codebase and as I said, I really like it.

What is holding me back from fully committing to it right now is the integration with GraphQL.
I looked into https://github.com/baransu/graphql_ppx_re and https://github.com/apollographql/reason-apollo but with the current support of fragments it kind of feels unfinished. (I don’t know how to describe it in a better way).

So my question is, how are you currently handling the integration with GraphQL in a Reason-React app?

Thank you,
Torben :slight_smile:


#2

I think a lot of people are using graphql_ppx[_re]. Because of its design, it can’t handle fragments. If you really need fragments, there’s an alternative: https://github.com/sainthkh/reasonql


#3

Shameless self plug, but if you’re ok with using experimental stuff (the new React concurrent mode) and have a schema that supports it, there’s bindings for using Relay with ReasonML: https://reason-relay-documentation.zth.now.sh/docs/start-here


#4

graphql_ppx_re really works great for us. Due to the type system you don’t really need fragments to prevent under fetching. It’s still easier overfetch, and fragments make for a nicer DX. I’m actually interested to improve fragment support in graphql_ppx_re, and have some implementation ideas.


#5

So you are only using query and pass the data into into the children as props?
I thought about that approach too, but that would remove the colocation of data and implementation, which i would really miss.

Do you need any help with improving fragment support? I would be interested to help out (if i can).


#6

Yes, but you are passing the data as props anyway even when you are using fragments right (or am I missing something). I do agree it’s nice to colocate data requirements with the components that receive the data, and miss that too.

Also definitely check out @zth’s reason-relay if you can still choose the Graphql client. It’s super awesome, and the relay compiler is so powerful! Especially they are very early with adopting Suspense (nothing like that in Apollo land unfortunately).

We already adopted Apollo, so currently not an option for us. The upside of graphql_ppx_re/reason-apollo-hooks is that no code needs to be generated, as everything happens in a PPX.

I don’t specifically need help at the moment, but if you are interested you can start a PR, happy to collaborate, otherwise I’l start it at some point and it would be great if you could chime in on the PR. I am currently working on two PR’s to improve graphql_ppx_re:

  • This one - to decrease the javascript code that is being emitted (its a LOT at the moment, not ideal)

  • And a non-published one that adds tagged template literal support for better integration in the ecosystem, specifically building it for Gatsby integration, but it would make Apollo integration also better because it would allow for query extraction in a manifest.

So progressively I am getting to know the code base and it will be easier to tackle something like fragments. (The code base is pretty tricky to get into, as there is so much happening, and almost no documentation. Also PPX-s are hard to understand and almost no documentation around how to write a PPX. Not even a reference documentation.


#7

@zth reason-relay looks super cool, can’t wait to try it out!

Does the (unfinished) Using with schemas that don’t conform to the Relay spec
docs mean the server doesn’t need to be Relay-compatible if I can make do without the utilities for graphql connections (easy pagination?) and refetching? I haven’t had the chance to use Relay before, and I’m not sure how much Relay depends on Relay-spec-compliant servers for its core functionality. I’m interested in using reason-relay with Hasura for a subscription-heavy app.


#8

The PupilFirst project (https://github.com/SVdotCO/pupilfirst) extensively uses GraphQL and Reason. It would be a good place to look to see patterns used in production.

There is also a back-end GraphQL best practices, in the context of Reason’s static types, written by its author @harigopal at https://blog.harigopal.in/guides/a-complete-guide-to-setting-up-a-graphql-server-on-rails/


#9

PupilFirst looks like a very solid open learning platform. A bit like Open EdX, but more modern.


#10

What about writing a Relay compatible server in OCaml? Does OCaml GraphQL server have some support?

I saw that there’s relay support in Absinthe, the Elixir library for writing GraphQL servers.
Which other frameworks are production ready to write Relay compatible servers?


#11

@osener sorry for my late reply, I totally missed this!

So, basically yes, you can use ReasonRelay with any schema if you don’t care about pagination and some refetching abilities. I say some because you can still refetch fragments that are on the root Query type, so some refetching will work.
If you don’t have globally unique IDs you’ll also need to supply a getDataId function to the environment, where you combine __typename and the actual id to make the data id. Happy to provide an example if needed! I’ll also work more on that section of the docs soon to clarify things.

A subscription heavy app should work well even without conforming to the spec, probably only need to set up getDataId, but please try it and let me know!

I’m also working on updating the ReasonRelay docs as I just published a new version that uses records instead of Js.t (which means you can now pattern match properly) and automatically converts nullable/enums/unions, which should greatly simplify things!


#12

@bozhidar so, doing a fully Relay compliant server (fun fact: the Relay spec was actually recently promoted to official best practices for GraphQL, rather than just a spec for Relay) doesn’t really require any support from frameworks (even though that can of course simplify things). It means the following:

  1. Globally unique IDs, which basically mean that if an object has an id prop, it should be globally unique. This really make sense if you think about it - you’re not in a database table here contextually, you’re in a graph of nodes, where each node should be possible to identify somehow.

It’s commonly done by combining the object typename with it’s id and base64-encoding the result. Relay doesn’t care how it looks as long as the ID is globally unique. This should be easily doable in any setting.

  1. Connections. Connections are just a convention for how to structure pagination. This means that you could use anything “behind the scenes” for pagination using connections. Connections in the spec allow paginating both backwards and forwards, which scare a lot of people - just don’t implement backwards pagination if you don’t need it. Also, another tip from experience: Doing normal offset/limit based pagination behind the scenes is totally fine. Connections allow for a very optimized pagination by using cursors etc, but no need to overcomplicate things - a cursor could just as easily be an index in an array, a set of stringified current parameters, an offset or anything else the server can use to continue paginating.

  2. The Node interface. This means that any object that implement the Node interface has an id prop that’s globally unique and can be used to refetch that particular node through a unified node(id: ID!) prop on the schema root. This also scares many people, but it’s not that complicated. The node prop takes an id, and that ID is what you set it up to be in point 1 above. Let’s say it’s a base64 encoded combination of typename and database id. In the handler for node you’d then decode the base64, split the result into typename and database id, and viola, you know what type (typename) you’ll need to fetch a single node of, and you know what id of it to fetch. Really not that complicated. Also something that you don’t need a particular framework or language to implement, it’s just a GraphQL interface with some additional logic in the resolver.

Sorry for the wall of text, just figured I’d put this here in case anyone else is interested in this too. My experience is that people way overestimate how complex the Relay spec is to implement, or that it’s a complicated own thing of it’s own entirely. Just wanted to write a little about that.


#13

I’ve worked on a Django GraphQL server that complied to the described ID pattern. The front end was using Apollo and I knew that these base64 encoded combinations of type and id are related to Relay, I was just interested what else is specified by Relay and how much do web frameworks comply to this specification. It makes sense for most GraphQL or RESTfull apps to implement unique IDs and pagination.

I am also interested if:

  • The Relay client offers some advantages to Apollo and
  • ReasonRelay is a connection library to JS Reason, or is it a client completely written in Reason?

Elixir’s Graphql library Absinthe has a module for writing Relay compatible server. More info can be found here.