I'm trying to make a Http request in NestJS
As it's inspired from angular I jave append my Headers
import { Injectable, HttpService} from '#nestjs/common';
...
const headersRequest = new Headers();
headersRequest.append('Content-Type', 'application/json');
headersRequest.append('Authorization', `Basic ${encodeToken}`);
Then call the api
const result = await this.httpService.post(apiUrl, newDevice, { headers: headersRequest });
I get an error
ReferenceError: Headers is not defined
And when I ass Headers to import
I get this message waring in VScode
Only a void function can be called with the 'new' keyword.
NestJS uses axios under the hood to make http requests, take a look at its documentation for request configuration:
https://github.com/axios/axios#request-config
Looks like there is no interface for headers, just pass a plain JS dictionary object:
const headersRequest = {
'Content-Type': 'application/json', // afaik this one is not needed
'Authorization': `Basic ${encodeToken}`,
};
const result = await this.httpService.post(apiUrl, newDevice, { headers: headersRequest });
Another option (since nest v5 introduced HttpModule.registerAsync) if your encodeToken is pretty static or hardcoded from your config is setting it up in the module level:
import { Module, HttpModule } from '#nestjs/common';
import { ConfigModule } from '..';
import { ConfigService } from '../config/config.service';
#Module({
imports: [
ConfigModule,
HttpModule.registerAsync({
imports: [ConfigModule],
useFactory: async (configService: ConfigService) => ({
baseURL: configService.get('vendors.apiEndpoint'),
headers: {
'Authorization': 'Basic ' + configService.get('vendors.encodeToken')
},
timeout: 7000,
maxRedirects: 5
}),
inject: [ConfigService]
})
],
// ... other module stuff
})
export class MyModule {}
I think this method false
in for read headers parameter just req.headers
example
#Get()
findHeaderexample(#Res() res,#Req req) {
return req.headers;
}
If you want to set a custom header, you can use #ApiHeader()
#ApiHeader({
name: 'api-key',
description: 'api-key',
})
You could use withCredentials option as below:
export const HttpMessagingProvider = HttpModule.registerAsync({
imports: [ConfigModule],
useFactory: async (configService: ConfigService) => ({
baseURL: configService.get('vendors.apiEndpoint'),
timeout: 5000,
maxRedirects: 5,
withCredentials: true,
}),
inject: [ConfigService]
});
Related
I have this working:
export default axios.create({
baseURL: 'sample',
headers: {
'Content-Type': 'application/json',
},
transformRequest: [
(data) => {
return JSON.stringify(data);
},
],
});
but the problem is once I edited to be like this:
const API = () => {
const token = 'sample'
const api: AxiosInstance = axios.create({
baseURL: 'http://localhost:5000',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${token}`,
},
transformRequest: [
(data) => {
return JSON.stringify(data);
},
],
transformResponse: [
(data) => {
return JSON.parse(data);
},
],
});
return api;
};
export default API;
I want it to be an arrow function so I can access the token inside the function.
The problem is once I start to import the arrow function it will create an error not reading POST method
import API from 'apis';
API.post
Is there a way to implement it like an arrow function but will not lose the type definitions or create an error?
You don't loose any type definitions, but you're not using your import as a function.
If you write API().post it will work.
I would suggest doing the following:
import axios from 'axios';
const api = axios.create({
baseURL: 'http://localhost:5000',
headers: {
'Content-Type': 'application/json',
},
transformRequest: [
(data) => {
return JSON.stringify(data);
},
],
transformResponse: [
(data) => {
return JSON.parse(data);
},
],
});
import store from '../store'
const listener = () => {
const token = store.getState().token
api.defaults.headers.common['Authorization'] = token;
}
store.subscribe(listener)
export default api;
You can access the token here as well.
Just because this is the question you find when you look for my problem, if you use require to import axios, to use the correct type definition you'll have to import ti like that:
const axios = require('axios').default
axios.create(...) // No error
This would give an error:
const axios = require('axios')
axios.create(...) // Error
I have one api.js which exports by default an axios.create() instance:
import axios from 'axios'
import Cookies from 'js-cookie'
const api = axios.create({
baseURL: process.env.VUE_APP_API_URL,
timeout: 10000,
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${Cookies.get('Token')}`,
Organization: Cookies.get('Organization'),
Company: Cookies.get('Company')
}
})
export default api
Then I import this in multiple files like this:
//api/users.js
import api from './api.js'
const methods = {
postUser (params) {
return api.post('/users', params)
},
getUser (id) {
return api.get('/users/' + id)
}
}
export default methods
However there will be some functions that should update the Cookies Organization and Company and I was wondering if is possible to update the default api instance and automatically update it in all imports that use it. I know a simple page refresh would work but I'm building a SPA and I would like to prevent screen to be manually refreshed.
You can add the headers dynamically, that way the cookies will be read on every request.
import axios from 'axios'
import Cookies from 'js-cookie'
const api = axios.create({
baseURL: process.env.VUE_APP_API_URL,
timeout: 10000,
// Static headers
headers: {
'Content-Type': 'application/json',
},
transformRequest: [function (data, headers) {
// You may modify the headers object here
headers['Authorization'] = `Bearer ${Cookies.get('Token')}`
headers['Organization'] = Cookies.get('Organization')
headers['Company'] = Cookies.get('Company')
// Do not change data
return data;
}],
})
export default api
I would suggest to read about interceptor for axios. (https://github.com/axios/axios#interceptors)
A very basic example would be the following.
Lets assume your webservice would return a response http status 401 header.
You'd intercept the response with the following:
// Add a response interceptor
axios.interceptors.response.use(function (response) {
// happy case its 2XX
return response;
}, async (error) => {
if (error.response.status === 401) {
// do some logic to retrieve a new JWT or Cookie.get()
const jwt = Cookies.get('Token');
const config = error.config;
config.headers['Authorization'] = `Bearer ${jwt}`;
}
return await axios.request(config);
});
The next request will then have an authorization header attached to the request header.
I have this axios object, and I have noticed that sometimes it fails to get accesstoken because of async issues.
How would you go about awaiting Cookies.get('accesstoken')
This is my code
import axios from 'axios';
import constants from '../constants.js';
import Cookies from 'js-cookie';
const API = axios.create({
baseURL: `${constants.urlBackend}`,
timeout: 10000,
// headers: {
// 'Content-Type': 'application/json'
// },
});
API.interceptors.request.use(
config => {
var accesstoken = Cookies.get('accesstoken');
if (accesstoken) {
config.headers.Authorization = `Bearer ${accesstoken}`;
} else {
delete API.defaults.headers.common.Authorization;
}
return config;
},
error => Promise.reject(error)
);
export default API;
I dont think I can wrap the API.interceptos.request.use in an async function, or at least it didnt seem to work
I have to put a token inside the 'Authorization' header for every HTTP request.
So I have developed and registered an HttpInterceptor :
#Injectable()
export class TokenInterceptor implements HttpInterceptor {
constructor(public authService: AuthService) {
}
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
let modifiedReq;
const token = this.authService.getToken();
// we need the heck clone because the HttpRequest is immutable
// https://angular.io/guide/http#immutability
if (token) {
modifiedReq = request.clone();
modifiedReq.headers.set('Authorization', `Bearer ${token}`);
}
return next.handle(modifiedReq ? modifiedReq : request).pipe(tap(() => {
// do nothing
},
(err: any) => {
if (err instanceof HttpErrorResponse) {
if (err.status === 0) {
alert('what the heck, 0 HTTP code?');
}
if (err.status !== 401) {
return;
}
this.authService.goToLogin();
}
}));
}
}
But the header seems never to be put on the request sent. What am I doing wrong?
Also, sometimes an errorcode '0' gets caught by the interceptor; what does it mean?
Angular 8.2.11
EDIT 1: ------------------------
I've also tried like this:
request = request.clone({
setHeaders: {
authorization: `Bearer ${token}`
}
});
but still no header has been set.
Also, the module is correctly registered in app.module
providers: [{
provide: HTTP_INTERCEPTORS,
useClass: TokenInterceptor ,
multi: true,
}..
EDIT 2 : ------------------------
Check this image... I'm going crazy.
It's working for me like this:
const headersConfig = {
'Accept': 'application/json', //default headers
};
...
if (token) {
headersConfig['Authorization'] = `Bearer ${token}`;
}
...
return next
.handle(request.clone({
setHeaders: headersConfig
}))
maybe you forget to put in app.module this:
providers: [{
provide: HTTP_INTERCEPTORS,
useClass: TokenInterceptor ,
multi: true,
}..
the final part write in this way:
return next.handle(modifiedReq);
I was wrong. When doing update of the clone request, angular will put the new headers in fields called "lazyUpdate" and not direcly inside the headers.
The requests were failing because of other reasons.
I have a problem. I have a Vuex state. Also I am making axios request. I have created a separate file for template axios request with predefined header. It looks like this:
import axios from 'axios'
import store from '../store/index'
export default axios.create({
baseURL: 'https://k-3soft.com/',
timeout: 1000,
headers: {
'X-Requested-With': 'XMLHttpRequest',
'Accept': 'application/json',
'Content-Type': 'application/json',
'Authorization': `Bearer ${store.getters.getToken}`
}
})
The problem is that in this case store in undefined. So how can I import to this /src/axios/request.js file my vuex store?
Also I have tried import { store } from '../store/index'.
My store looks like this:
import Vue from 'vue'
import Vuex from 'vuex'
import user from './modules/user'
Vue.use(Vuex)
export default new Vuex.Store({
namespaced: true,
modules: {
user
},
state: {
url: 'https://icfprod.k-3soft.com/',
token: '',
},
getters: {
getToken: state => state.token
},
})
Also may by anyone can share to view any repository where there is Vuex with modules, axios with file with separate predefined template. Just wanna see how to organize my project's structure. Thanks everyone for help.
Use a factory function to create the axios instance.
// request.js
import axios from 'axios'
const createAxiosInstance = (token) => {
return axios.create({
baseURL: 'https://k-3soft.com/',
timeout: 1000,
headers: {
'X-Requested-With': 'XMLHttpRequest',
'Accept': 'application/json',
'Content-Type': 'application/json',
'Authorization': `Bearer ${token}`
}
}
})
export default createAxiosInstance
Then use it in a module like:
// user.js
import createAxiosInstance from '../request.js'
const userModule = {
// ...
actions: {
async doSomeAction ({ state, commit, rootState }) {
const axios = createAxiosInstance(rootState.token)
const response = await axios.post('/some/api/endpoint')
.then(response => response)
.catch(error => {
// handle error
})
commit('SOME_MUTATION', response.data)
}
}
}