I am implementing axios interceptor in tsx for react native expo. I am geting following error:
TypeError: axios.create is not a function. (In 'axios
.create()', 'axios.create' is undefined).
How can I solve this?
Version for axios: "axios": "^1.2.1",
import { _retrieveData } from "./AsyncStorage";
const configData = require('../config/config.json');
const axios = require('axios');
const userApi = axios.create();
userApi.defaults.timeout = 4000;
userApi.interceptors.request.use(async (config: any) => {
const token = await _retrieveData('token');
config.headers.common = { 'Authorization': `Bearer ${token}` }
return config;
}, (error: any) => {
return Promise.reject(error);
});
export default userApi;
I'm new to React Native and I'm trying to send axios request to my backend but I'm stuck in it.
export const login = (email, password) => async dispatch => {
const config = {
headers: {
'Content-Type': 'application/json'
}
};
const body = JSON.stringify({ email, password });
const res = await axios.post(`http://localhost:8000/auth/jwt/create/`, body, config);
console.log('kk');
dispatch({
type: LOGIN_SUCCESS,
payload: res.data
});
dispatch(load_user());
};
when it tries to post request through axios it gives following error.
although I haved tried this in React JS and it's working perfectly.
please help me to solve this in react native
Per the React Native Networking Docs, React Native supports the fetch web API for sending requests. I advise you use fetch instead of axios as it has all of the same features without any added bloat and overhead. Here is a port of your code to use fetch:
export const login = (email, password) => async (dispatch) => {
const res = await fetch(`http://localhost:8000/auth/jwt/create/`, {
method: "POST", // this signnifies POST request type
body: JSON.stringify({ email, password }), // still including the body
headers: {
// apply the headers
"Content-Type": "application/json"
}
});
const data = await res.json(); // parses the body as a json object
console.log("kk");
dispatch({
type: LOGIN_SUCCESS,
payload: data
});
dispatch(load_user());
};
Try to use this way:
// define axios request
import axios from 'axios';
const request = axios.create({
baseURL: 'https://url.com/api/v1',
timeout: 20000,
});
request.interceptors.request.use(
config => {
// config.headers.Authorization = `Bearer ${token}`;
config.headers.Accept = 'Application/json';
return config;
},
error => {
//return Promise.reject(error);
console.log("interceptors.request: ", error);
return false;
},
);
request.interceptors.response.use(
response => {
if (response && response.data) {
return response.data;
}
return response;
},
error => {
console.log('Response error: ', error);
//throw error;
return false;
},
);
export default request;
Usage:
import request from '../';
export const getAPI = () => {
return request({
url: '/getData',
method: 'GET',
// ...
});
};
getAPI().then(response => {
//...
});
I'm doing a little api with register and auth using jwt, apollo-vue and graphql
I can`t get data through queries (or set it through mutations) from/to my backend.
But i can do it from Postman, cause i know how to send a token in the headers.
I'm too try to call onLogin(apolloClient, token) bellow the action login from vuex. Nothings work
I'm very newby with backend, i will appreciate any advice
Another problem? : If in the function below...
const authLink = setContext(async (_, { headers }) => {
// add here console.log(localStorage.getItem('apollo-token'))
const token = await localStorage.getItem('apollo-token')
// and then console.log(token)
return {...}
})
The first console print a token, but the second console print null. This is weird for me.
This is my vue-apollo.js
import Vue from 'vue'
import VueApollo from 'vue-apollo'
import { createApolloClient, restartWebsockets } from 'vue-cli-plugin-apollo/graphql-client'
import { setContext } from 'apollo-link-context'
Vue.use(VueApollo)
const AUTH_TOKEN = 'apollo-token'
// Http endpoint
const httpEndpoint = process.env.VUE_APP_GRAPHQL_HTTP || 'http://localhost:3000/graphql'
const authLink = setContext(async (_, { headers }) => {
const token = await localStorage.getItem(AUTH_TOKEN)
return {
...headers,
Authorization: token || ''
}
})
// Files URL root
export const filesRoot = process.env.VUE_APP_FILES_ROOT || httpEndpoint.substr(0, httpEndpoint.indexOf('/graphql'))
Vue.prototype.$filesRoot = filesRoot
// Config
const defaultOptions = {
httpEndpoint,
wsEndpoint: null,
tokenName: AUTH_TOKEN,
websocketsOnly: false,
ssr: false,
link: authLink
}
export const { apolloClient } = createApolloClient({
...defaultOptions,
})
export function createProvider(options = {}) {
const { apolloClient, wsClient } = createApolloClient({
...defaultOptions,
...options,
})
apolloClient.wsClient = wsClient
const apolloProvider = new VueApollo({
defaultClient: apolloClient,
defaultOptions: {
$query: {
// fetchPolicy: 'cache-and-network',
},
},
errorHandler(error) {
// eslint-disable-next-line no-console
console.log('%cError', 'background: red; color: white; padding: 2px 4px; border-radius: 3px; font-weight: bold;', error.message)
},
})
return { apolloProvider, apolloClient }
}
// Manually call this when user log in
export async function onLogin(apolloClient, token) {
if (typeof localStorage !== 'undefined' && token) {
localStorage.setItem(AUTH_TOKEN, token)
}
if (apolloClient.wsClient) restartWebsockets(apolloClient.wsClient)
try {
await apolloClient.resetStore()
} catch (e) {
// eslint-disable-next-line no-console
console.log('%cError on cache reset (login)', 'color: orange;', e.message)
}
}
// Manually call this when user log out
export async function onLogout(apolloClient) {
if (typeof localStorage !== 'undefined') {
localStorage.removeItem(AUTH_TOKEN)
}
if (apolloClient.wsClient) restartWebsockets(apolloClient.wsClient)
try {
await apolloClient.resetStore()
} catch (e) {
// eslint-disable-next-line no-console
console.log('%cError on cache reset (logout)', 'color: orange;', e.message)
}
}
main.js from vue
// HTTP connection to the API
const httpLink = createHttpLink({
// You should use an absolute URL here
uri: 'http://localhost:3000/graphql',
})
// Cache implementation
const cache = new InMemoryCache()
// Create the apollo client
const apolloClient = new ApolloClient({
link: httpLink,
cache,
})
Vue.config.productionTip = false
Vue.use(VueScreen)
.use(VueApollo)
const apolloProvider = new VueApollo({
defaultClient: apolloClient,
})
new Vue({
router,
store,
vuetify,
apolloProvider,
render: h => h(App)
}).$mount('#app')
EDIT: more code
This is the query, in a view on vue
import gql from "graphql-tag";
export default {
name: "Home",
apollo: {
Users: gql`
{
Users {
_id
username
email
password
token
createdAt
}
},
`,
},
};
The error that i receive is:
bundle.esm.js:75 POST http://localhost:3000/graphql 500 (Internal Server Error)
Error sending the query 'Users' ServerError: Response not successful: Received status code 500
at throwServerError
In the backend, this is my query
Query: {
async Users(_, req, context) {
const auth = checkAuth(context)
if (auth.id) {
const users = await User.find()
users.forEach(e => {
e.password = null
})
return users
} else {
return new Error("must be logged.")
}
},
and this is my checkAuth.js
import jwt from 'jsonwebtoken'
import { AuthenticationError } from 'apollo-server'
import 'dotenv/config'
module.exports = (context) => {
const authHeader = context.headers.authorization;
console.log("headers: ",context.headers)
if (authHeader) {
const token = authHeader.split('Bearer ')[1];
if (token) {
try {
const user = jwt.verify(token, process.env.SECRET_KEY);
return user
} catch (err) {
return new AuthenticationError("Invalid token.")
}
}
return new Error("Token must be 'Bearer [token]'")
}
return new Error("I need a token bro!")
}
EDIT 2
the context.header received on the backend
headers: {
host: 'localhost:3000',
connection: 'keep-alive',
'content-length': '160',
'sec-ch-ua': '"Chromium";v="92", " Not A;Brand";v="99", "Google Chrome";v="92"',
accept: '*/*',
'sec-ch-ua-mobile': '?0',
'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Safari/537.36',
'content-type': 'application/json',
origin: 'http://localhost:8081',
'sec-fetch-site': 'same-site',
'sec-fetch-mode': 'cors',
'sec-fetch-dest': 'empty',
referer: 'http://localhost:8081/',
'accept-encoding': 'gzip, deflate, br',
'accept-language': 'es-419,es;q=0.9,en;q=0.8'
},
The vue-apollo.js file is not used.
In your main.js the apolloClient you inject in Vue is declared in the main.js and doesn't contain the authLink. All your code in vue-apollo.js isn't called.
So instead of this:
// HTTP connection to the API
const httpLink = createHttpLink({
// You should use an absolute URL here
uri: 'http://localhost:3000/graphql',
})
// Cache implementation
const cache = new InMemoryCache()
// Create the apollo client
const apolloClient = new ApolloClient({
link: httpLink,
cache,
})
Vue.config.productionTip = false
Vue.use(VueScreen)
.use(VueApollo)
const apolloProvider = new VueApollo({
defaultClient: apolloClient,
})
new Vue({
router,
store,
vuetify,
apolloProvider,
render: h => h(App)
}).$mount('#app')
Try this:
import { createProvider } from 'vue-apollo.js';
Vue.config.productionTip = false
Vue.use(VueScreen)
.use(VueApollo)
const { apolloProvider, apolloClient } = createProvider();
new Vue({
router,
store,
vuetify,
apolloProvider,
render: h => h(App)
}).$mount('#app')
From what i see, you only send the token in the authorization header.
const authLink = setContext(async (_, { headers }) => {
const token = await localStorage.getItem(AUTH_TOKEN)
return {
...headers,
Authorization: token || ''
}
})
but in the backend you expect to find a bearer token:
module.exports = (context) => {
const authHeader = context.headers.authorization;
console.log("headers: ",context.headers)
if (authHeader) {
const token = authHeader.split('Bearer ')[1]; << Your code is breaking here
if (token) {
try {
const user = jwt.verify(token, process.env.SECRET_KEY);
return user
} catch (err) {
return new AuthenticationError("Invalid token.")
}
}
return new Error("Token must be 'Bearer [token]'")
}
return new Error("I need a token bro!")
}
You must send 'Bearer [token]' instead of just the token. Like so:
const authLink = setContext(async (_, { headers }) => {
const token = await localStorage.getItem(AUTH_TOKEN)
return {
...headers,
Authorization: `Bearer ${token}`
}
})
In the documentation this is how setContext is used:
const setAuthorizationLink = setContext((request, previousContext) => ({
headers: {authorization: "1234"}
}));
The setContext function takes a function that returns either an object or a promise that returns an object to set the new context of a request.
In the code below you only return the headers. When you're supposed to return the context.
const authLink = setContext(async (_, { headers }) => {
const token = await localStorage.getItem(AUTH_TOKEN)
return {
...headers,
Authorization: token || ''
}
})
Try this instead
const authLink = setContext(async (_, { headers }) => {
const token = await localStorage.getItem(AUTH_TOKEN)
return {
headers: {
...headers,
Authorization: token || ''
}
}
})
I am getting access token after login and I want to assign that token to authorization in headers in my App.js
I am using async storage to store the access token in local storage and I want to assign to headers in my App.js file How can I do it. I want to assign token to authorization in headers so that I can make graphql API calls
MY App.js file
import React, {Component} from 'react';
import {AppRegistry,SafeAreaView, StyleSheet} from 'react-native';
import Navigator from "#Navigation"
import AsyncStorage from '#react-native-community/async-storage';
import { createHttpLink } from 'apollo-link-http';
import { setContext } from 'apollo-link-context';
import { ApolloProvider } from 'react-apollo';
import { ApolloClient } from 'apollo-client';
import { InMemoryCache } from 'apollo-boost';
const httpLink = createHttpLink({
uri: 'https://graphql.sample.com/graphql',
});
const token = AsyncStorage.getItem('#accessToken')
const authLink = setContext((_, { headers }) => {
return {
headers: {
...headers,
authorization: token ,
}
}
});
const link = authLink.concat(httpLink)
const cache = new InMemoryCache();
const defaultOptions = {
query: {
fetchPolicy: "network-only",
errorPolicy: "all"
}
};
const client = new ApolloClient({
link,
cache,
defaultOptions
});
class App extends Component {
render() {
return (
<ApolloProvider client={client}>
<Navigator/>
</ApolloProvider>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1
},
});
export default App;
Changing the authLink function to work with async/await worked for me! Hope this helps;
const authLink = setContext(async (_, { headers }) => {
// get the authentication token from async storage if it exists
const accessToken = await AsyncStorage.getItem('#accessToken');
// return the headers to the context so httpLink can read them
return {
headers: {
...headers,
authorization: accessToken ? `Bearer ${accessToken}` : '',
},
};
});
You should await AsyncStorage.getItem('#accessToken') to get your accessToken before passing it to authorization: token. This is a post relating to Waiting for AsyncStorage.getItem() in React Native.Try this:
...
const token = await AsyncStorage.getItem('#accessToken')
const authLink = setContext((_, { headers }) => {
return {
headers: {
...headers,
authorization: token ,
}
}
});
...
Problem:
I have create react-native application.And there I am using AsyncStorage with axios in like this to handle my API calls.This is how that looks like.
import axios from "axios";
import { AsyncStorage } from "react-native";
// TODO: Replace this with actual JWT token from Keycloak
axios.defaults.headers.post["Content-Type"] = "application/json";
// Create axios instance for api calls
var instance = null;
export const setAuth = async () => {
const user = await AsyncStorage.getItem("jwt");
AsyncStorage.getItem("jwt").then(token => {
instance = axios.create({
baseURL: "",
timeout: 150000,
headers: {
Authorization: "Bearer " + token,
"Content-Type": "application/json"
}
});
instance.interceptors.response.use(
function(response) {
return response;
},
async function(error) {
if (error.response.status) {
return error;
}
}
);
});
};
export const Get = (route, data) => {
instance || setAuth();
return instance.get(
route,
data == null ? { data: {} } : { data: JSON.stringify(data) }
);
};
export const Post = (route, data) => {
instance || setAuth();
return instance.post(route, JSON.stringify(data));
};
export const Put = (route, data) => {
debugger;
instance || setAuth();
return instance.put(route, JSON.stringify(data));
};
export const AddAdmin = (route, data) => {};
Becuase of the asynchronus property of AsyncStorage it is not creating the axios instanceinstance = axios.create({.The problem is with after this line .So can someone help me with this.I do not have any idea to find out what is wrong with this. Thank you.
You can give a try to this.
export const setAuth = async () => {
const token = await AsyncStorage.getItem('jwt');
instance = axios.create({
baseURL: '',
timeout: 150000,
headers: {
Authorization: 'Bearer ' + token,
'Content-Type': 'application/json'
}
});
// remaining Code
};
export const Get = (route, data) => {
function getData(){
return instance.get(
route,
data == null ? { data: {} } : { data: JSON.stringify(data) }
)
}
if(instance) return getData()
return setAuth().then(getData)
}