Angular6 - value of response header from one http request to another one as option without nested subscribes - header

I need to retrieve all specified records from an api endpoint using http get request. The information what is the of total records available is in the X-Total response header.
I tried to retrieve the value of X-Total response header with one http request and then passing the value to another http get request as the value of X-Size header - this approach resulted in nested subscribe:
getTotalRecords () {
return this.http.get('http://localhost:4200/api/loans/marketplace?', {
headers: new HttpHeaders({
'X-Size': '1'
}),
params: new HttpParams().set('rating__eq', 'A').set('fields', 'rating,amount'),
observe: 'response'
})
};
getData() {
this.getTotalRecords().subscribe(data => {
this.http.get('http://localhost:4200/api/loans/marketplace?', {
headers: new HttpHeaders({
'X-Size': data.headers.get('X-Total')
}),
params: new HttpParams().set('rating__eq', 'A').set('fields', 'rating,amount'),
observe: 'response'
}).subscribe(data => {
console.log(data.body);
})
})
};
This works but it seems to me like there has to be a better way of doing this. Also I have this code directly in a component because I wasn't able to make a service out of it - I don't know how to return an observable if I have to subscribe to one to create the other.
Thank you

You can use concatMap to invoke the inner Observable and then share before returning the Observable to make sure you won't make multiple HTTP calls when making multiple subscriptions:
getData() {
return this.getTotalRecords().pipe(
concatMap(data => this.http.get(...)),
share(),
);
}

Related

How to send an additional request to endpoint after each test case

I’m currently looking at Botium Box, and I’m wondering if it is possible to send an additional request to our endpoint after each test case? Let me give you some background information about how we set up the HTTP(S)/JSON connector in Botium Box and how we are sending information to our bot:
HTTP(S) endpoint:
https://MyChatBotsEndpoint.com/?userinput={{msg.messageText}}
HTTP method: POST
We also send cookies through the header template in the request builder. Like this:
{
"Cookie": "JSESSIONID={{context.sessionId}}"
}
The response is given back in JSON.
When a test ends (when it is successful but also when it fails), we need to send an additional request to our endpoint. The endpoint URL of that request should look like this:
https://MyChatBotsEndpoint.com/endsession
The header should include the cookie as described before.
Is there a way to achieve this in Botium?
Botium has many extension points to plug in your custom functionality. In this case, I guess the SIMPLEREST_STOP_HOOK is the best choice.
Write a small javascript file calling your endpoint, and register is with the SIMPLEREST_STOP_HOOK capability in botium.json. The context (session context from the HTTP/JSON connector) is part of the hook arguments.
in botium.json:
...
"SIMPLEREST_STOP_HOOK": "my-stop-hook.js"
...
my-stop-hook.js:
const request = require('request')
module.exports = ({ context }) => {
return new Promise((resolve, reject) => {
request({
method: 'GET',
uri: 'https://MyChatBotsEndpoint.com/endsession',
headers: {
Cookie: "JSESSIONID=" + context.sessionId
}
}, (err) => {
if (err) reject(err)
else resolve()
})
})
}

How do i call third party API data via fastify?

I had a small node server and I use the framework fastify.
In one of my routes, I want to get the data from a third party API.
I tried the following snippet:
fastify.route({
method: 'GET',
url: 'https://demo.api.com/api/v2/project/',
handler: async function ({ params, body}, reply) {
if (!body) return reply.send({ sucess: false })
console.log('testing')
console.log(body)
return reply.send({ sucess: true })
}
})
Unfortunately, I cannot call the URL by get because GET url's can only start with '/'.
How do i call a third pary api via fastify? do i need a extention?
If you need to define a route (like http://localhost:3000/) that proxies another server you need to use fastify-http-proxy.
Or if you need to call another endpoint and manage the response, there is the fastify.inject() utility but it is designed for testing.
Anyway, I think the best approach is to use some HTTP client like got
const got = require('got') // npm install got
fastify.get('/my-endpoint', async function (request, reply) {
const response = await got('sindresorhus.com')
console.log(response.body)
// DO SOMETHING WITH BODY
return { sucess: true }
})
Proxy your http requests to another server, with fastify hooks.
here is the example in fastify-http-proxy
server.register(require('fastify-http-proxy'), {
upstream: 'http://my-api.example.com',
prefix: '/api', // optional
http2: false // optional
})
https://github.com/fastify/fastify-http-proxy/blob/master/example.js

Axios - Remove headers Authorization in 1 call only

How can I remove the axios.defaults.headers.common.Authorization only in 1 call?
I'm setting the default for all the calls to my domain but I have 1 call that I make on another domain and if the token is passed the call gives me an error, when there's no default Auth token saved everything works fine.
So what I'm trying to do is not pass the Auth in that specific call
I tried this but it doesn't work
loadApiCoins({ commit }) {
Vue.axios({
method: 'get',
url: 'https://api.coinmarketcap.com/v1/ticker/',
headers: {
'Authorization': '',
},
}).then(...)
},
I also tried auth: {...} but that doesn't work either.
What's the solution?
Thanks
Try the following
delete axios.defaults.headers.common["Authorization"];
// or which ever header you have to remove
To send a request without:
Modifying global axios defaults
Creating a new axios instance
Change your request similarly to this:
axios.get('http://example.com', {transformRequest: (data, headers) => {
delete headers.common['Authorization'];
return data;
}
});
The answer I was looking for was posted in the comments of Apurva jain's answer, but hasn't been made an individual answer, so I've posted it separately for easy reference :)
if you already have a default 'Authorization' for all requests
you can create an instance for that specific request
var instance = axios.create();
delete instance.defaults.headers.common['Authorization'];
instance.get("http://api.com");
delete axios.defaults.headers.common["Authorization"];
will solve the problem. But remember to add the authorization header back.
I got the same issue trying to query S3 with my web-service auth token. Fixed it with this.
axios.get("http://api.com", {
headers:{ Authorization:""}
});
You can change the default headers to an empty string, this won't affect the common default headers. Though not entirely sure if all web services will ignore the empty string header.
A simple solution is to remove all common header from a new axios instance:
const awsAxios = axios.create({
transformRequest: (data, headers) => {
// Remove all shared headers
delete headers.common;
// or just the auth header
delete headers.common.Authorization;
}
});
delete request.defaults.headers.common.Authorization
That request should be return of a $axios.create()
To extend on #phantomraa's answer, you might want to use
this.$axios.$get(
url, {
// modify auth header for current request only
transformRequest: (data, headers) => {
// prevent the header from being added by default
delete headers.common['Authorization'];
// some libraries might set it directly as well, e.g. nuxtjs/auth
delete headers['Authorization'];
return data;
}
})
Sorry, need a bit more rep to just comment.
According to the latest axios Request Config documentation we can use transformRequest:
// This is only applicable for request methods 'PUT', 'POST', 'PATCH' and 'DELETE'
// The last function in the array must return a string or an instance of Buffer, ArrayBuffer,
// FormData or Stream
// You may modify the headers object.
An example:
axiosInstance.post('/api/auth-token', { email, password }, {
transformRequest: [
(data, headers) => {
delete headers.common['Authorization'];
return JSON.stringify(data);
},
],
});
Please note the call to JSON.stringify as mentioned in the documentation, you need to return a Buffer, ArrayBuffer, FormData or Stream.
const mynewinstance = axios.create();
mynewinstance.defaults.headers.common = {};
const output = await mynewinstance.get(`https://google.com`);
delete axios.defaults.headers.common["language"];

Angular 2 AuthHttp with jwt not connecting

I'm trying to use jwt's authHttp to set an API connection to a particular Back End. I'm trying to make it first without any token so I can test it but it seams like it's not even getting connected. I'm using it as following:
this.authHttp.get('localhost:3001/api/basic')
.subscribe(
data => console.log("data"),
err => console.log(err),
() => console.log('Request Complete')
);
The error I'm getting in the console is AuthHttpError {}
I've set my ngModules as it say in the guide:
providers: [
{
provide: AuthHttp,
useFactory: authHttpServiceFactory,
deps: [Http, RequestOptions]
}
And
function authHttpServiceFactory(http: Http, options: RequestOptions) {
return new AuthHttp(new AuthConfig({noTokenScheme : true}), http);
}
The thing that drive's me crazy is that using http it works fine like this:
this.http.get('http://localhost:3001/api/basic').subscribe(
data=> console.log(data),
error=> console.log("Getting Error")
);
You are probably thinking "Why he is not using http then instead of authHttp?". Well, that's because setting a heather "Authorization" and its token seams impossible with http.
Any help or guidance would be extremely helpful.
If you don't need JsonWebTokens but simply want to add custom headers, you can do it this way without having to import the angular2-jwt library :
In your service :
private customHeaders: Headers = this.setCredentialsHeader();
setCredentialsHeader() {
let headers = new Headers();
let credentials = window.localStorage.getItem('credentials2');
headers.append('Authorization', 'Basic ' + credentials);
return headers;
}
someMethod() {
let url = 'your.URL.to.API';
return this.http
.get(url, { headers: this.customHeaders })
.map(result => {
console.log(result);
});
}
This way you can add your Authorization header with the type of data you want.
If it's a Authorization Bearer type header you are looking for and use it with angular2-jwt, you can use the default configuration first before trying to provide your own AuthHttp instance through the factory. It will be much simpler to debug and figure where the problem is.
From the documentation : https://github.com/auth0/angular2-jwt#configuration-options
AUTH_PROVIDERS gives a default configuration setup:
In your module with your service, just import the AUTH_PROVIDERS like this :
import { AUTH_PROVIDERS } from 'angular2-jwt';
...
#NgModule({
...
providers: [
AUTH_PROVIDERS,
...
]
})
and simply use the AuthHttp instance in your service like you did.
You should see in the Navigator Network tab your headers being added to your request.
EDIT :
As stated in the documentation, it is appending the token value in the headers from the Token Getter Function defined in the AUTH_PROVIDERS by default.
You therefore need to add your JWT in your LocalStorage with the default name id_token.
To give you my working example, I'm setting a JWT upon the authentication process, where I get a JWT as a response from my Http Call :
auth.service.ts
this.identityService.setToken(token.accessToken);
identity.service.ts
setToken(token?) {
if (token) {
window.localStorage.setItem('id_token', token);
} else {
window.localStorage.removeItem('id_token');
}
}
You should be able to see your JWT in your network tab if done correctly.
Afterwards, the AuthHttp instance should add the headers to your requests as intended...
It might not work correctly if your Token is not a JWT. To check if it's a good one, you can use a website such as https://jwt.io/ where it will be decoded.
If it's still not working, this means the problem is coming from elsewhere. A service not provided correctly, etc.

Getting list with deep=true in Backand

I am having an issue getting relations backing using the deep parameter.
I'm using this url and am expecting it to return my related objects but is not.
url: Backand.getApiUrl() +"/1/objects/blogs?deep=true",
Yes, the deep works only for specific item because of performance reasons.
You should do /1/objects/blogs/1?deep=true
In general we suggest to query the blogs and from the client using promise to get the deep of each one.
If you must get it all at once, you can create server side on demand action, make the query and loop on the results while populating it with the deep. Because it runs on the server side it will be fast. here is a code example for the server-side action:
function backandCallback(userInput,dbRow,parameters,userProfile){
var response=$http({
method: "GET",
url: CONSTS.apiUrl+"/1/objects/blogs",
headers: {
"Authorization": userProfile.token
}
});
var mapping=response.data.map(function(item){
var object=item;
var user=$http({
method: "GET",
url: CONSTS.apiUrl+"/1/objects/users/"+item.author,
headers: {
"Authorization": userProfile.token
}
});
object.author_obj=user;
return object;
})
return mapping;
}