Idea Feedback: Apollo Elm Package

ApolloGraphQL - is a very popular library for handling lots of concerns around the consumption and creation of GraphQL API’s. Apollo Client specifically handles client-side challenges of using graphQL. I have used it myself on some side projects and find it incredibly useful as it handles paging, caching and local state management with ease.
Most popular frameworks do have an integration layer with it - https://www.apollographql.com/docs/react/integrations.html
I was wondering would there be enough interest to work on a library to use Apollo Client with Elm?

I don’t think it’s possible to write such a package, because it would require the package to use native js code (apollo-client). And you should not cannot use js code in elm packages: Every package on package.elm-lang.org is written entirely in Elm.

1 Like

At the risk of sounding a bit hash, why? Just to be listed on the Apollo Client site? What’s the value your looking for? Just curious :slight_smile:

Judging from https://www.youtube.com/watch?v=8Pyr82Qbjow it’s similar to https://package.elm-lang.org/packages/dillonkearns/elm-graphql/latest/ which is an awesome package I can highly recommend. Really enjoying the workflow.

I switched my elixir + elm stack from a rest + swagger setup to graphQL (absinthe) + dillonkearns/elm-graphql.
Implementing changes or features is a breeze.

1 Like

I do understand that. I was thinking of embedding Apollo client with help of web components - isn’t it possible in a package ?

It provides a bit more than just client side library to access GraphQL. Which in my understanding what library that you reference is.
See their own description of features:


And also https://www.apollographql.com/docs/react/features/pagination.html

I think Apollo is an awesome project. And I would love to have all the features in an elm package. A mentioning on theire site would be nice. dillonkearns package looks great too. dillonkearns package looks like it has everything I would need from an graphql package and more. But that is not the point.

You cannot have js code in an elm 0.19 package because you would lose some of the guarantees elm gives us. "Native Code" in 0.19

Dead code elimination in packages for js code would be lost too. See 0.19 release notes.

I don’t know about web components. Never used them before.

I’m not sure what you have in mind as the distinction between a client-side library to access GraphQL versus Apollo. The way I would describe it is that both Apollo and dillonkearns/elm-graphql are tools for performing GraphQL queries. They have some features in common, and some features are only in one or the other but not both.

Here are some features that dillonkearns/elm-graphql has which Apollo does not:

  • Provides a high-level DSL for making queries, which allows you to use Elm language constructs to build and abstract your GraphQL queries (Apollo queries are built with plain strings with a JSON object passed in for variables)
  • Rather than just grabbing raw JSON data, you build up your data into meaningful data structures (much like you do with JSON decoding in Elm)
  • You get Elm compiler errors if your query is invalid
  • You get documentation in your editor as you build up queries (the autogenerated functions have doc comments with the docs from your GraphQL API)
  • You can do exhaustive onType ... selections for unions and interfaces (the compiler will tell you if you add a new type on the back-end that you don’t handle on the client-side, and you don’t get a Maybe something back because it knows you’ve handled every possibility)
  • It handles creating aliases for you to prevent collisions automatically (see this blog post)

See this blog post for an overview of some of these features:

To me, these are all really important features, and they make using GraphQL in Elm the best GraphQL experience I’ve had (for my particular needs and tastes), including Apollo.

Should Apollo be Ported to Elm?

@Maxim-Filimonov I’ll share my thoughts here on API design in Elm in general, and GraphQL APIs in Elm specifically. I hope they contribute to the conversation here and shed light on the question of whether Apollo should be ported to Elm.

API Design in Elm

I’ve found that my APIs turn out to be far more useful and intuitive when I do the following

  1. Understand existing solutions (looking at Apollo is a good start here)
  2. Look at concrete Elm code which has a specific problem
  3. Try to solve that specific problem (not a general class of problems, often it’s helpful to extract from real code to ensure that you’re solving a real problem in a way that addresses it well)

In designing dillonkearns/elm-graphql, I really tried to consider how GraphQL queries would best be served by Elm code. I wanted to make it idiomatic, and I wanted to leverage the strengths of the Elm language and stay true to its philosophy.

Joël put it really nicely:

https://twitter.com/joelquen/status/1067455474096844800?s=21

I’ve got some more thoughts on API design in Elm here:

Apollo Idioms Compared to Elm Idioms

Let’s consider would make a GraphQL library fit nicely into Elm. To me, as a user, I find it really important to be able to get the Elm compiler giving me strong guarantees and leveraging the fact that I’ve got a typed schema for my API. This is challenging with Apollo because it uses Strings to build up queries, and in the context of JavaScript there are escape hatches and blind spots even if you add some sort of typing on top of it (like a GraphQL linter, or TypeScript).

Also, consider this element of the Elm philosophy:

There are worse things than being explicit

https://twitter.com/czaplic/status/928359289135046656?s=20

Compare this to Apollo. In my opinion, Apollo values the opposite thing. It would rather be convenient and have you memorize a few bits of magic that it does, rather than be explicit and have everything it’s doing be clearly traceable. This is similar to the Rails philosophy to “Provide sharp knives”. Some people really like this about Rails. For me, it made Rails development much more difficult because I had a lot to remember and think about when I wrote Rails code. I find the same to be true when I use Apollo.

I really like the elegance of having straightforward, non-clever libraries that can be easily traced, and I believe that this is the experience you get with dillonkearns/elm-graphql. In fact, if you tried to make some magic happen with an Elm library (as you would if you ported Apollo to Elm), I think you wouldn’t be able to get a lot of the benefits of the magic because of the design of Elm, and it would not feel idiomatic because it isn’t in line with the Elm philosophy.

Apollo-Specific Features in Elm

Let’s look at these specific features you point to and discuss how they would fit into Elm.

Pagination

I think this would be a great feature! In fact, I opened up a thread to brainstorm this a while back. I welcome any ideas, and in particular I would love to collect some real-world code.

I have a pagination example in the examples folder. I would love to discuss some tools that could be provided by dillonkearns/elm-graphql to make this experience easier.

I think it would be more explicit than with Apollo because of the constraints of the Elm language. To me that’s a good thing, and I think it could be just as convenient and more robust.

Local State Management

This doesn’t strike me as something that would be useful in the context of Elm and dillonkearns/elm-graphql. If you think it would be, then I would request some meaningful code examples that illustrate a pain-point here, and then we can have a discussion of how it could be improved! But really, I think that the fact that working with dillonkearns/elm-graphql let’s you build up meaningful, custom data structures in a type-safe way means that it’s actually quite easy to pass around those data structures alongside data from other non-GraphQL sources.

Caching

A few people have suggested adding this feature into dillonkearns/elm-graphql before. I always welcome discussions about possible improvements, but I can’t really do much with a general suggestion, I need some concrete problems and real-world code to understand how to improve that particular situation. When people have presented this particular problem, I’ve asked to get some more background to help understand how not having caching is a performance bottleneck in their app. Each time it’s been suggested so far, it turned out it actually wasn’t a bottleneck, they just thought it would be a nice feature.

I’d love to discuss this if there is someone who has a real need for this and can help me understand their situation. I have a feeling that the solution in the context of Elm would look quite different from Apollo’s answer. Because of the explicitness in the Elm language and ethos, I suspect that you could explicitly refresh data when you perform a mutation using some simple Elm code rather than a magic feature that automatically invalidates cache for you. Again, it’s hard to say without looking at real code that has this problem.

I hope that contributes to the conversation you wanted to have here! Cheers!

19 Likes

Thanks a lot for a very detailed response. I’m flying to a retreat tomorrow morning and won’t be back for another week, and then I’d definitely be keen to pick up the discussion and find where we can learn from Apollo experience and see if it fits elm context.

I have added a comment on the issue. Let me know what you think.

You might be right here. I’m thinking more in terms of things like schema stitching when we combine graphql responses from different sources, though Elm does it by default as we are not treating GraphQL objects special in any way, they are just part of a big model.

Referring to GraphQL tutorial with apollo if you look at the part where their update cache.
See _updateCacheAfterVote function.
They have a model like
Link – has many – votes

const VOTE_MUTATION = gql`
  mutation VoteMutation($linkId: ID!) {
    vote(linkId: $linkId) {
      id
      link {
        votes {
          id
          user {
            id
          }
        }
      }
      user {
        id
      }
    }
  }
`

The mutation sends back the updated link already so the use case for cache here is to find and update the cache for that specific link without refetching all links. They are actually not using Apollo cache properly in this tutorial as all cache updating is not required if one changes mutation to:

const VOTE_MUTATION = gql`
  mutation VoteMutation($linkId: ID!) {
    vote(linkId: $linkId) {
      id
      link {
        id
        votes {
          id
          user {
            id
          }
        }
      }
      user {
        id
      }
    }
  }
`

It’s kinda hard to spot the difference. It’s this part:

   link {
        **id**

as soon as we add id apollo cache will automatically find all instances of link with that specific id and update them with the fields returned from this mutation. Manual cache update in this tutorial is very close to the code which one would need to write when using elm-graphql package.
Not sure it fits with Elm philosophy, having explicit updateCache(link) would still work for me to be honest. Trying to find all entries of that specific Link manually in a multi-page application can get quite cumbersome and error-prone.

1 Like

Hello @Maxim-Filimonov, thanks for posting the example from the docs. That’s a great starting point for a conversation. I think it could still be more concrete and could lead to better understanding if we actually build a simple example that demonstrates what a similar query would look like with Elm code. That is, make a query, then perform a mutation that would invalidate the queried data. Then using the existing functionality in dillonkearns/elm-graphql, perform the query again. What’s the nicest we could make that look? Then, with that concrete code in front of us, we can discuss what it would look like in the context of Elm to automatically bust the cache. And we could discuss what wiring it would require, and whether it would actually be better with the “automagic” cache-invalidation, or whether explicit cache invalidation is good enough. I’m not sure what the answer will be, but I think we need to look at what solving this problem by hand would look like before we can say either way.

And thank you for posting in the pagination thread on Github, I would love to come up with some ideas there!

This topic was automatically closed 10 days after the last reply. New replies are no longer allowed.