Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ability to configure custom JSON.parse reviver for the HttpClient #21079

Closed
bygrace1986 opened this issue Dec 18, 2017 · 20 comments
Closed

Ability to configure custom JSON.parse reviver for the HttpClient #21079

bygrace1986 opened this issue Dec 18, 2017 · 20 comments
Labels
area: common/http Issues related to HTTP and HTTP Client feature Issue that requests a new feature state: has PR
Milestone

Comments

@bygrace1986
Copy link

bygrace1986 commented Dec 18, 2017

I'm submitting a...


[x] Feature request

Current behavior

With the new HttpClient if the responseType is set to 'json' or if it is not set (defaulted to 'json') then the JSON is parsed before being returned to the consuming code. Here is the source-code where the JSON.parse occurs:

body = body !== '' ? JSON.parse(body) : null;

Expected behavior

A reviver function can be configured that the HttpClient will use when parsing json. As far as the implementation, maybe an injection token can be exposed which developers can use to provide a reviver function.

What is the motivation / use case for changing the behavior?

Dates are deserialized as strings with JSON.parse. It is convenient to have dates serialized to Date objects globally via a centralized service using a reviver.

@Toxicable
Copy link

You just ask for the body as text rather than json then parse it yourself

@bygrace1986
Copy link
Author

@Toxicable That is what I am already doing with an interceptor. So it isn't a major priority and with interceptors I am already better off than I was with pre 4.3. But it would be nice to have a hook rather than copying/pasting that section of code to match the XSSI prefix striping, error handling, and whatever else changes in the future. I would also like to be able to set the proper responseType rather than changing it as a way to opt-out.

@alxhub alxhub added area: common/http Issues related to HTTP and HTTP Client feature Issue that requests a new feature labels Dec 19, 2017
@ngbot ngbot bot added this to the Backlog milestone Jan 23, 2018
@TobiDimmel
Copy link

TobiDimmel commented Feb 8, 2018

+1. Same reason - for deserializing dates in a central place.
Maybe one provides even an option in HttpClient to turn date deserialization to Date objects on.

@bygrace1986
Copy link
Author

@tade90 I'd say that the MVP is to allow a reviver to be specified. This will allow custom deserialization in general and not everyone will want to deserialize dates to the JavaScript Date object. People may want to deserialize to 3rd party representations (moment, js-joda, ...) that are better suited for their use-cases (handling timezones, date arithmetic, ...).

To what you said about "turn date deserialization to Date objects on" we would first have to define what a date is since the JSON standard does not seem to specify a format for dates. There are several but I think that ISO 8601 is what most people probably want. Maybe angular could provide a reviver function that you could configure or even a flag, but if ISO 8601 is the standard then you can easily setup a reviver using Date.parse. So it might be something that is better solved by an example in the documentation related to configuring custom revivers.

@TobiDimmel
Copy link

@bygrace1986

I'd say that the MVP is to allow a reviver to be specified.

Totally agree. Making the reviver able to be specified should be the base. Everthing from there would be sugar-coating. But it would be easier to use if there are pre-defined reviver functions for common use-cases like date serialization. This could be similar to the DatePipe where you have some pre-defined formats ('short', 'medium', ...) and you also can define custom formats ('M/d/yy, h:mm a').

There are several but I think that ISO 8601 is what most people probably want.

ISO 8601 would fulfill my needs.

@ngbot ngbot bot modified the milestones: Backlog, needsTriage Feb 26, 2018
@dholcombe
Copy link

I am also looking for a way to specify a custom reviver. My use case is also due to the need to handle dates. In this case ISO 8601 dates of the form "1999-02-28" which I want to revivify as Luxon DateTime objects.

@ezequielzacca
Copy link

its such a common case im amazed this hasnt been implemented yet

@hjb417
Copy link

hjb417 commented Jun 14, 2018

There should be a dependency injected service (E.x.: JsonSerializationService with a serialize/deserialize method) responsible for serialization that's used through angular so we can easily swap in our own serializer. The out of the box implementation should just call JSON.parse and JSON.stringify. It would also be great if the HttpClient had a property to allow getting/setting the serializer it will use. It will default to the dependency injected JsonSerializationService but exposing this allows specifying the serializer for that specific instance of HttpClient.

This is all based on the premise that services can be replaced/overridden by reregistering them with 'providedIn: root'. If that's not possible, I'm hoping there are other means of doing so.

@selipso
Copy link

selipso commented Jul 18, 2018

+1

This would also be helpful in parsing JSON more accurately if the data contains large numbers and keeping significant digits is important with string conversion.

trotyl added a commit to trotyl/angular that referenced this issue Jul 22, 2018
trotyl added a commit to trotyl/angular that referenced this issue Jul 22, 2018
trotyl added a commit to trotyl/angular that referenced this issue Jul 22, 2018
trotyl added a commit to trotyl/angular that referenced this issue Jul 23, 2018
@dawidgarus
Copy link

@bygrace1986 reviver is not enough if You want to handle numbers with high precision like in {"test": 9999999999.9999999}. You would get value already converted to number: 10000000000.

@pfeigl
Copy link

pfeigl commented Dec 17, 2018

This would also provide a way cleaner way to incorporate libraries like https://github.com/typestack/class-transformer

@JohnGalt1717
Copy link

+1 Really need to do this for efficiency because JSON.parse(reviver) is way faster than parsing and then looping through every property.

@etay2000
Copy link

This seems like a pretty common sense feature, although I am not surprised it has been lingering since 2017. With 2500 open issues, what does it take to actually get a feature like this to even be acknowledged by the Angular team?

@Lonli-Lokli
Copy link

Lonli-Lokli commented Mar 4, 2020

I do not know, maybe there is some magic upvote counter number, until then all high-voted issues & feture requests will be ignored by Angular team?
Now you have Ivy, can we have our issues get closed not by bot?
It's even have PR!

@sdepouw
Copy link

sdepouw commented Mar 5, 2020

+1. Lots of sneaky bugs can happen when an Angular newbie like myself was happily receiving responses with my TypeScript model classes happily saying "yes, this object is a Foo, so of course you can call myFoo.customFunc()" only for JavaScript to whine that customFunc() is not a function on myFoo! (The most common scenario I run into is requiring a Date object, but it's secretly a string due to no reviver/proper deserialization occurring).

Right now, getting around this not only requires being cognizant of this fact for every new HTTP call I make (sometimes the default parser is fine, sometimes it isn't), but also requires the same boilerplate code to be copy-pasted (ew!) just about everywhere. (Remember: Angular newbie. Most likely better ways but not from someone who's just onboarding to TypeScript, etc!)

Please add this.

@f-mon
Copy link

f-mon commented Jul 21, 2020

+1 for having an angular native way to configure a custom replacer and reviver when doing JSON stringify and JSON parse of http requests, anyway i'm currently using an interceptor like this to do the job:

@Injectable()
export class SerializerHttpInterceptor implements HttpInterceptor {

  intercept(httpRequest: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any> > {

    if (httpRequest.responseType==="json") {
        const newHttpRequest = httpRequest.clone({
            responseType: "text",
            body: JSON.stringify(httpRequest.body,dateReplacer)
        });
        return next.handle(newHttpRequest)
            .pipe(
                filter(event => event instanceof HttpResponse),
                map((event: HttpResponse<any>) => event.clone({ 
                        body: JSON.parse(event.body,dateReviver)
                    }))
            );
    } else {
        return next.handle(httpRequest);
    }
  }

}

dateReplacer and dateReviver are custom functions that i'm using for handling Dates

petebacondarwin pushed a commit to trotyl/angular that referenced this issue Jan 26, 2021
@sanjuroo
Copy link

can't believe it is still not implemented

@petebacondarwin
Copy link
Member

@sanjuroo - there is a PR for this (#25027), which needs fixing up; and we are going to discuss the feature at today's framework meeting.

@petebacondarwin
Copy link
Member

petebacondarwin commented Jan 29, 2021

We discussed this in the team meeting yesterday. The general consensus is that this is actually fairly straightforward to do via an interceptor and that the real problem is the lack of discoverability of this approach to solving the problem.

We accept that the problem is compounded by the fact that HttpClient defaults to json parsing with its own parser and so the natural solution that people lean towards is replacing this built-in JSON parsing directly. It would have been better if the default had been text so that JSON parsing felt more like a special case that would lead more naturally to overriding via an interceptor.

The proposal then, is not to merge this feature into core, but instead to improve the documentation to lead developers clearly to an interceptor based solution.

Here is a link to an example of how custom JSON parsing could be done in a reusable interceptor: https://stackblitz.com/edit/angular-ivy-nrdj5q?file=src%2Fapp%2Fapp.module.ts. Note that this could be wrapped up and distributed as a 3rd party library and then the application developer would only need to provide their own JsonParser class.

petebacondarwin added a commit to petebacondarwin/angular that referenced this issue Jan 30, 2021
Update the HTTP guide and associated example to demonstrate
how an interceptor can be used to provide a custom JSON parser.

Resolves angular#21079
petebacondarwin added a commit to petebacondarwin/angular that referenced this issue Jan 30, 2021
Update the HTTP guide and associated example to demonstrate
how an interceptor can be used to provide a custom JSON parser.

Resolves angular#21079
petebacondarwin added a commit to petebacondarwin/angular that referenced this issue Jan 30, 2021
Update the HTTP guide and associated example to demonstrate
how an interceptor can be used to provide a custom JSON parser.

Resolves angular#21079
petebacondarwin added a commit to petebacondarwin/angular that referenced this issue Jan 31, 2021
Update the HTTP guide and associated example to demonstrate
how an interceptor can be used to provide a custom JSON parser.

Resolves angular#21079
petebacondarwin added a commit to petebacondarwin/angular that referenced this issue Feb 2, 2021
Update the HTTP guide and associated example to demonstrate
how an interceptor can be used to provide a custom JSON parser.

Resolves angular#21079
petebacondarwin added a commit to petebacondarwin/angular that referenced this issue Feb 3, 2021
Update the HTTP guide and associated example to demonstrate
how an interceptor can be used to provide a custom JSON parser.

Resolves angular#21079
josephperrott pushed a commit that referenced this issue Feb 16, 2021
Update the HTTP guide and associated example to demonstrate
how an interceptor can be used to provide a custom JSON parser.

Resolves #21079

PR Close #40645
@angular-automatic-lock-bot
Copy link

This issue has been automatically locked due to inactivity.
Please file a new issue if you are encountering a similar or related problem.

Read more about our automatic conversation locking policy.

This action has been performed automatically by a bot.

@angular-automatic-lock-bot angular-automatic-lock-bot bot locked and limited conversation to collaborators Mar 19, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area: common/http Issues related to HTTP and HTTP Client feature Issue that requests a new feature state: has PR
Projects
None yet