apollo-angular
apollo-angular copied to clipboard
Add support for request progress
Angular now provides support for monitoring the progress of HTTP requests through an observable.
https://angular.io/guide/http#listening-to-progress-events
It would be great if this could be exposed through apollo-angular.
If you're interested in posting a PR, I could guide you and give some help. Just let me know.
@kamilkisiela I would like to work on it.
Here is my thought how to implement it:
- Extend
HttpRequestOptions
type add new fieldreportProgress?: boolean
- Add that new field to request creation
const req: Request = {
.....
options: {
....
reportProgress: this.options.reportProgress || false
},
};
- In
util.ts
in link-http-common removereportProgress: false
from create httpClient request.
Could you please look through and give your opinion?
Thanks.
If it's disabled by default then sure, let's do it. Make sure user can enable/disable not only in Link's config but also through operation's context.
I've faced with two minor issues, that I don't know how to solve correct.
Since in tests execute
method are used (that come from appolo-link
package) that method not using my local code, so I don't get HttpEvent
response, I guess.
@kamilkisiela Could give me piece of advice? And Could you please explain what do you mean:
but also through operation's context.
What is operation's context?
Thanks.
@artem-galas https://github.com/artem-galas/apollo-angular/pull/1
I'm interested how you will ship the progress value to the consumer. Apollo.query and Apollo.watchQuery both resolve with Observable<ApolloQueryResult>
.
@kamilkisiela Thanks for your help.
Yes, I'm also interested how to deliver that functionality to consumer....
I'm thinking to make reportProgress
work we have to patch apollo-link
/ apollo-client
packages, but I'm not sure it's a good Idea, because these packages are really significant and we can not change them for angular needs :)
What do you think?
@artem-galas Maybe a directive (let's say @http
) inside of graphql operation? We can't break the interface of GraphQL Result.
Can I ask why you guys need to access this http progress thing? Can't that be done within http interception?
@kamilkisiela
To be honest I hardly ever use reportProgress
it might be useful when download/upload files and these operations dosen't not required GraphQL.
But might be for some heavy query it might be useful as well. But in that case it much more easy to implement it through the interceptor
Regarding directive @http
inside graphQl operation, do you mean something like?
qpl
@http
heroes {
name
}
I would really like to have this option without a "hack", but in this case I had to use rest.
I would also like to have this option. In our application we upload files that have 1GB. We use https://github.com/jaydenseric/graphql-multipart-request-spec for this together with apollo-upload-client but I use the interceptor "the hacky way" to track progress.
For those who want to be able to get the upload progress of files to their GraphQL endpoint yet don't want to hack around with apollo-upload-client, my solution was to simply reimplement the upload mutation using Angular's HttpClient
with this helpful article.
Something like this:
import { HttpClient, HttpEventType, HttpResponse } from '@angular/common/http';
import { FetchResult } from '@apollo/client/core';
import { Apollo } from 'apollo-angular';
import { print } from 'graphql';
import { from, throwError } from 'rxjs';
import { filter, map, switchMap, tap } from 'rxjs/operators';
import { MutationError, UploadFileGQL, UploadFileMutation } from 'src/graphql';
const formData = new FormData();
formData.append(
'operations',
JSON.stringify({
query: print(this.uploadFileGql.document),
variables: {
file: null,
},
}),
);
formData.append(
'map',
JSON.stringify({
file: ['variables.file'],
}),
);
formData.append('file', file, file.name);
this.http
.post('/graphql', formData, {
reportProgress: true,
observe: 'events',
})
.pipe(
tap((event) => {
if (event.type === HttpEventType.UploadProgress) {
// You can get the upload progress here!
console.log(Math.round((100 * event.loaded) / event.total!));
}
}),
filter((event) => event.type === HttpEventType.Response),
switchMap((event) => {
const body: FetchResult<UploadFileMutation> = (<HttpResponse<any>>event).body!;
if (!body.errors) {
// This query refetching is optional and is only available in Apollo client 3.4+.
return from(this.apollo.client.refetchQueries(['SomeQueriesToRefetch'])).pipe(map(() => body));
} else {
return throwError(body.errors);
}
}),
)
.subscribe(
({ data }: FetchResult<UploadFileMutation>) => {
},
);
Any update on this? :/