Skip to content
Angular ng http 4 min read

Headers, Params & Options

Every call you make with Angular’s HttpClient accepts an optional options object that lets you shape the request and the response. Through it you attach authentication and content headers, append query parameters in a type-safe way, choose whether you want the parsed body or the full HTTP response, and opt into sending cookies for cross-origin calls. Understanding these options is what turns a naive get() into a production-ready API integration.

Setting headers with HttpHeaders

HttpHeaders is an immutable class. Each mutation method (set, append, delete) returns a brand-new instance rather than changing the original, so you must chain calls or capture the return value. This immutability makes headers safe to share across requests without accidental leakage.

import { inject } from '@angular/core';
import { HttpClient, HttpHeaders } from '@angular/common/http';

export class ArticleApi {
  private http = inject(HttpClient);

  create(article: Article) {
    const headers = new HttpHeaders()
      .set('Content-Type', 'application/json')
      .set('Authorization', `Bearer ${this.token}`)
      .append('X-Trace-Id', crypto.randomUUID());

    return this.http.post<Article>('/api/articles', article, { headers });
  }
}

You can also build headers from a plain object literal, which Angular converts internally. This is the most concise form when you do not need conditional logic:

return this.http.get<Article[]>('/api/articles', {
  headers: { 'Authorization': `Bearer ${this.token}`, 'Accept': 'application/json' },
});

Cross-cutting headers like Authorization belong in a functional interceptor, not scattered across services. Set per-request headers here only when they are genuinely specific to that one call.

Adding query parameters with HttpParams

HttpParams mirrors HttpHeaders: it is immutable and URL-encodes values for you, so you never hand-concatenate query strings. Use set to replace a key and append to add repeated keys (handy for array-style filters).

import { HttpParams } from '@angular/common/http';

search(term: string, page: number, tags: string[]) {
  let params = new HttpParams()
    .set('q', term)
    .set('page', page)          // numbers and booleans are accepted
    .set('size', 20);

  for (const tag of tags) {
    params = params.append('tag', tag);
  }

  return this.http.get<Article[]>('/api/articles', { params });
}

A request for search('rxjs', 2, ['ng', 'http']) produces:

Output:

GET /api/articles?q=rxjs&page=2&size=20&tag=ng&tag=http

The object-literal shorthand works for params too. Use it for flat, unconditional queries:

this.http.get<Article[]>('/api/articles', {
  params: { q: term, page, size: 20 },
});

HttpParams is immutable — params.set(...) returns a new instance. Forgetting to reassign (params = params.set(...)) is the single most common params bug.

Response type and the observe option

By default HttpClient parses the response body as JSON and emits just that body. Two options change this behaviour.

The responseType option controls how the body is interpreted. The observe option controls how much of the HTTP exchange you receive.

OptionValuesEffect
responseType'json' (default), 'text', 'blob', 'arraybuffer'How the body is deserialized
observe'body' (default), 'response', 'events'Emit the body, the full HttpResponse, or a stream of HttpEvents

Reading a non-JSON payload such as a CSV export requires responseType: 'text':

downloadCsv() {
  return this.http.get('/api/articles/export', { responseType: 'text' });
  // Observable<string>
}

When you need status codes or response headers, set observe: 'response' to receive the full HttpResponse<T>:

load(id: string) {
  return this.http.get<Article>(`/api/articles/${id}`, { observe: 'response' }).pipe(
    tap((res) => console.log('ETag:', res.headers.get('ETag'))),
    map((res) => res.body!),
  );
}

Output:

ETag: "a1b2c3d4"

Setting observe: 'events' emits every HttpEvent in order — useful for tracking upload/download progress via reportProgress: true.

Sending credentials and other options

For cross-origin requests where the browser must include cookies (and honour Set-Cookie responses), set withCredentials: true. Your server must answer with Access-Control-Allow-Credentials: true and an explicit origin for this to work.

this.http.get<Session>('/api/session', { withCredentials: true });

You can combine any of these options in a single call. Angular’s overloaded typings infer the correct return type from the options you pass:

this.http.post<Article>('/api/articles', body, {
  headers: { 'X-Idempotency-Key': key },
  params: { draft: true },
  observe: 'response',
  withCredentials: true,
});
// Observable<HttpResponse<Article>>

Best practices

  • Treat HttpHeaders and HttpParams as immutable — always reassign or chain the returned instance.
  • Push authentication and tracing headers into a functional interceptor; keep per-request options minimal.
  • Prefer HttpParams (or the object shorthand) over manual string concatenation so values are encoded correctly.
  • Reach for observe: 'response' only when you genuinely need status codes or response headers; otherwise let Angular emit the body.
  • Match responseType to the payload — never request 'json' for text, blob, or binary endpoints.
  • Enable withCredentials deliberately, and confirm the matching CORS headers exist on the server.
  • Let Angular infer return types from your options rather than casting; the overloads encode the correct shape.
Last updated June 14, 2026
Was this helpful?