angularapiescapingslimslim-4

Angular 2 & Slim PHP Framework: How to properly escape a string for use in a GET request


Environment

I have a frontend built using Angular2 which communicates with an API built using Slim PHP Framework v4.

Within the Angular frontend, a user can enter text into a form and submit it, then receive a response from the API.

The Angular project makes a request to the URL /api/{text}.

As far as I am aware, there is no way to access arguments supplied via, for example, /api?text={text} in Slim v4 and so I am unable to utilise Angular's HttpParams feature. For this reason, the URL is passed to Angular's HttpClient directly. i.e.

let text = 'Some random text / with special characters \.';
let myObservable: Observable<MyResponseObject[]>;
myObservable = this.http.get<MyResponseObject[]>(
  'http://my.domain.name/api/' + text
).pipe(catchError(this.handleError));

Problem

I have read that certain characters are encoded, then decoded again by Angular prior to submitting a request (i.e. \,/,.). For this reason, the value of the text variable in the above example is invalid.

One solution is to manually create a regex statement and use it to encode the string prior to submitting a request, then decode the string within the API.

I would like to avoid this and so I am wondering if one of two things is possible:

  1. Is there any Javascript, Typescript or Angular feature for encoding strings, as described, for use within a URI?

  2. Is there any way that I can access the value of arguments supplied with the format ?text={text} from a GET request within Slim version 4?

EDIT:

I'm also using custom provider within Angular to attach an auth token as a URL parameter in the format ?auth=[my_token_here]. The token is attached to every request sent by Angular. The custom provider uses the following code to attach the parameter:

intercept(req: HttpRequest<any>, next: HttpHandler) {
  return this.authService.user.pipe(take(1), exhaustMap(user => {
    if(!user) {
      return next.handle(req);
    }
    const modifiedReq = req.clone({
      params: new HttpParams().set('auth', user.token)
    });
    return next.handle(modifiedReq);
  }));
}

I've worked out how to read the value of 'auth' from the Slim API. However, when I modify the get request to add the text variable as a parameter, the parameter is never submitted and the Slim API still only sees the auth parameter. The modified code is as follows:

myObservable = this.http.get<MyResponseObject[]>(
  'http://localhost:8080/ngrams/', {
  params: new HttpParams().set('text', text)
}).pipe(catchError(this.handleError));

So here there are no errors, but the 'text' parameter is never attached to the URL (I can see only the auth parameter when checking the browser's network tab when I submit the request).

I'm an Angular noob so this logic may be flawed, but the above code for authentication was copied from a tutorial. My thinking is that maybe assigning new HttpParams() in the auth provider is overriding the parameters I set for the get request.

When I create the same request manually or using Postman, so the URL in my local environment is http://localhost:8080/api/?text=some text goes here, then I can successfully retrieve the parameter using the $req->getQueryParams() method.


Solution

  • As per Nima's answer, the values were being read correctly by the Slim API when using getQueryParams(). The issue was that the parameters were not being sent in the first place.

    The problem was that my authentication service was assigning a new HttpParams object to http requests, where it should have been adding an auth token to the existing set of parameters.

    This issue was solved by updating the intercept() method mentioned in the question, so that the auth token is attached to the request's existing params property:

    intercept(req: HttpRequest<any>, next: HttpHandler) {
      return this.authService.user.pipe(take(1), exhaustMap(user => {
        if(!user) {
          return next.handle(req);
        }
        const modifiedReq = req.clone({
          params: req.params.set('auth', user.token)
        });
        return next.handle(modifiedReq);
      }));
    }