Providers & HTTP in NestJS

Using Providers and HTTP Requests in a NestJS Backend



·

In the previous tutorial, we covered setting up a simple NestJS server that communicated with an Ionic application. All we have done so far is create a simple controller in NestJS that responded with some dummy message data. At the moment, it looks like this:

import { Controller, Get, Param } from '@nestjs/common';

@Controller('messages')
export class MessagesController {

    @Get()
    getMessages(){
      return {
          message: 'In a real example, I would return all of the messages'
      }
    }

    @Get(':id')
    getMessage(@Param('id') id){
        return {
            message: `In a real example, I would return the message with an id of ${id}`
        }
    }

}

The purpose of the previous tutorial was to introduce you to the basic structure of a NestJS project and get some simple communication happening between the backend and the front end.

In this tutorial, we will be aiming to cover two more concepts:

  • Using Providers
  • Making HTTP Requests

If you are coming from an Ionic/Angular background, then you could consider the Controllers in a NestJS backend to be similar in concept to the pages/views in your Ionic applications. Like pages, we should aim to keep our controllers as “light” as possible. The main role of a controller is to “direct traffic” – we should not assign too much “work” to a controller, it should just listen for the incoming requests, outsource the work that needs to be done, and then send a response to the request.

In that sense, it is a good idea to utilise “providers” in a NestJS application to do the heavy lifting for us. This way, a controller can make a request to a provider to do some work, rather than doing the work itself. This is much the same as we would have our pages in an Ionic/Angular application makes requests to a provider rather than do the work itself.

As an example, we will be modifying our existing server to fetch some data from a real API rather than just returning a string as dummy data. In the course of doing this, we will also need to learn how to make HTTP requests, as we will be launching an HTTP request from the provider that we create.

We will be using the API that quotesondesign.com provides to pull in some quotes to the application. The general process that we will be creating is:

  1. The Ionic application makes a request to our NestJS backend
  2. The controller that listens for that request will make a call to our provider
  3. The provider will make a request to the API and return the data to the controller
  4. The controller will return the data to the Ionic application

Why not just consume the API directly from the client?

Technically, we probably could just make an HTTP request from our Ionic application directly to the API for the same result. For example, in our Ionic application (or whatever kind of client-side tech you happen to be using) we could do something like this:

this.http.get('http://quotesondesign.com/wp-json/posts/2463).subscribe((response) => {
	console.log(response);
});

Assuming that this particular API supports CORS, this would work just fine. We won’t be doing this, though. In this tutorial, we will be making a request to our NestJS server to load the data into the application instead (and the server will handle making the request to the Quote API), e.g:

this.http.get('http://localhost:3000/messages').subscribe((response) => {
    console.log(response);
});

There can be benefits to proxying the request through our own server (e.g. if the API we wanted to use did not support CORS). However, what the service does is beside the point anyway – the point of this tutorial is to demonstrate how to use a provider in NestJS to “do work”, and I wanted a simple example to demonstrate the general idea.

In a more realistic/complex example, we might use the provider to handle requests that need to be handled on the server side. Perhaps a request to a MongoDB database, performing some authorisation logic, or handling uploading or downloading files. We will get to the more complex stuff in future, but for now, let’s just keep it basic.

Before We Get Started

Last updated for NestJS 5.0.0

This tutorial continues on from the last tutorial, which covered setting up a basic Ionic application using NestJS as the backend. You do not need to use Ionic/Angular in order to understand this tutorial, you could be using different tech on the front-end, but the tutorial is written with Ionic/Angular developers in mind. Many of the concepts in NestJS are the same as those in Angular, and this tutorial assumes a basic level of understanding of those Angular concepts.

  1. Creating the Provider

The first thing we are going to do is add the provider to our application.

Run the following command to generate the provider:

nest g service services/quotes

By using this generate command, the provider will automatically be added to the imports in app.module.ts, which is required in order to use the provider.

After you have run the command, you will find the basic outline of the provider in src/services/quotes.service.ts.

  1. Making an HTTP Request

The main role of our provider will be to perform an HTTP request and return that data to the controller. We are going to implement three different methods in the provider:

  • A method to return all of the quotes
  • A method to return a specific quote by id
  • A method to return a random quote

Before we can make any HTTP requests, we will need to set up the HttpModule in our NestJS application (just like we would need to set up the HttpClientModule in Angular).

Modify src/app.module.ts to reflect the following:

import { Module, HttpModule } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { MessagesController } from './messages/messages.controller';
import { QuotesService } from './services/quotes.service';

@Module({
  imports: [HttpModule],
  controllers: [AppController, MessagesController],
  providers: [AppService, QuotesService],
})
export class AppModule {}

We will also need to inject the HttpService into the provider.

Modify src/services/quotes.service.ts to reflect the following:

import { Injectable, HttpService } from '@nestjs/common';
import { map } from 'rxjs/operators';

@Injectable()
export class QuotesService {

    constructor(private http: HttpService){

    }

}

Now we will be able to launch HTTP requests through this.http. Notice that we are also importing the map operator here. When we run our HTTP requests we don’t want to return the entire response object, we just want to return the data. We will be using the map operator to modify that response into the format we want. Now, let’s add our methods.

Modify src/services/quotes.service.ts to reflect the following:

import { Injectable, HttpService } from '@nestjs/common';
import { map } from 'rxjs/operators';

@Injectable()
export class QuotesService {

    constructor(private http: HttpService){

    }

    getQuotes(){
        return this.http.get('http://quotesondesign.com/wp-json/posts')
            .pipe(
                map(response => response.data)
            );        
    }

    getQuote(id){
        return this.http.get('http://quotesondesign.com/wp-json/posts/' + id)
            .pipe(
                map(response => response.data)
            ); 
    }

    getRandomQuote(){
        return this.http.get('http://quotesondesign.com/wp-json/posts?filter[orderby]=rand&filter[posts_per_page]=1')
            .pipe(
                map(response => response.data)
            );
    }

}

The way in which we launch the request is much the same as the way we would do it with Angular, except that here we are explicitly mapping the response to only return the data. Although we don’t usually map responses in Angular, both map and pipe are just a part of the RxJS library and both are available to use in Angular – this isn’t a NestJS specific thing.

  1. Using the Provider

With our provider created, we now need to make use of it inside of our Messages controller. We can do that by importing it and injecting it through the constructor.

Modify src/messages/messages.controller.ts to reflect the following:

import { Controller, Get, Param } from '@nestjs/common';
import { QuotesService } from '../services/quotes.service';

@Controller('messages')
export class MessagesController {

    constructor(private quotesService: QuotesService){

    }

    @Get()
    getMessages(){
        return this.quotesService.getQuotes();
    }

    @Get(':id')
    getMessage(@Param('id') id){
        return this.quotesService.getQuote(id);
    }

}

Our controller remains mostly the same as it was before, except now we are returning a call to the quotes service. We just return the observable returned by the HTTP request directly, and that will be handled by our Ionic application. Unlike in the last tutorial, now our route that accepts the id parameter is actually doing something useful, as it will return a specific quote from the API that matches that id.

  1. Updating the Client

The last step is to utilise these changes in our front-end. We don’t really need to make any changes as we haven’t changed the structure of how our API works, but we will need to request an id that actually exists.

Modify src/app/home/home.page.ts to reflect the following:

import { Component, OnInit } from '@angular/core';
import { MessagesService } from '../services/messages.service';

@Component({
  selector: 'app-home',
  templateUrl: 'home.page.html',
  styleUrls: ['home.page.scss'],
})
export class HomePage implements OnInit {

  constructor(private messages: MessagesService){

  }

  ngOnInit(){

    this.messages.getMessages().subscribe((res) => {
      console.log(res);
    });

    this.messages.getMessage('2463').subscribe((res) => {
      console.log(res);
    });

  }

}

If we were to serve this application now, we would see a response in the console that looks like this:

NestJS HTTP Response

Summary

If you are already with Angular, then what we have covered will likely feel like pretty familiar territory. Although we could have easily launched those HTTP requests from within the controller itself, it is a good idea to use providers to handle the heavy lifting in the application – especially as the application starts to become more complex.

What to watch next...