Skip to content

Using HttpClient in Modern Angular Applications

Using HttpClient in Modern Angular Applications

This article was written over 18 months ago and may contain information that is out of date. Some content may be relevant but please refer to the relevant official documentation or available resources for the latest information.

Introduction

With all the wonderful treats that the Angular team has given us during the recent "renaissance" era, many new developers are joining in on the fun. And one of the challenges they'll face at some point is how to call an API from your Angular application properly. Unfortunately, while searching for a guide on how to do this, they might stumble upon a lot of outdated information. Hence, this article should serve as a reliable guide on how to use the HttpClient in Angular >= 17.

The Setup

To make an HTTP request in Angular, you can take advantage of the HttpClient provided by the @angular/common/http package. To use it, you'll need to provide it. Here's how you can do that for the whole application using the bootstrapApplication function from @angular/platform-browser:

import { provideHttpClient } from "@angular/common/http";
import { bootstrapApplication } from "@angular/platform-browser";

bootstrapApplication(App, {
  providers: [provideHttpClient()],
});

With that, you should be good to go. You can now inject the HttpClient into any service or component in your application.

Using HttpClient in Services

Let's take a common example: You have a database object, say a Movie, and you want to implement CRUD operations on it. Typically, you'll want to create a service that provides methods for these operations. Let's call this service MovieService and create a skeleton for it with a method for getting all movies.

// movie.service.ts

import { HttpClient } from "@angular/common/http";
import { Injectable } from "@angular/core";

@Injectable({
  providedIn: "root",
})
export class MovieService {
  // Inject the HttpClient in constructor
  constructor(private httpClient: HttpClient) {}

  getAllMovies() {
    // TODO: Implement this method
  }
}

Implementing the Method using HttpClient

Let's assume we have a GraphQL API for our movies. We can implement our getAllMovies using HttpClient to make a request to fetch all movies.

First, we will need to define a new type to represent the response from the API. This is especially important when you are using GraphQL, which may return a specific structure, such as:

{
  "data": {
    "allMovies": {
      "edges": [
        {
          "id": 1,
          "title": "One Flew Over the Cuckoo's Nest",
          "director": "Milos Forman",
          "releaseDate": "1975-11-19"
        },
        {
          "id": 2,
          "title": "The Shining",
          "director": "Stanley Kubrick",
          "releaseDate": "1980-05-23"
        }
      ]
    }
  }
}

When working with a real API, you'll likely use some code generator to generate the types for the response from the GraphQL schema. But for the sake of this example, we'll create an interface to represent the response manually:

// movie-api.model.ts
import { Movie } from "./movie.model";

export interface MoviesListResponse {
  data: {
    allMovies: {
      edges: Movie[];
    };
  };
}

Now, we can implement the getAllMovies method using HttpClient:

getAllMovies(): Observable<MoviesListResponse> {
    // The graphql query to fetch all movies
    const query = `{
      allMovies(first: 10) {
        edges {
          id
          title
          director
          releaseDate
        }
      }
    }`;

  return this.httpClient.post<MoviesListResponse>(
      'https://api.example.com/graphql',
      {
        query,
      },
      {
        headers: {
          'Content-Type': 'application/json',
        },
      }
    );
}

Note: The post method is used here because we are sending a request body. If you are making a GET request (e.g. to a REST API), you can use the get method instead.

The getAllMovies method returns an Observable of MoviesListResponse. In this example, I have typed it explicitly to make it obvious at first glance, but you could also omit the type annotation, and TypeScript should infer it.

Note: While I'm excited about signals as much as the next guy, making HTTP requests is one of the typical async operations for which RxJS Observables are a perfect fit, making a great argument for RxJS still having a solid place in Angular alongside signals.

Using the Service in a Component

Now that we have our MovieService set up, we can use it as a component to fetch and display all movies.

But first, let's create a Movie interface to represent the structure of a movie. Trust me, this will prevent many potential headaches down the line. Although using any at the beginning and implementing the types later is a valid approach in some cases, using data fetched from an API without validating the type will inevitably lead to bugs that are difficult to solve.

// movie.model.ts

export interface Movie {
  id: number;
  title: string;
  director: string;
  releaseDate: Date;
}

Now, we can start implementing our standalone MoviesComponent:

// movies.component.ts

import { Component, inject } from "@angular/core";
import { MovieService } from "./movie.service";
import { Movie } from "./movie.model";

@Component({
  selector: "app-movies",
  standalone: true,
  imports: [],
  templateUrl: "./movies.component.html",
})
export class MoviesListComponent {
  // We are using the "inject" function to inject the MovieService but we could also use the constructor
  movieService = inject(MovieService);

  // The object to hold the movies using the Movie interface
  movies: Movie[] = [];

  constructor() {
    // Call the method to fetch all movies
    this.movieService.getAllMovies().subscribe((response) => {
      // Assign the movies to the movies property
      this.movies = response.data.allMovies.edges;
    });
  }
}

In this component, we are calling the getAllMovies method from the MovieService in the constructor to fetch all movies and assign them to the movies property which we will use to display the movies in the template.

<!-- movies.component.html -->

<ul>
  @for(movie of movies; track movie.title) {
  <li>{{ movie.title }}</li>
  }
</ul>

In this case, placing our code inside the constructor is safe because it doesn’t depend on any @Input(). If it were, our code would fail because the inputs aren’t initialized at time of instantiation. That's why it is sometimes recommended to place logic in ngOnInit instead. You could also put this call in an arbitrary method that is called e.g. on a button click.

Another way to handle the subscription is to use the async pipe in the template. This way, Angular will automatically subscribe and unsubscribe from the observable for you and you won't have to assign the response to a property in the component. Due to the structure of the returned data, however, we'll need to use the RxJS map operator to extract the movies from the response.

// movies.component.ts

import { AsyncPipe } from '@angular/common';
import { Component, inject } from "@angular/core";
import { map, Observable } from 'rxjs';
import { Movie } from './movie.model';
import { MovieService } from "./movie.service";

@Component({
  selector: "app-movies",
  standalone: true,
  imports: [AsyncPipe], // We need to import the AsyncPipe to have it available in the template
  templateUrl: "./movies.component.html",
})
export class MoviesListComponent {
  movieService = inject(MovieService);

  // The observable to hold the movies
  movies$: Observable<Movie[]> = this.movieService.getAllMovies().pipe(
      map(({data}) => data.allMovies.edges)
    );
}

Note using the pipe method to chain the map operator to the observable returned by getAllMovies. This is a common pattern when working with RxJS observables introduced in RxJs 5.5. If you see code that uses the map operator directly on the observable and wonder why it isn't working for you, it's likely using an older version of RxJS.

Now, we can simply apply the async pipe in the template to subscribe to the observable and display the movies:

<!-- movies.component.html -->

<ul>
  @for(movie of movies$ | async; track movie.title) {
  <li>{{ movie.title }}</li>
  }
</ul>

Conclusion

HttpClient in Angular is pretty straightforward, but with all the changes to RxJS and Angular in the past few years, it can pose a significant challenge if you're not super-experienced with those technologies and stumble upon outdated resources. Following this article, you should hopefully be able to implement your service using HttpClient to make requests to an API in your modern Angular application and avoid the struggle of copying outdated code snippets.

This Dot is a consultancy dedicated to guiding companies through their modernization and digital transformation journeys. Specializing in replatforming, modernizing, and launching new initiatives, we stand out by taking true ownership of your engineering projects.

We love helping teams with projects that have missed their deadlines or helping keep your strategic digital initiatives on course. Check out our case studies and our clients that trust us with their engineering.

You might also like

“Music and code have a lot in common,” freeCodeCamp’s Jessica Wilkins on what the tech community is doing right to onboard new software engineers cover image

“Music and code have a lot in common,” freeCodeCamp’s Jessica Wilkins on what the tech community is doing right to onboard new software engineers

Before she was a software developer at freeCodeCamp, Jessica Wilkins was a classically trained clarinetist performing across the country. Her days were filled with rehearsals, concerts, and teaching, and she hadn’t considered a tech career until the world changed in 2020. > “When the pandemic hit, most of my gigs were canceled,” she says. “I suddenly had time on my hands and an idea for a site I wanted to build.” That site, a tribute to Black musicians in classical and jazz music, turned into much more than a personal project. It opened the door to a whole new career where her creative instincts and curiosity could thrive just as much as they had in music. Now at freeCodeCamp, Jessica maintains and develops the very JavaScript curriculum that has helped her and millions of developers around the world. We spoke with Jessica about her advice for JavaScript learners, why musicians make great developers, and how inclusive communities are helping more women thrive in tech. Jessica’s Top 3 JavaScript Skill Picks for 2025 If you ask Jessica what it takes to succeed as a JavaScript developer in 2025, she won’t point you straight to the newest library or trend. Instead, she lists three skills that sound simple, but take real time to build: > “Learning how to ask questions and research when you get stuck. Learning how to read error messages. And having a strong foundation in the fundamentals” She says those skills don’t come from shortcuts or shiny tools. They come from building. > “Start with small projects and keep building,” she says. “Books like You Don’t Know JS help you understand the theory, but experience comes from writing and shipping code. You learn a lot by doing.” And don’t forget the people around you. > “Meetups and conferences are amazing,” she adds. “You’ll pick up things faster, get feedback, and make friends who are learning alongside you.” Why So Many Musicians End Up in Tech A musical past like Jessica’s isn’t unheard of in the JavaScript industry. In fact, she’s noticed a surprising number of musicians making the leap into software. > “I think it’s because music and code have a lot in common,” she says. “They both require creativity, pattern recognition, problem-solving… and you can really get into flow when you’re deep in either one.” That crossover between artistry and logic feels like home to people who’ve lived in both worlds. What the Tech Community Is Getting Right Jessica has seen both the challenges and the wins when it comes to supporting women in tech. > “There’s still a lot of toxicity in some corners,” she says. “But the communities that are doing it right—like Women Who Code, Women in Tech, and Virtual Coffee—create safe, supportive spaces to grow and share experiences.” She believes those spaces aren’t just helpful, but they’re essential. > “Having a network makes a huge difference, especially early in your career.” What’s Next for Jessica Wilkins? With a catalog of published articles, open-source projects under her belt, and a growing audience of devs following her journey, Jessica is just getting started. She’s still writing. Still mentoring. Still building. And still proving that creativity doesn’t stop at the orchestra pit—it just finds a new stage. Follow Jessica Wilkins on X and Linkedin to keep up with her work in tech, her musical roots, and whatever she’s building next. Sticker illustration by Jacob Ashley....

Incremental Hydration in Angular cover image

Incremental Hydration in Angular

Incremental Hydration in Angular Some time ago, I wrote a post about SSR finally becoming a first-class citizen in Angular. It turns out that the Angular team really treats SSR as a priority, and they have been working tirelessly to make SSR even better. As the previous blog post mentioned, full-page hydration was launched in Angular 16 and made stable in Angular 17, providing a great way to improve your Core Web Vitals. Another feature aimed to help you improve your INP and other Core Web Vitals was introduced in Angular 17: deferrable views. Using the @defer blocks allows you to reduce the initial bundle size and defer the loading of heavy components based on certain triggers, such as the section entering the viewport. Then, in September 2024, the smart folks at Angular figured out that they could build upon those two features, allowing you to mark parts of your application to be server-rendered dehydrated and then hydrate them incrementally when needed - hence incremental hydration. I’m sure you know what hydration is. In short, the server sends fully formed HTML to the client, ensuring that the user sees meaningful content as quickly as possible and once JavaScript is loaded on the client side, the framework will reconcile the rendered DOM with component logic, event handlers, and state - effectively hydrating the server-rendered content. But what exactly does "dehydrated" mean, you might ask? Here's what will happen when you mark a part of your application to be incrementally hydrated: 1. Server-Side Rendering (SSR): The content marked for incremental hydration is rendered on the server. 2. Skipped During Client-Side Bootstrapping: The dehydrated content is not initially hydrated or bootstrapped on the client, reducing initial load time. 3. Dehydrated State: The code for the dehydrated components is excluded from the initial client-side bundle, optimizing performance. 4. Hydration Triggers: The application listens for specified hydration conditions (e.g., on interaction, on viewport), defined with a hydrate trigger in the @defer block. 5. On-Demand Hydration: Once the hydration conditions are met, Angular downloads the necessary code and hydrates the components, allowing them to become interactive without layout shifts. How to Use Incremental Hydration Thanks to Mark Thompson, who recently hosted a feature showcase on incremental hydration, we can show some code. The first step is to enable incremental hydration in your Angular application's appConfig using the provideClientHydration provider function: ` Then, you can mark the components you want to be incrementally hydrated using the @defer block with a hydrate trigger: ` And that's it! You now have a component that will be server-rendered dehydrated and hydrated incrementally when it becomes visible to the user. But what if you want to hydrate the component on interaction or some other trigger? Or maybe you don't want to hydrate the component at all? The same triggers already supported in @defer blocks are available for hydration: - idle: Hydrate once the browser reaches an idle state. - viewport: Hydrate once the component enters the viewport. - interaction: Hydrate once the user interacts with the component through click or keydown triggers. - hover: Hydrate once the user hovers over the component. - immediate: Hydrate immediately when the component is rendered. - timer: Hydrate after a specified time delay. - when: Hydrate when a provided conditional expression is met. And on top of that, there's a new trigger available for hydration: - never: When used, the component will remain static and not hydrated. The never trigger is handy when you want to exclude a component from hydration altogether, making it a completely static part of the page. Personally, I'm very excited about this feature and can't wait to try it out. How about you?...

Vercel & React Native - A New Era of Mobile Development? cover image

Vercel & React Native - A New Era of Mobile Development?

Vercel & React Native - A New Era of Mobile Development? Jared Palmer of Vercel recently announced an acquisition that spiked our interest. Having worked extensively with both Next.js and Vercel, as well as React Native, we were curious to see what the appointment of Fernando Rojo, the creator of Solito, as Vercel's Head of Mobile, would mean for the future of React Native and Vercel. While we can only speculate on what the future holds, we can look closer at Solito and its current integration with Vercel. Based on the information available, we can also make some educated guesses about what the future might hold for React Native and Vercel. What is Solito? Based on a recent tweet by Guillermo Rauch, one might assume that Solito allows you to build mobile apps with Next.js. While that might become a reality in the future, Jamon Holmgren, the CTO of Infinite Red, added some context to the conversation. According to Jamon, Solito is a cross-platform framework built on top of two existing technologies: - For the web, Solito leverages Next.js. - For mobile, Solito takes advantage of Expo. That means that, at the moment, you can't build mobile apps using Next.js & Solito only - you still need Expo and React Native. Even Jamon, however, admits that even the current integration of Solito with Vercel is exciting. Let's take a closer look at what Solito is according to its official website: > This library is two things: > > 1. A tiny wrapper around React Navigation and Next.js that lets you share navigation code across platforms. > > 2. A set of patterns and examples for building cross-platform apps with React Native + Next.js. We can see that Jamon was right - Solito allows you to share navigation code between Next.js and React Native and provides some patterns and components that you can use to build cross-platform apps, but it doesn't replace React Native or Expo. The Cross-Platformness of Solito So, we know Solito provides a way to share navigation and some patterns between Next.js and React Native. But what precisely does that entail? Cross-Platform Hooks and Components If you look at Solito's documentation, you'll see that it's not only navigation you can share between Next.js and React Native. There are a few components that wrap Next.js components and make them available in React Native: - Link - a component that wraps Next.js' Link component and allows you to navigate between screens in React Native. - TextLink - a component that also wraps Next.js' Link component but accepts text nodes as children. - MotiLink - a component that wraps Next.js' Link component and allows you to animate the link using moti, a popular animation library for React Native. - SolitoImage - a component that wraps Next.js' Image component and allows you to display images in React Native. On top of that, Solito provides a few hooks that you can use for shared routing and navigation: - useRouter() - a hook that lets you navigate between screens across platforms using URLs and Next.js Url objects. - useLink() - a hook that lets you create Link components across the two platforms. - createParam() - a function that returns the useParam() and useParams() hooks which allow you to access and update URL parameters across platforms. Shared Logic The Solito starter project is structured as a monorepo containing: - apps/next - the Next.js application. - apps/expo or apps/native - the React Native application. - packages/app - shared packages across the two applications: - features - providers - navigation The shared packages contain the shared logic and components you can use across the two platforms. For example, the features package contains the shared components organized by feature, the providers package contains the shared context providers, and the navigation package includes the shared navigation logic. One of the key principles of Solito is gradual adoption, meaning that if you use Solito and follow the recommended structure and patterns, you can start with a Next.js application only and eventually add a React Native application to the mix. Deployments Deploying the Next.js application built on Solito is as easy as deploying any other Next.js application. You can deploy it to Vercel like any other Next.js application, e.g., by linking your GitHub repository to Vercel and setting up automatic deployments. Deploying the React Native application built on top of Solito to Expo is a little bit more involved - you cannot directly use the Github Action recommended by Expo without some modification as Solito uses a monorepo structure. The adjustment, however, is luckily just a one-liner. You just need to add the working-directory parameter to the eas update --auto command in the Github Action. Here's what the modified part of the Expo Github Action would look like: ` What Does the Future Hold? While we can't predict the future, we can make some educated guesses about what the future might hold for Solito, React Native, Expo, and Vercel, given what we know about the current state of Solito and the recent acquisition of Fernando Rojo by Vercel. A Competitor to Expo? One question that comes to mind is whether Vercel will work towards creating a competitor to Expo. While it's too early to tell, it's not entirely out of the question. Vercel has been expanding its offering beyond Next.js and static sites, and it's not hard to imagine that it might want to provide a more integrated, frictionless solution for building mobile apps, further bridging the gap between web and mobile development. However, Expo is a mature and well-established platform, and building a mobile app toolchain from scratch is no trivial task. It would be easier for Vercel to build on top of Expo and partner with them to provide a more integrated solution for building mobile apps with Next.js. Furthermore, we need to consider Vercel's target audience. Most of Vercel's customers are focused on web development with Next.js, and switching to a mobile-first approach might not be in their best interest. That being said, Vercel has been expanding its offering to cater to a broader audience, and providing a more integrated solution for building mobile apps might be a step in that direction. A Cross-Platform Framework for Mobile Apps with Next.js? Imagine a future where you write your entire application in Next.js — using its routing, file structure, and dev tools — and still produce native mobile apps for iOS and Android. It's unlikely such functionality would be built from scratch. It would likely still rely on React Native + Expo to handle the actual native modules, build processes, and distribution. From the developer’s point of view, however, it would still feel like writing Next.js. While this idea sounds exciting, it's not likely to happen in the near future. Building a cross-platform framework that allows you to build mobile apps with Next.js only would require a lot of work and coordination between Vercel, Expo, and the React Native community. Furthermore, there are some conceptual differences between Next.js and React Native that would need to be addressed, such as Next.js being primarily SSR-oriented and native mobile apps running on the client. Vercel Building on Top of Solito? One of the more likely scenarios is that Vercel will build on top of Solito to provide a more integrated solution for building mobile apps with Next.js. This could involve providing more components, hooks, and patterns for building cross-platform apps, as well as improving the deployment process for React Native applications built on top of Solito. A potential partnership between Vercel and Expo, or at least some kind of closer integration, could also be in the cards in this scenario. While Expo already provides a robust infrastructure for building mobile apps, Vercel could provide complementary services or features that make it easier to build mobile apps on top of Solito. Conclusion Some news regarding Vercel and mobile development is very likely on the horizon. After all, Guillermo Rauch, the CEO of Vercel, has himself stated that Vercel will keep raising the quality bar of the mobile and web ecosystems. While it's unlikely we'll see a full-fledged mobile app framework built on top of Next.js or a direct competitor to Expo in the near future, it's not hard to imagine that Vercel will provide more tools and services for building mobile apps with Next.js. Solito is a step in that direction, and it's exciting to see what the future holds for mobile development with Vercel....

The simplicity of deploying an MCP server on Vercel cover image

The simplicity of deploying an MCP server on Vercel

The current Model Context Protocol (MCP) spec is shifting developers toward lightweight, stateless servers that serve as tool providers for LLM agents. These MCP servers communicate over HTTP, with OAuth handled clientside. Vercel’s infrastructure makes it easy to iterate quickly and ship agentic AI tools without overhead. Example of Lightweight MCP Server Design At This Dot Labs, we built an MCP server that leverages the DocuSign Navigator API. The tools, like `get_agreements`, make a request to the DocuSign API to fetch data and then respond in an LLM-friendly way. ` Before the MCP can request anything, it needs to guide the client on how to kick off OAuth. This involves providing some MCP spec metadata API endpoints that include necessary information about where to obtain authorization tokens and what resources it can access. By understanding these details, the client can seamlessly initiate the OAuth process, ensuring secure and efficient data access. The Oauth flow begins when the user's LLM client makes a request without a valid auth token. In this case they’ll get a 401 response from our server with a WWW-Authenticate header, and then the client will leverage the metadata we exposed to discover the authorization server. Next, the OAuth flow kicks off directly with Docusign as directed by the metadata. Once the client has the token, it passes it in the Authorization header for tool requests to the API. ` This minimal set of API routes enables me to fetch Docusign Navigator data using natural language in my agent chat interface. Deployment Options I deployed this MCP server two different ways: as a Fastify backend and then by Vercel functions. Seeing how simple my Fastify MCP server was, and not really having a plan for deployment yet, I was eager to rewrite it for Vercel. The case for Vercel: * My own familiarity with Next.js API deployment * Fit for architecture * The extremely simple deployment process * Deploy previews (the eternal Vercel customer conversion feature, IMO) Previews of unfamiliar territory Did you know that the MCP spec doesn’t “just work” for use as ChatGPT tooling? Neither did I, and I had to experiment to prove out requirements that I was unfamiliar with. Part of moving fast for me was just deploying Vercel previews right out of the CLI so I could test my API as a Connector in ChatGPT. This was a great workflow for me, and invaluable for the team in code review. Stuff I’m Not Worried About Vercel’s mcp-handler package made setup effortless by abstracting away some of the complexity of implementing the MCP server. It gives you a drop-in way to define tools, setup https-streaming, and handle Oauth. By building on Vercel’s ecosystem, I can focus entirely on shipping my product without worrying about deployment, scaling, or server management. Everything just works. ` A Brief Case for MCP on Next.js Building an API without Next.js on Vercel is straightforward. Though, I’d be happy deploying this as a Next.js app, with the frontend features serving as the documentation, or the tools being a part of your website's agentic capabilities. Overall, this lowers the barrier to building any MCP you want for yourself, and I think that’s cool. Conclusion I'll avoid quoting Vercel documentation in this post. AI tooling is a critical component of this natural language UI, and we just want to ship. I declare Vercel is excellent for stateless MCP servers served over http....

Let's innovate together!

We're ready to be your trusted technical partners in your digital innovation journey.

Whether it's modernization or custom software solutions, our team of experts can guide you through best practices and how to build scalable, performant software that lasts.

Prefer email? hi@thisdot.co