Bruno Miguel
Bruno Miguel

Reputation: 1115

Angular HttpClient Get method with body

I'm improving an existing API, and the requirement is to provide a single get method which can accept multiple search criteria and based on those criteria perform the query.

I'm using Spring MVC. The get method signature:

@GetMapping("/subscribers")
public ResponseEntity<List<SubscriberDTO>> getAllSubscribers(Pageable pageable, @RequestBody List<SearchCriteria> lstSearchCriteria)

The implementation is working as expected tested on Postman

Now I was going to Angular to implementing the front end and I can't find a way to send a body through HttpClient Get method...

I'm kind of stuck. Should I send the search criteria over headers? Or there's a better way of doing it?

Upvotes: 45

Views: 148655

Answers (6)

Bullsized
Bullsized

Reputation: 577

While it it is not recommended (the very first sentence from the GET method's documentation), technically you could do it:

  constructor(private http: HttpClient) {}

  doAGetWithBodyRequest(): void {
    this.http.request(
    // the type of request:
    'get',
    // the path:
    'https://localhost:8080',
    // the body:
    { body: 'your-body-in-here' }
  }

Upvotes: -1

user2555515
user2555515

Reputation: 1033

There is an ongoing debate whether get request can have body or not. That I think is not a subject of this thread. If you do need to make get request with body ( for example the server imposes that) you can use request method:

request(method: string, url: string, options: {
        body?: any;
        headers?: HttpHeaders | {
            [header: string]: string | string[];
        };
       //.......
        
    }): Observable<ArrayBuffer>;

Upvotes: 8

cbp
cbp

Reputation: 25628

Just to clarify some of the answers here, firstly, as stated Angular does not support supplying a body with a GET request, and there is no way around this. The reason for that is not Angular's fault but that of XMLHttpRequest (XHR), the API that browsers use for making requests. XHR does not support body with GET requests.

There is nothing in the current HTTP standards that says a Body with a GET request is invalid, only that it is not semantically well defined.

In terms of REST, in my opinion, supplying a body with a GET request is much preferable to using POST. So it is somewhat annoying that XHR does not support this.

Upvotes: 5

Nuno Sousa
Nuno Sousa

Reputation: 882

As far as I can tell you cannot use HttpClient get to send a body. You could use the query at least for it to be idiomatic. (Or you can try to force the issue somehow).

Lets say you have an array with your criteria:

const criteria = [ {a: 25}, {b: 23} ];
http.get(url + '/?criteria='+ encodeURIComponent( JSON.stringify(criteria)));

Sending a body in a GET request is a violation of some RFC standard, and even though it might work you're bound to summon some arcane demons.

Upvotes: 37

Sander Oosterwijk
Sander Oosterwijk

Reputation: 439

To make Amir's answer some more generic I have done the following to build params for the passed item.

To my generic data service I have added this variant:

// Get data for passed parameters or item containing filters
public getByItem<T>(apiMethod: string, item?: T, apiParms?: HttpParams): Observable<T> {
    if (!apiParms) apiParms = new HttpParams();
    if (item) {
        const keys = Object.keys(item) as Array<keyof T>;
        for (let key of keys) {
            apiParms = apiParms.append(key.toString(), item[key].toString());
        }
    }
    // Call generic method of data service
    return this.get<T>(apiMethod, apiParms); // => return this.http.get<T>(environment.apiUrl + apiMethod, { headers: this.defaultHeaders

Upvotes: -1

Amir
Amir

Reputation: 2022

In the service method, you can have your method like below which takes the optional parameters for the search query. And you can send your search parameter over Observe as below.

getAllSubscribers(
    page?,
    itemsPerPage?,
    userParams?
  ): Observable<PaginatedResult<Subscribers[]>> {
    const paginatedResult: PaginatedResultSubscribers[]> = new PaginatedResult<
      Subscribers[]
    >();

    let params = new HttpParams();

    if (page != null && itemsPerPage != null) {
      params = params.append("pageNumber", page);
      params = params.append("pageSize", itemsPerPage);
    }

    if (userParams != null) {
      params = params.append("minAge", userParams.minAge);
      params = params.append("maxAge", userParams.maxAge);
        }

       return this.http
      .get<Subscribers[]>(this.baseUrl + "/subscribers", { observe: "response", params })
      .pipe(
        map(response => {
          paginatedResult.result = response.body;
          if (response.headers.get("Pagination") != null) {
            paginatedResult.pagination = JSON.parse(
              response.headers.get("Pagination")
            );
          }
          return paginatedResult;
        })
      );
  }

The basic idea is the use of HttpParams.

Upvotes: 9

Related Questions