Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

feat(common): support custom JSON parser in HttpClient#25027

Closed
trotyl wants to merge 1 commit intoangular:masterangular/angular:masterfrom
trotyl:json-custom-parsetrotyl/angular:json-custom-parseCopy head branch name to clipboard
Closed

feat(common): support custom JSON parser in HttpClient#25027
trotyl wants to merge 1 commit intoangular:masterangular/angular:masterfrom
trotyl:json-custom-parsetrotyl/angular:json-custom-parseCopy head branch name to clipboard

Conversation

@trotyl
Copy link
Contributor

@trotyl trotyl commented Jul 22, 2018

closes #21079

PR Checklist

Please check if your PR fulfills the following requirements:

PR Type

What kind of change does this PR introduce?

[ ] Bugfix
[x] Feature
[ ] Code style update (formatting, local variables)
[ ] Refactoring (no functional changes, no api changes)
[ ] Build related changes
[ ] CI related changes
[ ] Documentation content changes
[ ] angular.io application / infrastructure changes
[ ] Other... Please describe:

What is the current behavior?

Issue Number: #21079

When user works with an extended JSON format, eg. JSON5, due to it's not compatible with JSON.parse(), user have to make it raw text and parse it manually.

But JSON5 format is still conceptually 'json' rather than 'text', it's a fully superset of ES JSON, just being more human friendly.

What is the new behavior?

Simply with:

@NgModule({
  providers: [
    { provider: JsonParser, useValue: JSON5 }
  ]
})
class AppModule {}

Or strip a different receiver:

class MyJsonParser implements JsonParser {
  parse(text: string, reviver?: (key: any, value: any) => any): any {
    const strippedText = text.trimStart(CUSTOM_XSSI)
    return JSON.parse(strippedText, reviver)
  }
}

Or have a different reviver:

class MyJsonParser implements JsonParser {
  parse(text: string, reviver?: (key: any, value: any) => any): any {
    const wrappedReviver = wrapReviver(reviver)
    return JSON.parse(text, wrappedReviver)
  }
}

Then server could provide JSON5 response directly and no error would be raised.

Does this PR introduce a breaking change?

[ ] Yes
[x] No

Other information

@trotyl trotyl force-pushed the json-custom-parse branch 2 times, most recently from 6ed46ea to 18ad2a9 Compare July 22, 2018 13:51
packages/common/http/src/module.ts Outdated Show resolved Hide resolved
packages/common/http/src/xhr.ts Outdated Show resolved Hide resolved
@trotyl trotyl force-pushed the json-custom-parse branch from 18ad2a9 to 31a9d98 Compare July 23, 2018 05:00
@vicb vicb added area: common Issues related to APIs in the @angular/common package area: common/http Issues related to HTTP and HTTP Client and removed area: common/http Issues related to HTTP and HTTP Client labels Jul 23, 2018
@pkozlowski-opensource pkozlowski-opensource added area: common/http Issues related to HTTP and HTTP Client and removed area: common Issues related to APIs in the @angular/common package labels Dec 19, 2018
@ngbot ngbot bot added this to the needsTriage milestone Dec 19, 2018
@Lonli-Lokli
Copy link

What should be done to accept this PR?

Copy link
Contributor

@petebacondarwin petebacondarwin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@trotyl thanks for this PR. I am sorry it slipped under our radar for so long. I rebased it and cleaned up the conflicts. But I have a few suggestions for how to make it a bit slimmer.

@Injectable()
export class HttpXhrBackend implements HttpBackend {
constructor(private xhrFactory: XhrFactory) {}
constructor(private xhrFactory: XhrFactory, @Inject(JSON_PARSER) private jsonParser: JsonParser) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about making this optional, then we wouldn't have to define a provider for the default case:

Suggested change
constructor(private xhrFactory: XhrFactory, @Inject(JSON_PARSER) private jsonParser: JsonParser) {
constructor(private xhrFactory: XhrFactory, @Optional() @Inject(JSON_PARSER) private jsonParser?: JsonParser) {
if (jsonParser == null) { // note == matches both `null` and `undefined`
this.jsonParser = JSON;
}

beforeEach(() => {
factory = new MockXhrFactory();
backend = new HttpXhrBackend(factory);
backend = new HttpXhrBackend(factory, JSON);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If jsonParser was optional this would not need to change.

const XSSI_PREFIX = /^\)\]\}',?\n/;

/**
* Utility for parsing JSON text to JavaScript object
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we would need a bit more documentation for this and the JSON_PARSER token below, ideally with an example and referencing each other.

Comment on lines +134 to +136
export function _JSON(): JsonParser {
return JSON;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If jsonParser was optional then this would not be needed.

@petebacondarwin
Copy link
Contributor

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 parseing 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.

@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 1, 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 cla: yes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Ability to configure custom JSON.parse reviver for the HttpClient

8 participants

Morty Proxy This is a proxified and sanitized view of the page, visit original site.