jeddeloh / rescript-apollo-client Goto Github PK
View Code? Open in Web Editor NEWReScript bindings for the Apollo Client ecosystem
License: MIT License
ReScript bindings for the Apollo Client ecosystem
License: MIT License
I just had a situation where it would be useful to read variables passed to a mutation from its update
function. The official TypeScript definitions state:
export type MutationUpdaterFunction<
TData,
TVariables,
TContext,
TCache extends ApolloCache<any>
> = (
cache: TCache,
result: Omit<FetchResult<TData>, 'context'>,
options: {
context?: TContext,
variables?: TVariables,
},
) => void;
https://github.com/apollographql/apollo-client/blob/main/src/core/types.ts#L170-L182
My use case is that I wanted to create a hook that uses MySharedMutation.use()
under the hood, passing it the update
function, so that users of that custom hook do not need to think how to update cache for that specific mutation.
let useMySharedMutation = MySharedMutation.use(~update=updateLogic)
/// later, somewhere else...
useMySharedMutation(/* options, without the need to specify `update` logic*/ { /*variables*/ })
Do you think it makes sense to add options
param to ReScript bindings as well? I'm asking because it would be a breaking change in the sense that all users of the update
param would need to update their functions passed to update
to include the third param ~options
.
Hi There,
I'm using a client (non-react/non-hook) query to run tests in jest and got the following error:
Invariant Violation:
"fetch" has not been found globally and no fetcher has been configured.
I saw that Apollo in javascript has an argument to directly pass the fetch
function:
The same argument doesn't seem to exist as a make()
argument for ApolloClient
.
let instance = {
open ApolloClient
make(
~cache=Cache.InMemoryCache.make(),
~connectToDevTools=false,
~uri=_ => graphql_api_address ++ "/graphql"
// should fetch argument be supported here?
(),
)
}
Is there a workaround to be able to use Apollo in jest tests?
Hey @jeddeloh!
As discussed in this forum post, we'd like to move active ReScript projects to their respective maintainer's github org to free up the reasonml-community org.
Would it be viable to move the repo to your personal / company github org? That way it's easier to tell if a project is actively maintained, especially if it is backed by a company.
You can then explicitly add contributors later on to keep collaboration going!
Let me know what you think!
cheers
Sadly no tests yet. Being a bindings library, it doesn't feel to me like tests using mocks will provide a lot of value. It probably needs to be fully end-to-end. I really like this idea to package up a simple Apollo server: https://github.com/zth/graphql-client-example-server and use that.
As can been seen in the documentation of Apollo , the previousData
property should be added in ApolloClient.Types.QueryResult
Hi There,
I'm using the hooks API for subscriptions in the following way:
let subscription = Queries.TraceSubscription.use({
< variables here >
},
~skip,
~fetchPolicy=NoCache
)
Then when I'm checking for changes, multiple updates occur with the same value:
React.useEffect1(() => {
Js.log(subscription)
// getting multiple "updates" with the same subscription value
}, [subscription])
Is this intended behavior?
I have a mutation that updates an entity. When passing input parameters I want one of the fields to be sent as Null. However, when I try to running something like this:
updateEntity({
id: id
exampleField: None
})
This is the variable object I find in the network request
operationName: "UpdateEntityField"
query: "mutation UpdateEntity($id: ID!, $field: String)
variables: {id: "exampleid"}
While I wanted to send something along these lines
operationName: "UpdateEntityField"
query: "mutation UpdateEntity($id: ID!, $field: String)
variables: {id: "exampleid", field: null}
I found a workaround for this which passes Js.Nullable.null->Obj.magic
instead of None
. I know this violent usage of Js.Nullable.null
is not the nicest way to handle this issue, but as we are passing this straight to the Javascript world I don't think this can cause any issues down the line. I think it would be better if we could introduce a better way to handle something like this and make it type-safe.
How do I get access to the query like it is requested to the server.
module TodosQuery = %graphql(`
query TodosQuery {
todos: allTodos {
id
text
completed
}
}
`)
Js.log(TodoQuery.queryString)
expected output:
"query TodosQuery {\n todos: allTodos {\n id \n text \n completed \n } \n }"
Hi,
Actually, I'm trying to use this module on the ground of Gatsby. I faced the one problem which is the error in process of building the static page. I guess the ws
is not existing in node env during building Gatsby static page.
So, I tried to add ~webSocketImpl
, but no gain.
Can you give me a tip to use a custom ws implementation? using JS modulews
or bs-ws
which is binding to ws
.
It's parametrically typed here (basically accepts any parameters). OR add it to the query extension?
Also we could accept normal variables instead of jsVariables
, so we don't have to manually convert it.
Is there any particular reason that this prop is missing from the binding?
Detailed explanation of it's usage can be found here:
apollographql/apollo-client#6760 (comment)
From the apollographql docs:
https://www.apollographql.com/docs/react/api/react/hooks/#nextfetchpolicy
Hi There,
I couldn't find if it's possible to bind to existing record types in hooks examples but have use a similar feature with reason-apollo-hooks
.
In reason-apollo-hooks
, you used to be able to annotate queries like this:
query myQuery {
vectorType @bsRecord {
x
y
}
}
This would prompt the compiler to look for a record type named vectorType
and bind that to GraphQL responses.
Trying to do the same thing in rescript-apollo
results in type errors when parsing GraphQL responses:
This has type:
array<
MyQuery.MyQuery_inner.t_myQuery_Type_subtype,
>
But somewhere wanted:
array<ReactHooksTemplate.Type.subtype>
Is there another way to explicitly bind graphql queries to records types that exist in my application?
Hello,
I just encountered a runtime error with the graphql-ppx use
hook, it appears that in a certain case when the ~skip
argument is passed as true
the NetworkStatus gets undefined.
Here's how I fixed it, I suggest these changes:
src/@apollo/client/core/ApolloClient__Core_NetworkStatus.re
module NetworkStatus = {
module Js_ = {
- type t = int;
+ type t = option(int);
};
[@bs.deriving jsConverter]
| [@bs.as 7] Ready
| [@bs.as 8] Error;
- let toJs: t => Js_.t = tToJs;
+ let toJs: t => Js_.t = (t: t) => Some(tToJs(t));
- let fromJs: Js_.t => t = string => tFromJs(string)->Belt.Option.getExn;
+ let fromJs: Js_.t => t =
+ optionalString => {
+ switch (optionalString) {
+ | Some(string) => tFromJs(string)->Belt.Option.getExn
+ | None => Ready
+ };
+ };
};
src/@apollo/client/core/ApolloClient__Core_Types.re
data,
error,
loading: js.loading,
- networkStatus: js.networkStatus->NetworkStatus.fromJs,
+ networkStatus: Some(js.networkStatus)->NetworkStatus.fromJs,
};
};
Thanks for the great contribution!
You can use @apollo/client
without react with @apollo/client/core
.
This lib binds to @apollo/client
. Would it be crazy to make this work with @apollo/client/core
?
Is that a whole different setup? I tried just changing the binding to @apollo/client/core
for the stuff exported from core
and it did not work so..
Thanks you, sir.
I'd really like to get a proper documentation site up. Some possibilities:
This is just a proposal, but there are three things I would love to be able to do:
reason-promise
or another library by default, but allow people to opt out or provide their own promise transformation functionRight now, turning all the file modules into functors seems like the only way to achieve this, but it's probably worth thinking about more.
Is this a good place to talk about next steps?
auth0/auth0-react#97 (comment)
To get the token from Auth0-React
library an async function has to be called. This is not possible with the current bindings.
Since the commit 8508e94 there is a bug in function ensureApolloError
This function is declared like this:
let ensureApolloError: t => t = error =>
%bs.raw(`
function (error, makeApolloError) {
var error = error || {};
if (Array.isArray(error.graphQLErrors)) {
return error;
} else if (error && typeof error.message === "string" && error.extensions) {
return makeApolloError({graphQLErrors: [error]});
} else {
return makeApolloError({networkError: ensureError(error)})
}
}
`)(error, make, ensureError)
The raw function takes 2 parameters in input, and it is called with 3 parameters.
I think in fix it, we need to do this:
let ensureApolloError: t => t = error =>
%bs.raw(`
function (error, makeApolloError, ensureError) {
var error = error || {};
if (Array.isArray(error.graphQLErrors)) {
return error;
} else if (error && typeof error.message === "string" && error.extensions) {
return makeApolloError({graphQLErrors: [error]});
} else {
return makeApolloError({networkError: ensureError(error)})
}
}
`)(error, make, ensureError)
Awesome work you've done so far!!
Please consider nameapacing your package in bsconfig like:
namespace: "Jeddeloh_ReasonApolloClient"
This could avoid potential naming collisions.
Hello
Once again many thanks for your great bindings. 👏🥳
I am currently experiencing a bug in the use of the ApolloClient.Utilities.getOperationDefinition
function.
let terminatingLink = ApolloClient.Link.split(~test=({query}) =>
switch ApolloClient.Utilities.getOperationDefinition(query) {
| Some({kind, operation, name: {value}}) =>
kind === "OperationDefinition" &&
operation === "query" &&
value->Js.String2.startsWith("Analytics")
| _ => false
}
, ~whenTrue=httpAnalyticsLink, ~whenFalse=httpGatewayLink)
It creates an error if I have a graphql query that takes this form (no operation name).
query ($id: ID!) {
user(id: $id) { ... }
}
In this cas, the name
property is undefined. So it is not possible to access value
property.
So I applied this patch ⬇️
diff --git a/node_modules/rescript-apollo-client/src/graphql/language/ApolloClient__Graphql_Language_Ast.res b/node_modules/rescript-apollo-client/src/graphql/language/ApolloClient__Graphql_Language_Ast.res
index 1c007fa..80f26c6 100644
--- a/node_modules/rescript-apollo-client/src/graphql/language/ApolloClient__Graphql_Language_Ast.res
+++ b/node_modules/rescript-apollo-client/src/graphql/language/ApolloClient__Graphql_Language_Ast.res
@@ -172,7 +172,7 @@ module OperationDefinitionNode = {
type t = {
kind: string,
loc: option<Location.t>,
- name: NameNode.t,
+ name: option<NameNode.t>,
operation: OperationTypeNode.t,
variableDefinitions: option<array<VariableDefinitionNode.t>>,
directives: option<array<DirectiveNode.t>>,
And change that ⬇️
let terminatingLink = ApolloClient.Link.split(~test=({query}) =>
switch ApolloClient.Utilities.getOperationDefinition(query) {
- | Some({kind, operation, name: {value}}) =>
+ | Some({kind, operation, name: Some({value})}) =>
kind === "OperationDefinition" &&
operation === "query" &&
value->Js.String2.startsWith("Analytics")
| _ => false
}
, ~whenTrue=httpAnalyticsLink, ~whenFalse=httpGatewayLink)
Do you need a pull request?
Greetings from France 🇫🇷
Léo
Thanks to all of you, it's working well. By the way, I wonder if you have any plans to offer RetryLink .
Otherwise, you need to check if the flow on this page is working properly now.
https://www.apollographql.com/docs/react/data/error-handling/#on-graphql-errors
The last time I tried it, f.apply() was giving me an undefined error.
May you be full of happiness, with sincerity.
To open this issue here.. teamwalnut/graphql-ppx#202
https://github.com/apollographql/apollo-client/blob/main/CHANGELOG.md#apollo-client-350-2021-11-08
DataProxy.updateFragment
methodDataProxy.updateQuery
methodMutationResult.reset
methoduseLazyQuery
execute function returns a Promise with query resultI think if the minimum version gets bumped to ^3.5.0
that'd require a major version release? The useLazyQuery
change certainly is breaking.
I'm noticing some commented out variables
properties in src/@apollo/client/cache/core/types/ApolloClient__Cache_Core_Types_DataProxy.res
, is this comment
// I think fragment variables are still experimental?
referring to graphql-ppx or apollo/client?
Hi folks
I have been using react state to gate pollInterval on some queries, as some tasks progress on the back end. It took me a while to figure that None does not cancel a set interval. Should it? It seems like it should?
Seems likely a one liner. I can take a look if youre interested in a PR.
Thanks
Alex
Hi, first of all thanks for awesome library, really enjoy it by far.
I have question is there a way to modify output of graphql query?
I really want to remove any require
statements from my .bs.js file.
Right now my query look like this:
/* Me_Query.re */
[%graphql {|
query Me {
me {
firstName
id
lastName
...
}
}
|}];
and builded file like this
/* Me_Query.bs.js */
import * as ApolloClient__React_Hooks_UseQuery from "reason-apollo-client/src/@apollo/client/react/hooks/ApolloClient__React_Hooks_UseQuery.bs.js";
var Raw = {};
var query = (require("@apollo/client").gql`
query Me {
me {
__typename
firstName
id
lastName
}
}
`)
Is there any way I can from
require("@apollo/client").gql
change it to something like this:
import {gql} from 'graphql-tag'
var query = gql...
Thanks in advance.
For the first time user this example might be hard to understand. something like mutate(varaiblerecords) |> Js.Promise.then()
might be simple. If it is fine I can send a PR.
I have the query
module UserProfileQuery = [%graphql
{|
query UserProfile($sub: String!) {
users_by_pk(id: $sub) {
id
last_seen
created_at
name
picture
email
on_boarded
}
}
|}
];
But UserProfileQuery does not have use function.
Hi,
Any reason why the use
function returns records instead of variants?
I have a nullable field that I'm trying to change from a value to null. The query simply drops the field, rather than passing the new null value. How can I make Apollo send a null value rather than just omitting the field? I've hunted in the Apollo docs and don't see anything, so I'm hoping there are some rescript tricks I'm missing.
Thanks!
Should we get reason-apollo-client
to stable and then switch to res-apollo-client
?
Hello.
I have issue with HttpLink
headers.
Using this example from the documentation, I created a link to my GraphQL endpoint.
let httpLink = ApolloClient.Link.HttpLink.make(
~uri=_ => Env.graphqlEndpoint,
~headers=Obj.magic({"Accept": "application/json"}),
(),
)
I expect the Accept
header to be exactly application/json
, but */*
is automatically added to the value.
This is a bug? If not, how can this be fixed?
Thank you!
Here's what I think is still needed for a good experience here:
makeVar
bindingsTypePolicies
if it hasn't already been added by this point (it's currently just an abstract type)There is some defensive programming in the client where there is an expectation that the parse function can fail. GraphQL is a protocol with certain guarantees. That means we can assume data shapes and that in turn means that the parse function would never raise an exception unless there is a bug in graphql-ppx
.
Can we remove these checks?
This is more a question than an issue per se (sorry, I didn't know where to ask this), but is it possible to use Js.Nullable.t
with ApolloClient.query
?
I'm asking this because I'm using it with Next.js and wanted to do some SSR. Since getServerSideProps converts the props to JSON before sending them to React, I'm getting errors:
SerializableError: Error serializing `.projects._0[0].description` returned from `getServerSideProps` in "/projects".
Reason: `undefined` cannot be serialized as JSON. Please use `null` or omit this value all together.
Converting all of the option
als to Js.Nullable.t
worked but, since they are generated as Nullables by graphql-ppx, I would like to know if there's any way to access them in this library.
Thank you very much!
This is a living document that is a product of our ever-evolving understanding and welcomes change. The primary purpose is to provide transparency, but also alignment and prioritization of individual efforts.
Current proposed roadmap:
The GraphQL error type allows for an extensions
field, which is an arbitrary key/value object. Apollo leverages this to provide an error code
: https://www.apollographql.com/docs/apollo-server/data/errors/#codes.
I'm not entirely sure what the correct type should be here. Apollo provides some pre-defined errors in apollo-server, but you can extend the ApolloError class to define other errors specific to your domain (which I've done in the app I'm using this for). One option might be to allow for passing your own GraphQLError and/or extensions
type in the config, which you could define to contain the specific errors your app needs to handle? Aside from that, at least providing the extensions
field which contains a code
field typed as a string would be something.
How would we approach writing bindings for MockedProvider
? The mocks
prop is so dynamic and I am struggling where to begin. Has anybody thought about this?
A change was made in @apollo/client > 3.5 that means the query
property in the options object will override the first argument and because rescript encodes query: undefined
in that options object there's a runtime error. Technically I think the responsibility lies with apollo here, but humans probably wouldn't write useQuery(documentNode, { query: undefined })
either.
The easiest way to fix this looks like replacing query: None
with query: Some(Operation.query)
, but would also be fixed by removing the query
property entirely from the options type definitions. I'd be happy to do either just let me know what you'd prefer.
Also affects useMutation
, useLazyQuery
, etc
Hey there, first I'd like to thank everybody working on this wonderful library! Combined to GraphQL PPX, it's delightful.
I ran into the following issue: fetchMore
executes a request multiple times (twice on my project even on simple requests not implying variables or specific stuff and four times on your own example: https://github.com/reasonml-community/rescript-apollo-client/blob/master/EXAMPLES/src/hooksUsage/Query_Typical.res#L35).
Have you ever seen that?
Thanks for reading!
I see it greyed out. Is it accessible as a renamed method?
Thank you for the awesome work here!
Right now for both queries and mutation, there is use
function generated. I'm wondering if it would be possible to change it to useQuery
for queries and useMutation
for mutations. It would make it more readable if this module is a query or mutation.
I am trying to use onCompleted
on useMutation
. Maybe this is equivalent to some other method in the library?
This compiles but doesnt not look right and cause an invalid hook call
error.
let loginFn = () => {
let variables: LoginUser.t_variables = {email: "[email protected]"};
let _ =
ApolloClient.React.useMutation(
~mutation=(module LoginUser),
~onCompleted=
({login}) => {
Js.log2("TOKEN_LOGIN", login);
let token =
login.token
->Belt.Option.map(t => t)
->Belt.Option.getWithDefault("");
Dom.Storage.(localStorage |> setItem("token", token));
Dom.Storage.(localStorage |> setItem("userId", login.id));
},
LoginUser.serializeVariables(variables)->ignore,
// variables
)->ignore;
();
};
error:
Uncaught Error: Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:
1. You might have mismatching versions of React and the renderer (such as React DOM)
2. You might be breaking the Rules of Hooks
3. You might have more than one copy of React in the same app
See https://fb.me/react-invalid-hook-call for tips about how to debug and fix this problem.`
Being called like this since its the only way i can get it to compile:
module LoginUser = [%graphql
{|
mutation LoginUser($email: String!) {
login(email: $email) {
id
token
}
}
|}
];
[@react.component]
let make = () => {
let loginFn = () => {
let variables: LoginUser.t_variables = {email: "[email protected]"};
let _ =
ApolloClient.React.useMutation(
~mutation=(module LoginUser),
~onCompleted=
({login}) => {
Js.log2("TOKEN_LOGIN", login);
let token =
login.token
->Belt.Option.map(t => t)
->Belt.Option.getWithDefault("");
Dom.Storage.(localStorage |> setItem("token", token));
Dom.Storage.(localStorage |> setItem("userId", login.id));
},
variables->ignore,
)->ignore;
();
};
<div>
<p>
<button onClick={_e => loginFn()}>
"ApolloClient.React.useMutation"->React.string
</button>
</p>
</div>;
};
Thank you in advance!
Super work here!
Also, how is the above function different from the following which works but doesnt have onCompleted
as an option?
let logLogin = _ =>
Client.instance.mutate(~mutation=(module LoginUser), {email: "[email protected]"})
->Promise.get(
fun
| {data: Some({login}), error: None} => {
Js.log2("TOKEN_LOGIN", login);
let token =
login.token
->Belt.Option.map(t => t)
->Belt.Option.getWithDefault("");
Dom.Storage.(localStorage |> setItem("token", token));
Dom.Storage.(localStorage |> setItem("userId", login.id));
}
| {error} => Js.log2("Error: ", error),
);
I think I found it at ApolloClient.Bindings.Client.ApolloClient.mutate but guessing thats not the intended way for people to find it?
Thanks
A
What would be the equivalent in this project of this code:
const IS_LOGGED_IN = gql`
query IsUserLoggedIn {
isLoggedIn @client
}`
It found in the apollo docs here-> https://www.apollographql.com/docs/tutorial/local-state/.
I guess this is a query on the client which we would set up with cache?
There are some pagination improvements I'd love to try out: apollographql/apollo-client#6465
TypePolicies.t
needs fleshed outI am messing with the demo and created this file from the Mutation.re
example:
module Cache = ApolloClient.Cache;
module DeleteTodoMutation = [%graphql
{|
mutation DeleteTodo ($id:String!){
deleteTodoItem(input: { id: $id }) {
deletedTodoItemId
clientMutationId
}
}
|}
];
When I call this as is it compiles and fails. To make it work, it has to be
module Cache = ApolloClient.Cache;
module DeleteTodoMutation = [%graphql
{|
mutation DeleteTodo ($id:ID!){
deleteTodoItem(input: { id: $id }) {
deletedTodoItemId
clientMutationId
}
}
|}
];
Is this expected? Figured the typing was supposed to catch that. Working example is in #37
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.