RxJS Observable on Axios how to get access to the Response - rxjs

I am working on getting a response from an HTTP POST in my NestJS project. I am using the HttpModule which wraps Observables from RxJS around Axios. here's some code:
async doSomething(bar: Bar) {
const resp = await this.httpService
.post(`${UPLOAD_URL}?app_token=111222333`, {
foo: bar
})
.pipe(map(response => response))
.toPromise()
.catch(err => {
this.logger.error(err)
})
this.logger.debug('response object')
this.logger.debug(resp)
}
In this particular case, I just want to see what the result of the resp object is. I'm getting a Converting circular structure to JSON error, though. So my question is, how would I view the response? I am okay with viewing it with the .toPromise() chain or without it. I'm not familiar with Observables so I convert it to a Promise. Not sure if that's a huge perf hit, but it isn't important for this question.

The map you are using is not helpful, as it does not actually do any mapping of the response. If you are wanting to log something in the observable without changing it you can use the tap operator and do something like
this.httpService().post(url, data).pipe(
tap((data) => console.log(data),
).toPromise()
the reason you are getting the Converting circular structure to JSON error is because the Nest Logger will JSON.stringify() objects and does not use a circular replacer. Consider stringifying the object yourself with a circular replacer, using console.log() or using a different logging library.

Related

Nest js promise interceptor

Is there a way for me to wrap a request in nest js inside a callback?
I'm trying to create a prisma transaction interceptor but the problem is that nest js interceptor requires an obserable as return type.
In order to achieve my goal I need to wrap my request in a callback like:
await prisma.$transaction(async p => {
await requestToBeFinished()
})
But all nest js provides me is an observable like
return next
.handle()
.pipe(
tap(() => {console.log('After execution')}),
);
Is there a solution to this?
Thanks

NGXS State documentation

I'm new to NGXS and I'm trying to fully understand the docs so I can start using it knowing what I'm doing.
There is one thing I don't understand in this code snippet from here.
export class ZooState {
constructor(private animalService: AnimalService) {}
#Action(FeedAnimals)
feedAnimals(ctx: StateContext<ZooStateModel>, action: FeedAnimals) {
return this.animalService.feed(action.animalsToFeed).pipe(tap((animalsToFeedResult) => {
const state = ctx.getState();
ctx.setState({
...state,
feedAnimals: [
...state.feedAnimals,
animalsToFeedResult,
]
});
}));
}
}
Just below this code, it says:
You might notice I returned the Observable and just did a tap. If we
return the Observable, the framework will automatically subscribe to
it for us, so we don't have to deal with that ourselves. Additionally,
if we want the stores dispatch function to be able to complete only
once the operation is completed, we need to return that so it knows
that.
The framework will subscribe to this.animalService.feed, but why?
The action, FeedAnimals, uses the injected service, AnimalService to feed the animals passed in the action's payload. Presumably the service is operates asynchronously and returns an Observable. The value of that Observable is accessed via the tap function and is used to update the ZooState state context based on completing successfully.
In order to use NGXS specifically and Angular in general, you really have to understand RxJS... here's my goto doc page for it

Intercept observables before subscription callback

I am using the following code to make get request:
makeGetReq$(url:string):Observable{
let getReqObservable;
getReqObservable = this.httpClient.get(url) //code for making get request
return getReqObservable
}
The problem is sometimes my backend might return {error:true, message} with status code 200. (I know thats weird).In that case I want to intecept getReqObservable and not allow its subscription callback to run.
image.component.ts
makeGetReq$(url:string):Observable{
let getReqObservable;
getReqObservable = this.httpClient.get(url)//code for making get request
return getReqObservable
.do((value)=>{
if(value.error){
//do not allow it to propagate further
})
})
You should propagate it further, but as an error rather than an event (i.e. do just like if your backend did the right thing and returned an error response):
makeGetReq$(url: string): Observable<Something> {
return this.httpClient.get<Something>(url).pipe(
mergeMap(value => value.error ? throwError(value) : of(value))
);
}
Otherwise, the calling method has no way to know that an error occurred, and thus can't execute the callbacks it might have registered for errors.
The easiest would probably be filter.
Filter items emitted by the source Observable by only emitting those that satisfy a specified predicate.
It would look like this:
return getReqObservable
.filter(value => !value.error)
It was pointed out, that you lose the notification completely if you just filter out the error case. There is of course the option to create a RxJS error notification with throwError, but it is also possible to just subscribe to the same source observable a second time with a different filter condition.
Be careful however to not call the backend twice, e.g. by using share.

Using the result of an AJAX call as an AMD module [duplicate]

This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 5 years ago.
I'm using RequireJS while prototyping an application. I'm "faking" a real database by loading a json file via ajax.
I have several modules that need this json file, which I noticed results in multiple http requests. Since I'm already using RequireJS, I thought to myself "hey, why not load this json file as another module". Since a module can return an object, it seemed reasonable.
So I tried this:
// data.js
define(function(require){
const $ = require('jquery')
var data = {}
$.getJSON('/path/to/data.json', function(json_data){
data = json_data
})
// this does not work because getJSON is async
return data
})
// some_module.js
define(function(require){
const my_data = require('data')
console.log(data) // undefined, but want it to be an object
})
I understand why what I'm doing is not working. I'm not sure what the best way to actually do this would be though.
Things I don't want to do:
Change getJSON to async: false
add a while (data == null) {} before trying to return data
Is there an AMD-y want to accomplish what I'm trying to do? I'm sure there's a better approach here.
Edit
I just tried this. It works, but I'm not sure if this is a good or terrible idea:
// in data.js
return $.getJSON('/path/to/data.json')
// in some_module.js
const my_data = require('data')
my_data.then(function(){
console.log(my_data.responseText)
// do stuff with my_data.responseText
})
My concern is (1) browser support (this is a "promise", right?) and (2) if multiple modules do this at the same time, will it explode.
Because this question is specifically referring to using JQuery, you can actually do this without a native promise using JQuery's deferred.then().
// in data.js
return $.getJSON('/path/to/data.json')
// in some_module.js
const my_data = require('data') // this is a JQuery object
// using JQuery's .then(), not a promise
my_data.then(function(){
console.log(my_data.responseText)
// do stuff with my_data.responseText
})
Based on the description of then() in JQuery's docs, it looks like this is using a promise behind the scenes:
As of jQuery 1.8, the deferred.then() method returns a new promise that can filter the status and values of a deferred through a function, replacing the now-deprecated deferred.pipe() method. [...]
Callbacks are executed in the order they were added. Since deferred.then returns a Promise, other methods of the Promise object can be chained to this one, including additional .then() methods.
Since JQuery's .then() does work in IE, I guess they are polyfilling the promise for IE behind the scenes.

How to manipulate async scope in angularjs

I have this defined in controller
$scope.files = {};
Then I have a ajax call to get data and pass to $scope.files;
In the same controller. I have a ng-click function which I want to manipulate $scope.files
How to do that because it is async. I tried and the $scope.files always return blank {}
$scope.click = function() {
//Do something to $scope.files;
}
My fault. this is not related to async. I can actually get the data.
My problem is the return data is object and I tried to use .length to get the length of object so it always return 0 and {}. And I found .length for array.
and Object.keys(a) for object sizes
Looks like you need to use promise/deferred implementation. Promises allow you to execute code and once the promise is returned then continue.

Resources