# HttpClient in Angular

Call your Web API from a service with HttpClient's get, post, put and delete, each typed with the model it returns. Angular provides HttpClient on its own. While developing, a proxy sends the app's /api requests on to the API, so the browser sees one origin.

Journeyman · Angular · REST API · Updated November 3, 2026

## After this lesson you can

- Call a Web API from a service with HttpClient's get, post, put and delete
- Send an Angular app's /api requests to the Web API while developing, with a proxy

## Key takeaways

- `HttpClient` is ready to inject with no setup; add `provideHttpClient()` only to change how it works, for example to give it interceptors.
- Put API calls in a service, one per resource, such as `CategoryApi`, so components never build URLs themselves.
- `get`, `post`, `put` and `delete` are typed with what the JSON is, such as `get<Category[]>`, and `post` and `put` send their object as JSON.
- Each call returns an `Observable`, and nothing is sent until you `subscribe` to it.
- While developing, `proxy.conf.json` lets `ng serve` pass `/api` requests on to the API, so the browser sees one origin and CORS doesn't block the calls.

An Angular app gets its data from a Web API. Angular's way to call one is **`HttpClient`**: `fetch`, made for Angular. These lessons use the categories API you built in *HTTP and Web APIs*.

## Ready to use

`HttpClient` is a service that Angular provides on its own: there's nothing to set up before you inject it. It sends its requests with the browser's `fetch`.

Older apps and tutorials add **`provideHttpClient()`** to the providers in `src/app/app.config.ts`. Older versions of Angular needed it. Now you add it only to change how `HttpClient` works, for example to give it *interceptors*, code that runs on every request:

```typescript
import { ApplicationConfig, provideBrowserGlobalErrorListeners } from '@angular/core';
import { provideHttpClient } from '@angular/common/http';
import { provideRouter } from '@angular/router';
import { routes } from './app.routes';

export const appConfig: ApplicationConfig = {
  providers: [
    provideBrowserGlobalErrorListeners(),
    provideRouter(routes),
    provideHttpClient()
  ]
};
```

Without options, as here, it changes nothing, so you can leave it out.

## A service for the API

API calls go in a **service**, one per resource, like a client class in *A Simple API Client*. Components never build URLs themselves.

```typescript
import { HttpClient } from '@angular/common/http';
import { inject, Service } from '@angular/core';
import { Observable } from 'rxjs';

export interface Category {
  categoryId: number;
  categoryName: string;
  description: string | null;
}

@Service()
export class CategoryApi {
  private readonly http = inject(HttpClient);

  getAll(): Observable<Category[]> {
    return this.http.get<Category[]>('/api/categories');
  }

  getById(id: number): Observable<Category> {
    return this.http.get<Category>(`/api/categories/${id}`);
  }

  add(category: Category): Observable<Category> {
    return this.http.post<Category>('/api/categories', category);
  }

  update(category: Category): Observable<Category> {
    return this.http.put<Category>(`/api/categories/${category.categoryId}`, category);
  }

  delete(id: number): Observable<void> {
    return this.http.delete<void>(`/api/categories/${id}`);
  }
}
```

- **`inject(HttpClient)`** gets Angular's HTTP client, as a component injects a service.
- **`get<Category[]>(url)`** sends a `GET`, and the type says what the JSON is: here, a list of categories. `post`, `put` and `delete` work the same way; `post` and `put` take the object to send as JSON, with the `Content-Type` header set for you.
- `description: string | null` says the description is a string **or** `null`, as the API sends it: TypeScript's way of writing C#'s `string?`.
- Each method returns an **`Observable`**: a value that arrives later, like a promise. The next lesson explains observables; for now, you **subscribe** to one to get its value.

## Using it in a component

```typescript
import { Component, inject, OnInit, signal } from '@angular/core';
import { Category, CategoryApi } from './category-api';

@Component({
  imports: [],
  selector: 'app-category-list',
  template: `
    <ul class="list-group">
      @for (category of categories(); track category.categoryId) {
        <li class="list-group-item">{{ category.categoryName }}</li>
      }
    </ul>
  `,
})
export class CategoryList implements OnInit {
  private readonly api = inject(CategoryApi);
  protected readonly categories = signal<Category[]>([]);

  ngOnInit() {
    this.api.getAll().subscribe(categories => this.categories.set(categories));
  }
}
```

When the component starts, it asks for the categories. **`subscribe(callback)`** sends the request, and calls the callback with the list when it arrives; the callback puts it in the signal, and the page shows the eight categories.

## A proxy, while developing

The app runs at `http://localhost:4200` and the API at, say, `http://localhost:5179`: different ports, so different origins, and the browser would block the calls. That's the **CORS** rule from *Fetch*. The API could say the app's origin is allowed, but while developing there's a simpler way: the Angular dev server can **pass requests on**. Create `proxy.conf.json` beside `angular.json`:

```json
{
  "/api": {
    "target": "http://localhost:5179",
    "secure": false
  }
}
```

and tell `ng serve` to use it, in `angular.json`, under `serve`:

```json
"serve": {
  "builder": "@angular/build:dev-server",
  "options": {
    "proxyConfig": "proxy.conf.json"
  },
  ...
}
```

Restart `ng serve`. Now a request from the app for `/api/categories` goes to `http://localhost:4200/api/categories`, and the dev server passes it on to the API and hands back the answer. As far as the browser knows, there's only one origin. That's why the service uses addresses starting `/api/`, with no host: the same code works when the app and API are published together.

Start both: the API (**Ctrl+F5** in Visual Studio) and the app (`ng serve`). Open http://localhost:4200, and the categories come from your database.

## Check yourself

2 questions to try on the lesson page.

## So what

`HttpClient`, ready to inject, in a service per resource with typed `get`, `post`, `put` and `delete`, and a proxy while you develop. Components ask the service, and never see a URL.

## Key terms

- [HttpClient](https://www.ask-codey.com/glossary/httpclient-c-sharp)
- Dev Server Proxy

## Cheat sheets

- [HttpClient in Angular](https://www.ask-codey.com/cheat-sheets/calling-apis-from-angular-httpclient-in-angular-cheat-sheet)

Source: https://www.ask-codey.com/lessons/calling-apis-from-angular-httpclient-in-angular
