How to setup multiple clients in Vue apollo v4? - vue.js

I have 2 different servers (graphql, rest) and trying to setup multiple clients in my vue app.
Here is my setup apollo.provider.js
import { ApolloClient, createHttpLink, InMemoryCache } from '#apollo/client/core'
import { RestLink } from 'apollo-link-rest';
import { provide } from 'vue'
import { ApolloClients } from '#vue/apollo-composable'
// HTTP connection to the API
const httpLink = createHttpLink({
uri: 'https://reqres.in/graphql'
})
// Set `RestLink` with your endpoint
const restLink = new RestLink({
uri: "https://reqres.in"
});
// Cache implementation
const cache = new InMemoryCache()
// Create the graphql client
const graphqlClient = new ApolloClient({
cache: cache,
link: httpLink
})
// Create the rest client
const restClient = new ApolloClient({
cache: cache,
link: restLink
})
export const provider = provide(ApolloClients, {
default: graphqlClient,
restClient: restClient
})
This is not working, however I can use each client seperately by doing
import { createApolloProvider } from '#vue/apollo-option'
export const provider = createApolloProvider({
defaultClient: graphqlClient // or restClient
})
Please help me understand how to use both clients.

It turned out I mixed up between "options API" and "composition API"
considering my setup uses "options API" this solution works.
export const provider = createApolloProvider({
clients: {
graphqlClient,
restClient
},
defaultClient: graphqlClient,
})

Related

File uploads fail using axios-fetch with Apollo client and apollo-upload-client in Gatsby

I'm using axios-fetch as a fetch implementation for the Apollo Client in Gatsby. I want to upload files to the server, so I'm using the package: apollo-upload-client. But when inspecting the payload that gets sent, it says:
[object FormData], instead of serializing everything.
Any suggestions on how to fix this?
PD: I tried using cross-fetch and it work fine.
UPDATE:
This is my Apollo Client creation with axios-fetch:
import { ApolloClient, InMemoryCache } from '#apollo/client';
import { createUploadLink } from 'apollo-upload-client';
import { buildAxiosFetch } from 'axios-fetch'; // This doesn't work
import Axios from 'axios';
import { GRAPHQL_ENDPOINT } from '../settings';
const axios = Axios.create({ timeout: 10000 });
const fetch = buildAxiosFetch(axios);
const client = new ApolloClient({
cache: new InMemoryCache(),
// eslint-disable-next-line #typescript-eslint/no-explicit-any
link: new (createUploadLink as any)({
uri: GRAPHQL_ENDPOINT,
fetch,
}),
});
export default client;
Have you tried using serializing the data using JSON.stringify?
const client = new ApolloClient({
cache: new InMemoryCache(),
// eslint-disable-next-line #typescript-eslint/no-explicit-any
link: new (createUploadLink as any)({
uri: GRAPHQL_ENDPOINT,
JSON.stringify(fetch),
}),
});

Get ip address and pass to Apollo client before react native renders (expo)

in my app.js I have the following:
import React from 'react';
import { ApolloClient, InMemoryCache, createHttpLink, ApolloProvider } from '#apollo/client';
import * as Network from 'expo-network';
Per Apollo documentation I am assigning a uri to httpLink. Currently the uri is static but I would like this uri to be dynamic and update before the app renders.
const httpLink = createHttpLink({
uri: `http://192.168.1.165:5000/graphql`,
});
// get headers
const authLink = setContext( async (_, { headers }) => {
// return headers
...
});
// create apollo client
const client = new ApolloClient({
link: authLink.concat(httpLink),
cache: new InMemoryCache()
});
Finally rendering the app and passing client to Apollo:
export default () => {
return (
<ApolloProvider client={client}>
<SomeModule>
</SomeModule>
</ApolloProvider>
);
};
I'm attempting to use Expo to get the client IP address. The expo docs give a limited example of getting the ip address which I've interpreted to mean something like:
async function getLocalIPAddress() {
const ipAddress = await Network.getIpAddressAsync();
// do something
}
How should I invoke the function to get the IP address before export default is invoked?

Using async api into main.js of vue js

In main.js, from vue project app, I am setting a socket io url using the return of an API.
const url = getAPIAddress(params); //API promises
My problem is that main.js has no async function. So I canĀ“t use async/await.
How could I do that? Or Is there a better way to do it?
//main.js sample
import VueSocketIOExt from "vue-socket.io-extended";
import io from "socket.io-client";
import getAPIAddress from "getAPIAddress";
const url = getAPIAddress(params); //API promises
const socket = io(url, { autoConnect: false });
Vue.use(VueSocketIOExt, socket, { store });
Vue.config.productionTip = false;
Vue.use(VuetifyDialog, {
context: {
vuetify,
},
});
Hello you should try something like :
(async () => {
const url = await getAPIAddress(params); //API promises
// the rest of the code
})();

vue-apollo awsappsync - refresh credentials

I am using vue-apollo with AWSAppSyncClient. I have followed this documentation for Vue - https://github.com/awslabs/aws-mobile-appsync-sdk-js . My requirement is user should be able to subscribe to appsync. Here is the main.js code.
import './bootstrap';
import router from './routes';
import store from './store';
import App from './components/templates/App';
import AWSAppSyncClient from 'aws-appsync';
import VueApollo from "vue-apollo";
const config = {
url: process.env.MIX_APPSYNC_URL,
region: process.env.MIX_APPSYNC_REGION,
auth: {
type: process.env.MIX_APPSYNC_TYPE,
credentials: {
accessKeyId: "temporary access key goes here",
secretAccessKey: "temporary secret access key goes here",
sessionToken: "session token goes here"
}
},
};
I get the 'credentials' part after user logged in successfully with aws cognito validation.
const options = {
defaultOptions: {
watchQuery: {
fetchPolicy: 'cache-and-network',
}
}
}
// Create the apollo client
const apolloClient = new AWSAppSyncClient(config, options);
//The provider holds the Apollo client instances that can then be used by all the child components.
const apolloProvider = new VueApollo({
defaultClient: apolloClient,
});
var vm = new Vue({
el:"#dashboardapp",
router:router,
apolloProvider:apolloProvider,
store:store,
components: { App },
template: '<App/>',
data() {
return {
}
},
});
The above set up works fine. User can login. After cognito verifies user, it sends temporary credentials (accesskey, secret key, session token). With temporary credentials I am able to subscribe to aws appsync through vue-apollo. However, the credentials are valid for 1 hour only. So I need to update the credentials and keep the subscription part to get live data. But I dont know how to do it. I have gone through the docs, but not able to find anything specific to my case.
I need to update the credentials from either a child component of 'vm' or from vuex store. I already have updated credentials. I just dont know how to pass it to the 'AWSAppSyncClient' and how to re-subscribe with updated credentials. Also I don't want to reload the page. It should update credentials without reloading the page. Hope anyone would have done this before ?
I have done few changes to my code and now I am able to achieve what I wanted. Here are the changes I have done, in case anyone doing same thing.
First loading the apollo client as blank - means without awsappsyncclient in main.js file.
import './bootstrap';
import router from './routes';
import store from './store';
import App from './components/templates/App';
import VueApollo from "vue-apollo";
// Create the apollo client
const apolloClient = '';
//The provider holds the Apollo client instances that can then be used by all the child components.
const apolloProvider = new VueApollo({
defaultClient: apolloClient,
});
var vm = new Vue({
el:"#dashboardapp",
router:router,
apolloProvider:apolloProvider,
store:store,
components: { App },
template: '<App/>',
data() {
return {
}
},
});
Then from child component I am creating smart subscription. Once temporary credentials are expired, I am generating new credentials and updating in vuex store. Based on the change, I am stooping the old smart subscription and creating a new smart subscription.
Here is the child component code.
<template>
<div class="status-frame">
<!-- relevant code goes here -->
</div>
</template>
<script>
import gql from 'graphql-tag';
import AWSAppSyncClient from 'aws-appsync';
import VueApollo from "vue-apollo";
export default {
data () {
return {
}
},
methods: {
timelineSubscribe() {
if(this.$parent.$apolloProvider.clients[1]) {
delete this.$parent.$apolloProvider.clients[1];
this.$apollo.subscriptions.subscribeToNewNotification.stop();
}
const config = {
url: process.env.MIX_APPSYNC_URL,
region: process.env.MIX_APPSYNC_REGION,
auth: {
type: process.env.MIX_APPSYNC_TYPE,
credentials: {
accessKeyId: this.appsyncObj.accessKeyId,
secretAccessKey: this.appsyncObj.secretAccessKey,
sessionToken: this.appsyncObj.sessionToken
}
},
};
const options = {
defaultOptions: {
watchQuery: {
fetchPolicy: 'cache-and-network',
}
}
}
// Create the apollo client
const apolloClient = new AWSAppSyncClient(config, options);
// add apolloClient to a new index in apolloProvider.
this.$parent.$apolloProvider.clients[1] = apolloClient;
console.log(this.$apollo.provider.clients);
this.$apollo.addSmartSubscription('subscribeToAnything', {
client: '1',
query: gql`subscription subscribeToAnything ($accountId: String!) {
subscribeToAnything(accountId: $accountId) {
// required fields goes here
}
}`,
// Reactive variables
variables() {
// This works just like regular queries
// and will re-subscribe with the right variables
// each time the values change
return {
accountId: 'account_id goes here',
}
},
// Result hook
result(data) {
console.log(data);
},
skip () {
return false;
}
});
}
},
computed: {
appsyncObj() {
return this.$store.getters['profile/appsyncObj']; // get from vuex store
}
},
watch: {
'appsyncObj' () {
this.timelineSubscribe(); // each time appsyncObj changes, it will call this method and resubscribe with new credentials.
}
},
}
I update the vuex store for appsyncObj after login and after getting new credentials. However, I have not added that code here.

After Nuxt build api returns 404

I'm having this weird issue and I seriously need your help. In development my code works perfectly fine but after doing nuxt build and all the apis are returning 404 error. Please help
When I'm building the api and running it, it works. In development api and nuxt both works but building nuxt and the api, doesn't work.
Following are my configuration
Server configuration
import convert from 'koa-convert';
import cors from 'kcors';
import bodyParser from 'koa-body';
import session from 'koa-session';
import helmet from 'koa-helmet';
import config from 'config';
import serve from 'koa-static';
import mount from 'koa-mount';
import { cModules, cMiddleware } from '../app';
import { catchErr, statusMessage } from './errorConfig';
import nuxtConfig from './nuxtConfig';
function baseConfig(app, io) {
app.keys = config.get('secret');
app.proxy = true;
app.use(mount('/static', serve(config.get('paths.static'))));
app.use(convert.compose(
catchErr,
cors({
credentials: true,
origin: true
}),
bodyParser({
multipart: true,
formLimit: '200mb'
}),
session({
maxAge: 21600000
}, app),
helmet(),
statusMessage
));
cModules(app, io);
app.use(cMiddleware());
if (config.get('nuxtBuild')) {
nuxtConfig(app);
}
}
export default baseConfig;
And my Nuxt
import { Nuxt, Builder } from 'nuxt';
import koaConnect from 'koa-connect';
import isDev from 'isdev';
import config from '../../../nuxt.config';
async function nuxtConfig(app) {
const nuxt = new Nuxt(config);
if (isDev) {
await new Builder(nuxt).build();
}
const nuxtRender = koaConnect(nuxt.render);
app.use(async (ctx, next) => {
await next();
ctx.status = 200;
ctx.req.session = ctx.session;
await nuxtRender(ctx);
});
}
export default nuxtConfig;