Vue-apollo: [feature request] consider a new API to work with the new vue function-base API?

Created on 3 Jul 2019  ยท  33Comments  ยท  Source: vuejs/vue-apollo

@Akryum Any plans to publish a new function-based API like useQuery useMutation? ;)

enhancement

Most helpful comment

Sorry, I overlooked closing this as it's available already.

All 33 comments

Yes.

@Akryum would you accept a pr for this?

I'm working on it already. ๐Ÿ˜‰

@Akryum was riffing on this last weekend, has a really rough working example for useQuery, would need to handle setting array/objects but i think it is what we would need. Repo is here
https://github.com/Austio/vue-apollo-hooks/tree/master/demo

Working useQuery function: https://github.com/Austio/vue-apollo-hooks/blob/22584e45e1858fb25ad2f0fe16b5671eb0fc9bc9/demo/pages/useQuery.vue#L20

Usage in setup is here: https://github.com/Austio/vue-apollo-hooks/blob/22584e45e1858fb25ad2f0fe16b5671eb0fc9bc9/demo/pages/useQuery.vue#L56

Template has example of the subscribed data and a step to manually pull from the apollo client.

@Akryum do you have a branch yet for the new composition useQuery etc? I've experimented with some of our components recently but 90% of them are graphql-driven and I'm curious to try it.

Really looking forward for this. I can't get my hands on using the composition API since basically all of my components use graphql. Thanks for your hard work @Akryum

I see it's in use already (your links here plus the File Explorer example). How do I get to use it? The linked repo appears to be a nuxt demo app, so I just grab the src/index.ts I guess?

Hi there,

does anyone by any chance have a current example of ts + vue-apollo + composition-api (+nuxt) lying around?

I'm currently trying to cobble together at nuxt starter using postgraphile and want to use Typescript, vue-composition-api and vue-apollo & nuxt + a nuxt-postgraphile module, I created for it (with a lot of help of Benjie (from graphile ) and Atinux (from nuxt)).

I spent way too much time trying to get it to work, but I just don't know how e.g. to make TS not complain about the apollo{} in createComponent(). I feel once I passed this initial hurdle it would be a clear highway.

I'm talking about using it like this:

<script lang="ts">

import {
  SetupContext,
  computed,
  createComponent,
  reactive,
} from "@vue/composition-api";

import { SharedLayoutQuery } from "@app/graphql";

export default createComponent({
  name: "DefaultLayout",
  apollo: {
    // Simple query that will update the currentUser
    currentUser: SharedLayoutQuery,
  },
  components: {
[..]  
  },
  setup(_props, ctx: SetupContext) {
    const state = reactive({
      title: "No title",
      isLoggedIn: computed(() => {//check currentUser from apollo}),
    });

    return { ... toRefs(state) };
  },
});
</script>

I looked in the File Explorer example mentioned by @csmikle (I assume it's this one I found via search engine: https://gist.github.com/Akryum/05964e81d09fb5088b7769cff15f5e7c ).

It seems apollo {} is dead? and we should use useQuery and mutate manually instead?

I looked in the File Explorer example mentioned by @csmikle (I assume it's this one I found via search engine: https://gist.github.com/Akryum/05964e81d09fb5088b7769cff15f5e7c ).

It seems apollo {} is dead? and we should use useQuery and mutate manually instead?

Well, I would love to, but Module '"../../node_modules/vue-apollo/types"' has no exported member 'useQuery'. Did you mean to use 'import useQuery from "../../node_modules/vue-apollo/types"' instead? ๐Ÿ˜„

Then maybe we have to work around it by getting it from ctx.root

Like @Austio does in his example: https://github.com/Austio/vue-apollo-hooks/blob/22584e45e1858fb25ad2f0fe16b5671eb0fc9bc9/demo/pages/useQuery.vue#L25 posted above

Edit: or even better, use this file: https://github.com/Austio/vue-apollo-hooks/blob/master/src/index.js

So this is what I cobbled together so far to get it running with TS, but now it seems I'm at the end of my TS knowledge.
@Austio: would you mind taking a look at it? I basically mixed together your plugins/apollo-boost , src/index.js and demo/.../useQuery.vue

I get this error in my Compiler: Type 'Ref<null>' is not assignable to type 'TData'. 'Ref<null>' is assignable to the constraint of type 'TData', but 'TData' could be instantiated with a different subtype of constraint '{}'.

at this part

 return {
    // ...toRefs(state),
    data, error, loading, networkStatus, partial, stale
  };

// full code:
```TS

@JoeSchr updated with latest api here.

https://github.com/Austio/vue-apollo-hooks/commit/d38e4862817aaee3a712160f7ee49f8f31fd277e

@Akryum wdyt? I think this is pretty doable but would be a biggish breaking change. Probably would also be easier to maintain test/utils if we moved to this api and keep a branch for the old method of doing things.

@Austio Thanks a lot for your quick response. I will try it out tomorrow.

I suppose since there is not standardized API yet, it's pretty fruitless to convert it into TS? Or maybe my TS kung fu is just to low to turn watchQuery's result into appropriate TS? (apolloState in your new example). Wdyt?

@JoeSchr updated with latest api here.

Austio/vue-apollo-hooks@d38e486

@Akryum wdyt? I think this is pretty doable but would be a biggish breaking change. Probably would also be easier to maintain test/utils if we moved to this api and keep a branch for the old method of doing things.

That looks awesome, but it fails for something like Nuxt, if you want to pull the data on server side, while the current vue-apollo implementation with the smart queries doesn't.

Support of composition API for serverPrefetch is not implemented yet.

~Ii'm sure we will get this in vue-apollo sometime due to Guillaume Chau's work on composition api having ssr support . In the meantime i have a working example that has what i think is a good interface that we can build on and works on the client. I'm going to be using this on a production side project i'm working on to sus out any edges.~

~https://github.com/Austio/apollo-hooks-vue/blob/master/src/useQuery.js
Going to publish it roughly under apollo-vue-hooks so that we can have some iteration on this in the community before we decide on the api that is needed. Still needs a lot of work, held off on ts interfaces atm, prs welcome for useSubscription and useMutation, with any luck i may get to those this week though.~

Use https://v4.apollo.vuejs.org/guide-composable/setup.html

Sorry, I overlooked closing this as it's available already.

๐ŸŽ‰๐ŸŽ‰๐ŸŽ‰ @Akryum I'm really liking the API so far, seems very well thought out. Thank you for this.

FYI to others, you need at least "@vue/composition-api": "^0.3.3" to use @vue/apollo-composable.

Agreed dropped in and works like a charm @Akryum thank you!

@Akryum Does useQuery still accept a gql file instead of an inline gql template string?
I don't think I see this mentioned in the doc

It would have been nice if there was a way to avoid the second step of useResult to get at the object you want inside result (assuming you only had one)

Does useQuery still accept a gql file instead of an inline gql template string?
I don't think I see this mentioned in the doc

Yes

It would have been nice if there was a way to avoid the second step of useResult to get at the object you want inside result (assuming you only had one)

I though about this and couldn't come up with a nice API that didn't feel too magical

@Akryum useQuery and useSubscription have three parameters (document, variables, options) but useMutation has only two (document, options), and variables is in options. Why that? Wouldn't it be better to make them all the same?

Personally I would like to avoid the null in the middle of arguments like useQuery(gql, null, { fetchPolicy }), so I prefer the two-parameter way.

useQuery and useSubscription have three parameters (document, variables, options) but useMutation has only two (document, options), and variables is in options. Why that? Wouldn't it be better to make them all the same?

I went this way because I've found you rarely need the options (other than the document and the variables) for queries and subscriptions, whereas mutations you almost always put some options (such as update and optimisticResponse).
Also useMutation works quite differently compared to useQuery and useSubscription in the sense that it's not reactive and that you can pass the variables when calling mutate.

Thanks for working on this!

I tried to hook it into my Nuxt app, but I get I get this Error doing it: TypeError: composition_api_1.getCurrentInstance is not a function
What I did was adapting "Connect Apollo Client to Vue" from the docs:

import { provide } from '@vue/composition-api'
import { DefaultApolloClient } from '@vue/apollo-composable'

const app = new Vue({
  setup () {
    provide(DefaultApolloClient, apolloClient)
  },

  render: h => h(App),
})

into this, which get's loaded as a plugin by nuxt as startup.

//plugins/vue-apollo-composable.js

import { DefaultApolloClient } from '@vue/apollo-composable'
// import { provide } from '@vue/composition-api'

export default ({ app }, provide) => {
  const apolloClient = app.apolloProvider.defaultClient;
  app.DefaultApolloClient = apolloClient;
  // provide(DefaultApolloClient, apolloClient)
  // inject('myInjectedFunction', string => console.log('That was easy!', string))
}

I adapted this example from the nuxt docs about inject in root & context:
https://nuxtjs.org/guide/plugins#inject-in-root-amp-context

I checked that app.apolloProvider.defaultClient is already populated (by @nuxtjs/apollo ).

I stepped through it and it's this line that triggers it:

//node_modules/@vue/apollo-composable/dist/useQuery.js
function useQuery(document, variables, options) {
...
26:     var vm = composition_api_1.getCurrentInstance();
...
}

What can I try to make it work?

@JoeSchr: getCurrentInstance was added to the composition API in 0.3.3.

FYI to others, you need at least "@vue/composition-api": "^0.3.3" to use @vue/apollo-composable.

https://github.com/vuejs/composition-api/releases/tag/v0.3.3

โ€ข Expose getCurrentInstance for advanced usage in Vue plugins

Fixed it, after reading @Austio message, I thought putting @vue/composition-api at latest would be enough, but it stayed on 0.3.2
diff - "@vue/composition-api": "latest", + "@vue/composition-api": "^0.3.3",

maybe because I'm using yarn workspaces I didn't see the warning. Or there are so many warnings that I oversaw it. Sorry for the noise!

Sorry to bother you guys again, but I'm now trying for hours and hours to get my apolloClient into the root instance on an Nuxt installation.
Problem is, I can't call provide() like in example outside of a VueComponent::setup, so I have no Idea how I can make it available for inject(DefaultApolloClient) in @vue/apollo-composable/src/useApolloClient.ts

I created a plugin (according to nuxt docs) and this is the stuff I tried. It seems either _provided doesn't stick after this function or with the inject method even though I convert it to a string, there is always a $ concatenated, so it would be $_provided

import { Plugin, Context } from '@nuxt/types'
import { DefaultApolloClient } from "@vue/apollo-composable";

const DefaultApolloClientStr:string = DefaultApolloClient.toString();
const DollarDefaultApolloClientStr:string = `$${DefaultApolloClientStr}`;

declare module 'vue/types/vue' {
  interface Vue {
    _provided: any
 }
}
declare module '@nuxt/types' {
  interface Context {
    _provided: any
  }
}

const vueApolloComposable: Plugin = (ctx: Context, inject: (key: string, value: any) => void) => {
  debugger;
  const apolloClient = ctx.app.apolloProvider.defaultClient;
  const provided: {[k: string]: any} = {};
  provided.DefaultApolloClient = apolloClient
  ctx._provided = provided ;
  inject(DollarDefaultApolloClientStr, apolloClient);
  Vue.prototype._provided = provided;
}

export default vueApolloComposable

I also tried accessing it via alternative ctx.app.provide approach, which I found described a little bit hidden in the RFC

Can someone who is more experienced help me out please?

Hey @JoeSchr the best place for this question imo is the Vue forum, second best would be stack overflow. Could you please post over there and copy the link here so that others finding this can follow and I can help there?

Sorry if I'm making noise, but I wonder why @vue/apollo-composable internally accesses Apollo client instances through inject?

I mean, when I need to send a request in a router guard, I can't use the compositions since they can only be called directly inside a component's setup(). The only option I have seems to use the raw ApolloClient API. Mostly this is not a big problem, but being able to use the compositions makes me feel better. I don't see the reason not to make it this way. Could someone elaborate on the API design?

Was this page helpful?
0 / 5 - 0 ratings