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:
- The Ionic application makes a request to our NestJS backend
- The controller that listens for that request will make a call to our provider
- The provider will make a request to the API and return the data to the controller
- 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.
- 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.
- 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.
- 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
.
- 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:
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.