0

Matrix parameters have been around since the late 90ies, and Angular's RouterModule knows how to deal with requests containing them. Nowadays, I would say they are a defacto standard. Given that, I was wondering if Angular's HttpClient supports them (with URL-encoded values) in a way similar to how it supports query parameters with HttpParams?

All I've found so far is a comment in an issue from 2014 for AngularJS (not Angular) about when to encode semicolons.

Is the only way to use matrix parameters in an HTTP request (to a back-end) in Angular thus to build up the URL "manually", e.g. using String interpolation, while query params can be added to a request as the params property of type HttpParams via the HttpClient's options object?

(Put differently, Angular seems to deal with URL-encoding and adding question mark, equal signs and ampersands for query params - can it do the equivalent for matrix params?)

What's the clean/Angular way of using matrix parameters in requests (and will URL encoding of the matrix parameter values be taken care of automagically by HttpClient and its dependencies or is that something the dev has to do explicitly)?

Christian
  • 6,070
  • 11
  • 53
  • 103
  • HttpClient has no support for matrix parameters because it's not an official standard. There are other unofficial things people do with URLs such as collections, redirects, tracking tokens, etc. etc. I don't see the point in HttpClient having semantic support for this at the API level. It will just make the API harder to learn for people who aren't familiar with all of these things people do. – Reactgular Dec 29 '19 at 18:49
  • @Reactgular thanks, that explains why it isn't supported by the client (although, as pointed out, the router does support them), and it's interesting to see an experienced user's opinion why it shouldn't have official support - but it doesn't really answer my questions of how to use matrix params in Angular-originating requests and if their values need URL encoding... :) – Christian Dec 29 '19 at 18:55
  • So, that means if I had special characters (say an ampersand `&`) in my `id` matrix param's value (or a `name`parameter, e.g. `;name=Marks&Sparks`), I'd have to manually URL-encode/sanitise that (here to `%26`)? Is there a utility method I could call that Angular provides? Or is it clever enough to do that automatically? (Well, the ampersand is probably a bad example here, as it's reserved in that part of the URL, if I'm not mistaken - but you get the idea...) P.S.: Did I just accidentally edit your last comment or did you delete yours - or is my cache acting up? – Christian Dec 29 '19 at 19:10
  • I deleted it. I'm going to post an answer. – Reactgular Dec 29 '19 at 19:13
  • Go for the answer of @Reactgular. I don't want to intervene. Cheers Chris – ChrisY Dec 29 '19 at 19:18

2 Answers2

2

So far we know that it isn't officially supported.

But I think a HttpInterceptor could work here. I did not try it though:

import {
  HttpInterceptor,
  HttpRequest,
  HttpHandler,
  HttpEvent
} from "@angular/common/http";
import { Observable } from "rxjs";

export class MatrixParamInterceptor implements HttpInterceptor {
  intercept(
    req: HttpRequest<any>,
    next: HttpHandler
  ): Observable<HttpEvent<any>> {
    const cloneReq = req.clone({
      params: null, // should be already present in urlWithParams
      url: mapToMatrixParams(req.urlWithParams) 
    });
    return next.handle(cloneReq);
  }
}

The urlWithParams is evaluated in the constructor of HttpRequest. The HttpClient creates the initial HttpRequest that we modify in the interceptor.

HttpRequest class.

HttpClient class.

ChrisY
  • 1,681
  • 10
  • 12
2

Angular's RouterModule knows how to deal with requests containing them

It sort of knows how to deal with them because this is a side effect of supporting multiple active routes.

Further down in the documentation it talks about named outlets:

https://angular.io/guide/router#displaying-multiple-routes-in-named-outlets

Basically, it's possible for the router to activate one or more routes at the same time. Which is impossible for a URL so the work around is to inject the named routes as encoded into the URL path.

So a named outlet might be activated with the following URL:

http://.../crisis-center(popup:compose)

The above takes advantage of the characters (:) being valid URL characters. It's the same side effects we use to create matrix parameters, and you can see that the Angular team deliberately avoided collision with matrix parameters by using a different syntax.

I was wondering if Angular's HttpClient supports them (with URL-encoded values) in a way similar to how it supports query parameters with HttpParams?

The URL specification states that there can be only one query parameter.

That is not true for matrix parameters.

http://example.com/a;first=1/b;second=2/c;third=3

The above example shows that there are three distinct sets of matrix parameters. The web server would read these as follows:

a?first=1
b?second=2
c?third=3

There is a tight coupling between the URL path and parameters. Since the URL is a single parameter for the HttpClient methods. It's not possible (without changing the API) to pass matrix parameters separately.

Put differently, Angular seems to deal with URL-encoding and adding question mark, equal signs and ampersands for query params - can it do the equivalent for matrix params?

I'm sure you could create an API of some kind that would encode matrix parameters, but it would be at the URL level. Which means that the URL string would be a procedural value making the API less user friendly.

There are also multiple patterns for using matrix parameters. Java, C#, Python, etc.. etc.. all have frameworks that do them differently.

What's the clean/Angular way of using matrix parameters in requests

There isn't one. It's just another URL string.

(and will URL encoding of the matrix parameter values be taken care of automagically by HttpClient and its dependencies or is that something the dev has to do explicitly)?

You can not encode a URL and the HttpClient receives the URL as the first parameter. Here is an example of what happens.

console.log(encodeURIComponent('https://www.example.com/'));

Since a matrix parameter is part of the URL (before the query) then it's up to you to create a valid URL.

So basically, to answer your question. You need your own utility to generate the URL before you call HttpClient.get()

function encodeMatrix(url: string, params: any) {
  // do work
  return url;
}

httpClient.get(encodeMatrix("https://www.example.com/", myParams)).subscribe()
Reactgular
  • 52,335
  • 19
  • 158
  • 208