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

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),
}),
});

Related

How to setup multiple clients in Vue apollo v4?

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,
})

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?

Quasar Axios request wrong URL (Double URL)

The Error Image
when i send request via axios with url axios concatenate url of api
with the url of the quasar dev server how can i neglect this
concatenation and send the API url only there is any configuration for
baseUrl of axios with quasar ?
src/boot
import axios from 'axios'
export default async ({ Vue }) => {
axios.defaults.baseURL = 'http//:localhost:3000/'
Vue.prototype.$axios = axios
}
the componennt :
this.$axios({
url : 'backend/spots/all',
}).then(response=>{
this.allSlots = response.data
})
According Quasar documentation you can try it as below:
// src/boot/axios.js
const axiosInstance = axios.create({
baseURL: 'http//:localhost:3000'
})
export default async ({ Vue }) => {
Vue.prototype.$axios = axiosInstance
...
}
export { axiosInstance }
to use in some vue | js file:
import { axiosInstance } from 'src/boot/axios'
axiosInstance.get('/some-endpoint')
I am not sure, but can you try to change axios.defaults.baseURL = 'http//:localhost:3000/' to axios.defaults.baseURL = 'http://localhost:3000/' (change colon place) ?
For anyone reading this.
According to quasar axios boot file documentation you can try a more cleaner way...
import Vue from 'vue'
import axios from 'axios'
// we add it to Vue prototype
// so we can reference it in Vue files as this.$axios
// without the need to import axios or use vue-axios
Vue.prototype.$axios = axios
// can also create an axios instance specifically for the backend API
const api = axios.create({ baseURL: 'https://api.example.com' })
Vue.prototype.$api = api
export { axios, api }
I was having the same issue, in quasar.config.js under build I had
env: ctx.dev ? { // so on dev we'll have
API: JSON.stringify('https://my.staging.api/v1/')
} : { // and on build (production):
API: JSON.stringify('https://my.api/v1/')
},
removing JSON.stringify solved the issue
env: ctx.dev ? { // so on dev we'll have
API: 'https://my.staging.api/v1/'
} : { // and on build (production):
API: 'https://my.api/v1/'
},

How to use axios in Vue2 project created with vue-cli3

I created a new vue project using the command vue create axe using vue-cli-3.0.016beta. Then installed axios using npm install axios --save. In the main.js file I imported axios as shown below.
import Vue from 'vue'
import App from './App.vue'
import axios from 'axios'
Vue.config.productionTip = false
Vue.use(axios)
new Vue({
render: h => h(App)
}).$mount('#app')
There is not a bit of code change other than this. Still I get an error like the following:
Unhandled promise rejection
TypeError
​
columnNumber: 7
​
fileName: "http://localhost:8080/app.js line 1065 > eval"
​
lineNumber: 57
​
message: "parsed is undefined"
​
stack: "isURLSameOrigin#webpack-internal:///./node_modules/axios/lib/helpers/isURLSameOrigin.js:57:7\ndispatchXhrRequest#webpack-internal:///./node_modules/axios/lib/adapters/xhr.js:109:50\nPromise#webpack-internal:///./node_modules/core-js/modules/es6.promise.js:177:7\nxhrAdapter#webpack-internal:///./node_modules/axios/lib/adapters/xhr.js:12:10\ndispatchRequest#webpack-internal:///./node_modules/axios/lib/core/dispatchRequest.js:59:10\nrun#webpack-internal:///./node_modules/core-js/modules/es6.promise.js:75:22\nnotify/<#webpack-internal:///./node_modules/core-js/modules/es6.promise.js:92:30\nflush#webpack-internal:///./node_modules/core-js/modules/_microtask.js:18:9\n"
​
__proto__: Object { stack: "", … }
I want to axios globally to use interceptors, hence calling it here in main.js. But if I use it in a view-page there is no error!
is this a bug or I'm doing it wrong? Kindly help me to fix this and use axios globally.
Thanks
so the error I see is here
Vue.use(axios)
Vue.use expects a vue installable plugin.
You could have a look at vue-axios
import axios from 'axios'
import VueAxios from 'vue-axios'
Vue.use(VueAxios, axios)
but I would highly discourage it.
It's best to create your own ApiHandler.js file that handles all the remote stuff separately, and you can easily call from anywhere including vue components and vuex.
here is the beginning of my class
<script>
import axios from 'axios';
class ApiHandler{
constructor(apiUrl) {
this.axios = axios;
this.apiUrl = apiUrl || ''; // this line allow passing a custom endpoint for testing
this.config = {
headers: { 'Cache-Control': 'no-cache' }, // can setup to prevent all caching
baseURL: this.apiUrl,
};
}
/**
* #param {Object} payload
* #param {String} payload.username
* #param {String} payload.password
*/
login({ username, password }) {
return new Promise((resolve, reject) => {
this.axios.post('/api/login', { username: username.toLowerCase(), password }, this.config)
.then((response) => {
if (response.code === 200 && response.body && response.body.token) {
resolve(response.body.token);
} else {
reject('Bad Login');
}
})
.catch((err) => {
reject('internal error');
});
});
}
}
</script>
you can then call this from anywhere by...
<script>
import ApiHandler from '../lib/ApiHandler';
const apiRequest = new ApiRequest();
// and then anywhere in the script
let payload = {
username:'someuser',
password:'somepassword',
};
apiRequest.login(payload)
.then(()=>{
// yay - I'm logged in
})
.catch(err => {
// oh oh, display error
})
</script>
this gives you much more flexibility and allows you to separate the remote actions and allows doing first-leg response handling separate of your component, which allows more re-usability.
instead of
Vue.use(axios);
you should
Vue.prototype.$axios = axios;
then you can use it globally
login() {
this.$axios.post('<host>/api/login', data)
.then((res) => { // dosomething })
.catch((err) => { // dosomething });
}
if you want to add globally interceptors with axios, you can
// Add a request interceptor
axios.interceptors.request.use(function (config) {
// Do something before request is sent
return config;
}, function (error) {
// Do something with request error
return Promise.reject(error);
});
// Add a response interceptor
axios.interceptors.response.use(function (response) {
// Do something with response data
return response;
}, function (error) {
// Do something with response error
return Promise.reject(error);
});
// and
Vue.prototype.$axios = axios;

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;