maarekj / rescript-apollo-client

ReasonML / BuckleScript bindings for the Apollo Client ecosystem

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

⚠️ NOTICE: This package recently changed and is now published as rescript-apollo-client!

Logo

ReScript bindings for the Apollo Client ecosystem

npm version

DocumentationInstallationQuick StartExamplesContributing

Documentation

Go to the official documentation site (work in progress)

Installation

1. graphql-ppx

We rely on Graphql-ppx for typesafe GraphQL operations and fragments in ReScript. Go to the official documentation for installation instructions.

You should now have a graphql_schema.json in your project somewhere. Make sure it's always up-to-date!

2. Apollo Client

npm install rescript-apollo-client @apollo/client

3. Apollo-Specific graphql-ppx Configuration

Add the following under bs-dependencies and graphql, in your bsconfig.json

{
  "graphql": {
+   "apolloMode": true,
+   "extendMutation": "ApolloClient.GraphQL_PPX.ExtendMutation",
+   "extendQuery": "ApolloClient.GraphQL_PPX.ExtendQuery",
+   "extendSubscription": "ApolloClient.GraphQL_PPX.ExtendSubscription",
+   "templateTagReturnType": "ApolloClient.GraphQL_PPX.templateTagReturnType",
+   "templateTagImport": "gql",
+   "templateTagLocation": "@apollo/client"
  },
  "ppx-flags": ["@reasonml-community/graphql-ppx/ppx"],
  "bs-dependencies: [
    "@reasonml-community/graphql-ppx"
+   "rescript-apollo-client"
  ]
}
  • "apolloMode" automaticaly sprinkles __typename throughout our operation and fragment definitions
  • "templateTag*" is how we tell graphql-ppx to wrap every operation with gql
  • "extend*" allows rescript-apollo-client to automatically decorate the generated modules with Apollo-specific things like the correct hook for that operation!

Quick Start

Other than some slightly different ergonomics, the underlying functionality is almost identical to the official Apollo Client 3 docs, so that is still a good resource for working with this library.

The EXAMPLES/ directory is the best documentation at the moment (real docs are literally in progress), but in short, the appropriate hook is exposed as a use function on the module generated by graphql-ppx. Variables are always the last argument:

module TodosQuery = %graphql(`
  query Example ($userId: String!) {
    user(id: $userId) {
      id
      name
    }
  }
`)

@react.component
let make = () =>
  // The useQuery hook is automatically exposed on the module generated by graphql-ppx
  switch ExampleQuery.use({userId: "1"}) {
    | {data: Some({users})} =>
    ...
  }
}

It's probably worth noting this library leverages records heavily which allows for very similar syntax to working with javascript objects and other benefits, but comes with a downside. You may need to annotate the types if you're using a record in a context where the compiler cannot infer what it is. The most common case is when using a non-T-first api like Js.Promise. For this reason we expose every type from the ApolloClient.Types module for convenience. Example:

  let queryResult = SomeQuery.use()

  // I can destructure or access properties just like javascript, and also pattern match!
  switch queryResult {
    | {loading: true} =>
      // Show loading
    | {data: Some(data), fetchMore} =>
      let onClick = _ => fetchMore()
      // Show data
  }

  // Annotation is necessary in some cases
  apolloClient.query(~query=(module SomeQuery), ())
  |> Js.Promise.then(result => // Hover over the type and you can see it is an ApolloQueryResult.t__ok
    // Let's open the module so the record fields are accessible
    open ApolloClient.Types.ApolloQueryResult
    // ☝️ You don't have to go searching for a type, everything is accessible under ApolloClient.Types
    switch result {
    | Some(apolloQueryResult) =>
      Js.log2("Got data!", apolloQueryResult.data)
    | Error(_) =>
      Js.log("Check out EXAMPLES/ for T-first promise solutions that don't have this problem!")
    }
  )

Recommended Editor Extensions (Visual Studio Code)

vscode-reasonml-graphql provides syntax highlighting, autocompletion, formatting and more for your graphql operations

vscode-graphiql-explorer provides a visual interface to explore the schema and generate operations

Bindings to JavaScript Packages

Contains partial bindings to the following:

While we strive to provide ergonomics that are intuitive and "reasonable", the intent is to also expose a 1:1 mapping to the javascript package structures if that is your preference. For instance, if you're looking in the Apollo docs and see import { setContext } from '@apollo/link-context' and you'd prefer to interact with this library in the same way, you can always access with the same filepath and name like so:

module Apollo = {
  include ApolloClient.Bindings
}

// import { setContext } from '@apollo/client/link/context'
let contextLink = Apollo.Client.Link.Context.setContext(...)
// import { createHttpLink } from '@apollo/client'
let httpLink = Apollo.Client.createHttpLink(...)

For comparison, this library packages things up into logical groups that have a consistent structure with the intent to be more disoverable and less reliant on docs:

// Make a generic link
let customLink = ApolloClient.Link.make(...)
// Specific link types are nested under the more general module
let contextLink = ApolloClient.Link.ContextLink.make(...)
// See, they're all the same :)
let httpLink = ApolloClient.Link.HttpLink.make(...)

About This Library

Apollo bindings in the Reason / BuckleScript community are pretty confusing as a write this (July 14, 2020), so it's worth providing some context to help you make the right decisions about which library to use.

This library, rescript-apollo-client, targets Apollo Client 3 and aims to take full advantage of v1.0.0 graphql-ppx features and is intended to be a replacement for reason-apollo and reason-apollo-hooks. You should avoid using those libraries at the same time as this one.

If you have a large code base to migrate from reason-apollo-hooks, it might make sense to upgrade to the reason-apollo-hooks PR that adds support for graphql-ppx 1.0 first. This PR has been used by some larger companies to gradually upgrade.

Alternatives

reason-apollo, despite being under the apollographql github org, doesn't have any official Apollo team support behind it and currently seems like it may be abandoned. It binds to the react-apollo js package and some of the older apollo packages not under the @apollo npm namespace.

reason-apollo-hooks is the hooks companion to the reason-apollo library and binds to @apollo/react-hooks. Given the lack of development on reason-apollo, there has been a lot of active contribution pulling reason-apollo features in there. It's fairly battle-tested and it provides a nice, simple interface to hooks. It's not currently compatible with graphql-ppx v1.0.0, but there is a branch that adds basic support for it.

Contributing

Lets work to make the Apollo experience in ReasonML the best experience out there! This is a solid base, but there's a lot of low-hanging fruit remaining—more bindings, docs, examples, tests, better ergonomics—there's so much left to do! Check out the Contributing Guide or issues to get started.

About

ReasonML / BuckleScript bindings for the Apollo Client ecosystem

License:MIT License


Languages

Language:ReScript 96.0%Language:JavaScript 2.7%Language:CSS 1.2%Language:HTML 0.1%