GraphQL resolvers - when to make resolver functions async or not? - graphql

I completed this tutorial on making a graphql-node backend server built on Prisma2 and GraphQL. The tutorial doesn't explain why it writes some Resolver functions async and some not.
I thought that the async was added to functions that interacted with the database, but you can see this resolver gets data from the database but doesn't use async. But in this resolver it does use async.
Can somebody please explain why there is this seemingly arbitrary usage of async? When and why I should use it? Thanks in advance.

The first thing you should do is read up on Promises. Promises are a way in JavaScript to encapsulate computations that are still ongoing. This is usually the case when you talk to an external service like a database or the operating system. They have been replacing callback style APIs.
In GraphQL a resolver can either return a value or a Promise that resolves to a value. This means, you can freely choose returning a value or a Promise, but if you call a database function like Prisma, you will get a Promise back, so you are kind of forced to stay "in Promise land", as there is no way to turn a Promise into a value. You can only chain functions, that should be executed with the value "in the future" (with then).
The last concept to understand is async/await. These async syntax is an addition to JavaScript syntax, that makes working with Promises easier. With await, you can stop the execution of a function until a value in a Promise arrives. Now, this looks like you are turning a Promise back into a value, but in reality, you function implicitly returns a Promise. For the VM to know about this, you have to state, that a function might use async by adding the keyword await in front of the function.
So when do you use async for a resolver? You could do it all the time, and the code would be correct. But doing it, even when you don't need to (e.g. you are not talking to a service) might have some performance implications. So it's better to only do it, if you really want to use the await keyword somewhere. I hope this can get you started with the concepts above, there is really a lot to learn. Maybe just go with your intuition and TypeScript errors until you deeply understand what is going on.

Related

Does toPromise() unsubscribe from the Observable?

I have not been able to find any normative text to answer this question. I have been using this code pattern (this is in TypeScript in an Angular application):
observeSomethingFun$: Observable<Fun>;
...
async loadsOfFun() {
const fun = await this.observeSomethingFun$.toPromise();
// I now have fun
}
In general, Observables need to be unsubscribed from. This happens automatically when the Angular async pipe is used but what happens in this case? Does toPromise unsubscribe after emitting one value?
If not, how do I unsubscribe manually?
Update:
It turns out #Will Taylor's answer below is correct but my question needs some clarification.
In my case the Observable emits a never-ending stream, unlike for example Angular's HttpClient Observables that complete after emitting one value. So
in my case I would never get past the await statement according to Taylor's answer.
RxJS makes this easy to fix. The correct statement turns out to be:
const fun = await this.observeSomethingFun$.pipe(first()).toPromise();
The RxJS first operator will receive the first value and unsubscribe from the source Observable. it will then send out that value to the toPromise operator
and then complete.
No need to unsubscribe.
Which is convenient, as there is no way to unsubscribe from a promise.
If the Observable completes - the promise will resolve with the last value emitted and all subscribers will automatically be unsubscribed at this point.
If the Observable errors - the promise will reject and all subscribers will automatically be unsubscribed at this point.
However, there are a couple of edge cases with toPromise in which the behavior is not completely clear from the docs.
If the Observable emits one or more values but does not complete or error, the promise will neither resolve or reject. In this case, the promise would hang around in memory, which is worth considering when working with toPromise.
If the Observable completes but does not emit a value, the promise will resolve with undefined.
First of all, thank you for this question and answer, I wrongly assumed toPromise() knew what it was doing in all scenarios and would unsubscribe when that observable completes (even if it is an observable stream)
So I will just say that it doesn't hurt to pipe all of your observables before using .toPromise()
I just went through a big ordeal of stepping through our app for memory leaks and found the above answer by Will to be good. The elaboration on the actual question was exactly the same issue I was running into.
We are stepping through each observable in the app right now and we use either
pipe(take(1)) which is equivalent to pipe(first()).
or we use pipe(takeUntil(this.destroyed)) where this.destroyed.next(true) is called when we destroy our particular component or service.
We use take() to keep our verbiage consistent so we can search for take or takeUntil across various components.
Long story short, yeah you might take a very slight performance hit piping your observables at each instance, but I highly recommend doing so in order to prevent any unwanted app-wide memory leak hunts. Then maybe if you have the time you can step through each one and see where .toPromise() actually unsubscribes correctly for you.

What is the difference between future and promise in vertx?

I usually see the use of either promise and future in the start of a vert.x verticle. Is there any specific difference between both?
I have read about their differences in Scala language, is it the same in case of Vert.x too?
Also when should I know when to use promise or a future?
The best I've read about:
think on Promise as producer (used by producer on one side of async operation) and Future as consumer (used by consumer on the other side).
Futures vs. Promises
Promise are for defining non-blocking operations, and it's future() method returns the Future associated with a promise, to get notified of the promise completion and retrieve its value. The Future interface is the result of an action that may, or may not, have occurred yet.
A bit late to the game, and the other answers say as much in different words, however this might help. Lets say you were wrapping some older API (e.g. callback based) to use Futures, then you might do something like this :
Future<String> getStringFromLegacyCallbackAPI() {
Promise<String> promise = Promise.promise();
legacyApi.getString(promise::complete);
return promise.future();
}
Note that the person who calls this method gets a Future so they can only specify what should happen in the event of successful completion or failure (they cannot trigger completion or failure). So, I think you should not pass the promise up the stack - rather the Future should be handed back and the Promise should be kept under the control of the code which can resolve or reject it.
A Promise as well is a writable side of an action that may or not have occurred yet.
And according to the wiki :
Given the new Promise / Future APIs the start(Future<Void>) and stop(Future<Void>) methods have been deprecated and will be removed in Vert.x 4.
Please migrate to the start(Promise) and stop(Promise) variants.
As a paraphrase,
A future is a read-only container for a result that does not yet exist, while a promise can be written (normally only once).
More from here

How to cancel http requests made by Apollo (angular) client?

I noticed that when I unsubscribe from query, http request is still executing and not being canceled. Also tried to use AbortController but without any luck. How does one cancel http requests made by Apollo client?
This is an old question, but since I just wanted to do the same and managed to do it with the latest Apollo Client (3.4.13) and Apollo-Angular (2.6.0), you need to make sure that you're using watchQuery() instead of query(), and then call unsubscribe() on the returned Apollo subscription from the previous request. The latter implies of course that you should store somewhere the subscription object that you want to abort.
This is an old question, but I spent two days on this bananas problem and I want to share for posterity.
We're using Angular and GraphQL (apollo-angular and codegen to make GraphQL services) and we opted for an event-driven architecture using NgRx to send events and then perform http calls. When sending multiple identical events (but with different property values) we noticed we got stale data in some cases, especially edge cases like when 20+ of these identical events were sent. Obviously not common, but not ideal, and a hint of perhaps bad scale since we were going to need many more events in future.
The way we resolved this issue was by using .watch() instead of .fetch() on the GraphQL generated services. Initially, since .fetch() returned the same Observable as .watch().valueChanges, we thought it was easier and simpler to just use .fetch(), but their behavior seems much different. We were never able to cancel http requests performed by .fetch(). But after changing to .watch().valueChanges, the Observable acted exactly as http request Observables would, complete with -- thankfully -- cancelation.
So in NgRx, we swapped our generic mergeMap operator for the switchMap operator. This will ensure previous effects listening on dispatched events will be canceled. We needed no extra overhead, no .next-ing to Subjects, no extra Subscriptions. Just change .fetch() into .watch().valueChanges and then switchMap to your heart's content. The takeUntil operator will now also cancel these requests, which is our performed method of unsubscribing from Observables.
Sidenote: I'm amazed that this information was this hard to come by, and honestly this question and one GitHub issue was all I could find to intimate this discrepancy. Even now I don't quite understand why anyone would want .fetch() if all it does is perform an http call that will always resolve and then return an Observable that does not behave the way you expect Observables to behave.

Promises without `.then`

Is there any downside to using a promise with only .catch section, but without .then at all?
I'm asking about the cases where the resolution result is not needed, only error handling.
Is this a good pattern to rely on .catch only and skip .then?
Or is it something that depends on which promise implementation it is?
Conceptually, there's nothing wrong with an operation that only has an error handler and has nothing else to do upon successful completion. If that's all it needs, then that's fine. For example, suppose you're updating a server with some new data from the client. If the data is successfully sent to the server, there's nothing else to do because the operation is complete, but if there's an error, then there is perhaps something else to do (retry, inform the user, correct the data based on the error code, etc...).
To comment on whether that's the right way to design your specific code, we'd have to see the actual code and understand what it is doing and then form an opinion on whether that is the best way to structure that specific code.
If I was designing a general purpose function, I'd certainly provide both completion (resolving the promise) and error (rejecting the promise) so the caller could hook into either one. But it is really up to the caller which events they want to know about and if only the error matters, then just having a .catch() is fine.

SaveEventually withCallback

Will ParseObject.saveEventually(SaveCallback cb) populate the parse object's object id before calling the callback's "done" method? There is nothing about this in the documentation and although I could experiment with trail/error, it wouldn't guarantee anything in all cases or in the future.
My usecase is to minimize web calls as much as possible and so I'd much rather grab the object ID on completion instead of having to call back to parse on completion to pull down the data if it's already available.

Resources