Skip to content

Instantly share code, notes, and snippets.

@pkozlowski-opensource
Last active August 29, 2015 14:11
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pkozlowski-opensource/5a57d28ccfeacaba7661 to your computer and use it in GitHub Desktop.
Save pkozlowski-opensource/5a57d28ccfeacaba7661 to your computer and use it in GitHub Desktop.
$http and request param serialisation issues

Issues description

"Hard-coded" serialization format for request parameters

The current version of the $http service has a hard-coded way of serializing request parameters. This one-and-only-one way of doing things causes practical problems to people using backends that have different serialziation schemas (mostly Rails and PHP).

More specifically, given this $http call:

$http.get('http://google.com', {params: {foo: [1 ,2], bar: 'sth;else'}});

a URL produced by the default serialization schema will be:

http://google.com?foo=1&foo=2&bar=sth;else

This is unfortunatelly not the format expected by some (many?) people:

  • PHP / Rails users would expect an array to be serialised to request params as: foo[]=1&foo[]=2&bar=sth;else
  • there is a question of special chars encoding - in this particular case ; is expected to be percent-encoded by some backends

More generally, users might use backends that use a completly different serialisation schema, ex.:

http://google.com;foo=[1,2];bar=sth%3Belse

This per-backend variability of the URL serialization schema indicates that a URL building mechanism used by AngularJS should be configurable / overridable for users, instead of being fixed deep inside the framework.

Testing considerations

As of today people are using $httpBackend mock to test $http-based code. The problem here is that while writing they functional code people operate on a different abstraction level as compared to tests (that are expressed in terms of backend interactions and not higher-level $http interactions). One practical consequence of this approach is that people needs to re-construct a URL in their tests. In other words they need to duplicate logic burried deep-inside $http.

Issues - summary

Based on the above description we've got 2 main problems to solve:

  • make URL-construction mechanism configurable to:
    • allow custom, per-backend serialization schemas - issues: #3740, #7429
    • allow users to deal with certain back-end quirks (ex.: %-encoding) - issues: #9224
  • make it easier for people to generate URLs in their tests - issues: #3311

Proposed solution(s)

The general idea is to extract the logic of the buildUrl to a separate service ($$httpUrl? $urlBuilder?) thus allowing:

  • easy customisation of the serialisation schema (just swap the default service)
  • community to build custom serialisation schemas dedicated to a given backend type
  • usage of a new service from the unit tests to prepare string representation of a URL the same way as $http would do
  • easier unit-testing of the serialization service itself (both custom implementations from the community as well as built-in one)

After doing so we would introduce a new configuration param to the config object (paramsSerializer? urlBuilder?) that, by default, would invoke current logic from the extracted service. Adding a new config param would allow us to handle a use-case where users are hitting different backends with different serialization schemas.

Prior art

@GabrielDelepine
Copy link

When I see @catip's solution, I get worry about the consistency of the AngularJS ecosystem. My vision is to adopt a universal way while maintaining enough options available to satisfy the different approaches.

I'll prefer add an option to the $http config like { array_strict_mode: true }.

PS : And make transformRequest available for $resource's GET query : angular/angular.js#11277

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment