{"id":2751,"date":"2019-04-25T17:28:00","date_gmt":"2019-04-25T17:28:00","guid":{"rendered":"https:\/\/ionicframework.com\/?p=2751"},"modified":"2020-10-15T22:29:58","modified_gmt":"2020-10-15T22:29:58","slug":"full-stack-typescript-with-ionic-angular-and-nestjs-part-2","status":"publish","type":"post","link":"https:\/\/ionic.io\/blog\/full-stack-typescript-with-ionic-angular-and-nestjs-part-2","title":{"rendered":"Full-Stack TypeScript with Ionic, Angular, and NestJS Part 2"},"content":{"rendered":"<p>Welcome to part two of the Full-stack TypeScript with Ionic and NestJS series!<\/p>\n<p>In <a href=\"https:\/\/ionicframework.com\/blog\/full-stack-typescript-with-ionic-angular-and-nestjs-part-1\/\" target=\"_blank\" rel=\"noopener\">part one of the series<\/a>, we went over the benefits of using TypeScript on both the client and server, shared an introduction to NestJS, and built a simple app, that\u2019s already up and running, called GoSpaceRanger.<\/p>\n<p>So far in GoSpaceRanger, we have a simple list screen showing a list of missions our space rangers can go on:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"350\" height=\"622\" data-src=\"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2019\/04\/ioniclistpage2.png\" alt=\"\" class=\"aligncenter size-full wp-image-2735 lazyload\" data-srcset=\"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2019\/04\/ioniclistpage2.png 350w, https:\/\/ionic.io\/blog\/wp-content\/uploads\/2019\/04\/ioniclistpage2-169x300.png 169w\" data-sizes=\"auto, (max-width: 350px) 100vw, 350px\" src=\"data:image\/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==\" style=\"--smush-placeholder-width: 350px; --smush-placeholder-aspect-ratio: 350\/622;\" \/><noscript><img loading=\"lazy\" decoding=\"async\" width=\"350\" height=\"622\" src=\"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2019\/04\/ioniclistpage2.png\" alt=\"\" class=\"aligncenter size-full wp-image-2735\" srcset=\"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2019\/04\/ioniclistpage2.png 350w, https:\/\/ionic.io\/blog\/wp-content\/uploads\/2019\/04\/ioniclistpage2-169x300.png 169w\" sizes=\"auto, (max-width: 350px) 100vw, 350px\" \/><\/noscript><\/p>\n<p>In this second part of our series, we are going to dive deeper into building out the Nest backend service, including adding a database to store missions and using some Nest features to keep our code clean and reusable.<\/p>\n<p><!--more--><\/p>\n<h2>Getting Back Into the Project<\/h2>\n<p>If you followed along in part one, go back into the main project folder, open up the <code>gsr-client<\/code> (the Ionic project) and <code>gsr-server<\/code> (the Nest project) folders.<\/p>\n<p>If you would like to start fresh in part two, clone the project repo from git@github.com:ionic-team\/demo-ionic-nest-tutorial.git, and go to the <code>part2-start<\/code> branch, which leaves you at the same place as if you had completed part one.<\/p>\n<p>Open up each of the projects in your favorite code editor and run <code>ionic serve<\/code> in the <code>gsr-client<\/code> folder to kick off the Ionic development server, and <code>npm run start:dev<\/code> in the <code>gsr-server<\/code> folder to start the Nest server.<\/p>\n<h2>Friends of Nest<\/h2>\n<p>To help build out the backend, we will look into a few additional libraries to use within the Nest service.<\/p>\n<p>The following libraries are NPM packages that provide additional functionality in the Nest backend. Like Nest, they are written in TypeScript and take advantage of TypeScript features\u2014like decorators and type meta-data\u2014to provide a cleaner, more declarative coding experience.<\/p>\n<h3>TypeORM<\/h3>\n<p><a href=\"\/\/github.com\/typeorm\/typeorm\" target=\"_blank\" rel=\"noopener\">TypeORM<\/a> is an ORM (object relational mapper), which helps manage and interact with databases. TypeORM uses a code-first methodology, which means you create your classes, and TypeORM automatically generates the tables and columns in your database for you. TypeORM is heavily influenced by other enterprise-grade ORMs, such as Entity Framework, and provides a performant, scalable, and easy to use data access library.<\/p>\n<p>TypeORM supports the most common relational databases: such as MySql, PostgreSQL, SQLite, MS SQL, and more. Setting up your database instance is outside the scope of this tutorial, so please reference the database vendor&#8217;s documentation if you need assistance there. In this tutorial, I am going to use PostgreSQL, but feel free to stick with whatever database you have available\u2014the only part that should change with the code is the connection info to the database.<\/p>\n<p>To install TypeORM (and a couple of additional helper libraries) run the following command in the <code>gsr-server<\/code> folder:<\/p>\n<pre><code class=\"language-bash\">npm install @nestjs\/typeorm typeorm pg\n<\/code><\/pre>\n<blockquote><p>\n  Note: pg is the PostgreSQL driver for Node. If you use a different database, install the appropriate driver.\n<\/p><\/blockquote>\n<h3>Class Transformer<\/h3>\n<p><a href=\"https:\/\/github.com\/typestack\/class-transformer\" target=\"_blank\" rel=\"noopener\">Class Transformer<\/a> is a powerful library that helps with the serialization from everyday JavaScript objects into classes, as well as classes back to plain JavaScript. This library helps convert data coming in from requests to the proper class type.<\/p>\n<p>Install <code>class-transformer<\/code> via npm in the <code>gsr-server<\/code> folder:<\/p>\n<pre><code class=\"language-bash\">npm install class-transformer\n<\/code><\/pre>\n<h2>Adding a Database<\/h2>\n<p>First, we need to register the TypeORM library with Nest and provide it with the connection information to our database.<\/p>\n<p>In the server&#8217;s app module, add <code>TypeOrmModule<\/code> to the list of imports like so:<\/p>\n<p><code>gsr-server\/src\/app.module.ts<\/code>:<\/p>\n<pre><code class=\"language-typescript\">imports: [\n    TypeOrmModule.forRoot({\n      type: &#039;postgres&#039;,\n      host: &#039;localhost&#039;,\n      port: 5432,\n      username: &#039;mydbuser&#039;, \/\/ Update to your db username\n      password: &#039;mydbpassword&#039;, \/\/ Update to your db password\n      database: &#039;gospaceranger&#039;,\n      entities: [__dirname + &#039;\/**\/*.model{.ts,.js}&#039;],\n      synchronize: true,\n    })\n  ],\n<\/code><\/pre>\n<blockquote><p>\n  Import <code>TypeOrmModule<\/code> from &#8216;@nestjs\/typeorm&#8217;<\/p>\n<p>  Note: The synchronize property keeps your database schema up to date with your models, which helps during development, but make sure to disable this in production.\n<\/p><\/blockquote>\n<p>Additionally, you\u2019ll want to make sure to update the connection details (username, password, database, etc.) to your actual setup. The database that you will connect to needs to be a blank database, TypeORM will automatically create the schema for you based on the model definitions.<\/p>\n<p>Now that TypeORM is set up, we need a database entity to represent our missions. We already have the mission model, so let&#8217;s use that.<\/p>\n<p>Open up <code>Mission<\/code> and replace what is currently defined for the model with the following:<\/p>\n<p><code>gsr-server\/src\/models\/mission.model.ts<\/code>:<\/p>\n<pre><code class=\"language-typescript\">import { Entity, PrimaryGeneratedColumn, Column } from &#039;typeorm&#039;;\n\n@Entity()\nexport class Mission {\n  @PrimaryGeneratedColumn()\n  id?: number;\n\n  @Column({ length: 50 })\n  title: string;\n\n  @Column()\n  reward: number;\n\n  @Column()\n  active: boolean;\n\n  @Column() createdAt: Date = new Date();\n  @Column() createdBy: string = &#039;user&#039;;\n  @Column() isDeleted: boolean = false;\n}\n<\/code><\/pre>\n<p>Here our model has decorators applied to the class and its properties imported from TypeORM.<\/p>\n<p>At the class level, the <code>@Entity<\/code> decorators inform TypeORM that this class represents an entity in the database. TypeORM will create a table based on this model and associated all data for this model in that table. By default, it names the table based on the model&#8217;s name, but you could override that by passing in a string to <code>@Entity<\/code>.<\/p>\n<p>The <code>@PrimaryGeneratedColumn<\/code> decorator specifies that our <code>id<\/code> property will be the primary key for the missions table and that the value of it will be generated by the database.<\/p>\n<p>The rest of the properties have <code>@Column<\/code> decorators, which instructs TypeORM to created columns for each of these fields. The data type for the column will be derived from the properties TypeScript type.<\/p>\n<p>There are three additional fields on this mission model that wasn&#8217;t on the original. The <code>createdAt<\/code>, and <code>createdBy<\/code> fields store when the record was created and by whom. The <code>isDeleted<\/code> field gives us soft delete support, in which when a user deletes a record we mark it as deleted, but we keep the original around for our records.<\/p>\n<p>These additional meta-data fields only belong to the database entity, and shouldn&#8217;t be returned to the front end app.  We will add the logic in the <code>MissionsService<\/code> to not returned deleted missions when fetched.<\/p>\n<p>When the Nest server restarts, TypeORM analyzes all the entities and constructs the database schema on it. You should see a schema similar to the following now in your database:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"174\" height=\"221\" data-src=\"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2019\/04\/missionschema.png\" alt=\"\" class=\"aligncenter size-full wp-image-2753 lazyload\" src=\"data:image\/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==\" style=\"--smush-placeholder-width: 174px; --smush-placeholder-aspect-ratio: 174\/221;\" \/><noscript><img loading=\"lazy\" decoding=\"async\" width=\"174\" height=\"221\" src=\"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2019\/04\/missionschema.png\" alt=\"\" class=\"aligncenter size-full wp-image-2753\" \/><\/noscript><\/p>\n<p>Before we try to pull back any data, we will add a mission manually using SQL. Run this SQL statement in your database&#8217;s query tool to insert a single mission:<\/p>\n<pre><code class=\"language-sql\">INSERT INTO public.mission(\n    title, reward, active, &quot;createdAt&quot;, &quot;createdBy&quot;, &quot;isDeleted&quot;)\n    VALUES (&#039;Rescue cat stuck in asteroid&#039;, 500, true, &#039;4\/20\/2019&#039;, &#039;user&#039;, false);\n<\/code><\/pre>\n<h2>Retrieve Missions from the Database<\/h2>\n<p>TypeORM uses the Repository pattern, in which all your data interaction for a particular entity is handled through an object called a repository. The repository has methods to retrieve, create, update, and delete data for that particular entity. TypeORM provides these repositories for us, and we need to register them with Nest.<\/p>\n<p>Go back into the <strong>server<\/strong> <code>AppModule<\/code>, and append <code>TypeOrmModule.forFeature([Mission])<\/code> to the list of imports:<\/p>\n<p><code>gsr-server\/src\/app.module.ts<\/code>:<\/p>\n<pre><code class=\"language-typescript\">imports: [\n    TypeOrmModule.forRoot(...),\n    TypeOrmModule.forFeature([Mission])\n]\n<\/code><\/pre>\n<p>This import registers the <code>Mission<\/code> entity with both TypeORM and Nest and provides us a repository that we can now inject.<\/p>\n<p>Open up <code>MissionsService<\/code>, and update the class to the following:<\/p>\n<p><code>gsr-server\/src\/missions\/missions.service.ts<\/code>:<\/p>\n<pre><code class=\"language-typescript\">export class MissionsService {\n  constructor(\n    @InjectRepository(Mission) private missionsRepository: Repository&lt;Mission&gt;,\n  ) {}\n\n  async getMissions(): Promise&lt;Mission[]&gt; {\n    return this.missionsRepository.find({isDeleted: false});\n  }\n}\n<\/code><\/pre>\n<blockquote><p>\n  Import <code>InjectRepository<\/code> from &#8216;@nestjs\/typeorm&#8217; and <code>Repository<\/code> from &#8216;typeorm&#8217;.\n<\/p><\/blockquote>\n<p>We inject a Mission repository in the constructor of the class using TypeORM&#8217;s generic Repository class. If you are not familiar with generics, they are a TypeScript language feature that allows you to use a base class but have it work with a variety of different types, without having to write that class for each of those types. In our case, we have a base Repository class, but by passing in the Mission as a generic parameter (via <code>Repository&lt;Mission&gt;<\/code>, we set up this repository to work with the  <code>Mission<\/code> type.<\/p>\n<p>The <code>getMissions<\/code> method was updated to return data from the repository instead of the hard-coded array that we also removed. In the method, the repository&#8217;s <code>find<\/code> method is called, and we specify that we only want to return missions that are not deleted.<\/p>\n<p>With the service updated, we should now be able to retrieve all the missions stored in the database, and since the interface of the API hasn&#8217;t changed, the Ionic client should now show live data.<\/p>\n<p>However, if you take a look at the HTTP request, you will see that the data being returned has the meta-data fields (<code>createdAt<\/code>, <code>createdBy<\/code>, and <code>isDeleted<\/code>)  returned as well. Ideally, we would want to exclude these properties as the client does not need them.<\/p>\n<p>We utilize the <code>class-transformer<\/code> library we introduced above to do just that. The library has an <code>@Exclude<\/code> decorator, which when ran through <code>class-transformer<\/code>, will exclude any members decorated with it.<\/p>\n<p>Add the <code>@Exclude<\/code> decorator to those members from the <code>Mission<\/code> model:<\/p>\n<p><code>gsr-server\/src\/models\/mission.model.ts<\/code>:<\/p>\n<pre><code class=\"language-typescript\">@Exclude() @Column() createdAt: Date = new Date();\n@Exclude() @Column() createdBy: string = &#039;user&#039;;\n@Exclude() @Column() isDeleted: boolean = false;\n<\/code><\/pre>\n<p>To exclude the properties, we run them through the <code>classToPlain<\/code> function from the <code>class-transformer<\/code> library. We could do this in the controller like so:<\/p>\n<pre><code class=\"language-typescript\">@Get()\nasync getMissions() {\n  const missionEntities = await this.missionsService.getMissions();\n  const missions = classToPlain(missionEntities);\n  return missions;\n}\n<\/code><\/pre>\n<p>However, this adds some cruft to our controller methods. We would have to repeat this code everywhere we return a mission, and repeating code violates the DRY (don&#8217;t repeat yourself) principle.<\/p>\n<p>Fortunately, Nest provides a mechanism called interceptors that allow manipulation of data before being returned in the request. Let&#8217;s take a look at building one next.<\/p>\n<h2>Nest Interceptors<\/h2>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"544\" height=\"100\" data-src=\"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2019\/04\/nestinterceptor.png\" alt=\"\" class=\"aligncenter size-full wp-image-2754 lazyload\" data-srcset=\"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2019\/04\/nestinterceptor.png 544w, https:\/\/ionic.io\/blog\/wp-content\/uploads\/2019\/04\/nestinterceptor-300x55.png 300w\" data-sizes=\"auto, (max-width: 544px) 100vw, 544px\" src=\"data:image\/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==\" style=\"--smush-placeholder-width: 544px; --smush-placeholder-aspect-ratio: 544\/100;\" \/><noscript><img loading=\"lazy\" decoding=\"async\" width=\"544\" height=\"100\" src=\"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2019\/04\/nestinterceptor.png\" alt=\"\" class=\"aligncenter size-full wp-image-2754\" srcset=\"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2019\/04\/nestinterceptor.png 544w, https:\/\/ionic.io\/blog\/wp-content\/uploads\/2019\/04\/nestinterceptor-300x55.png 300w\" sizes=\"auto, (max-width: 544px) 100vw, 544px\" \/><\/noscript><\/p>\n<p>Interceptors are a piece of Nest middleware that gets access to both the start of the request (before the controller), and then again before the response is sent out (after the controller is done). Interceptors are an ideal fit for any data manipulation that needs to be done before a request is sent out.<\/p>\n<p>In our case, we will build an interceptor to call the <code>classToPlain<\/code> function from <code>class-transformer<\/code> on the data the controller returns, that way any transformations we set up on the models get applied.<\/p>\n<p>Run the following command in the <code>gsr-server<\/code> folder to create a new interceptor using the Nest CLI:<\/p>\n<pre><code class=\"language-bash\">nest g interceptor util\/data\n<\/code><\/pre>\n<p>Update the <code>DataInterceptor<\/code> class with the following:<\/p>\n<p><code>gsr-server\/src\/util\/data.interceptor.ts<\/code>:<\/p>\n<pre><code class=\"language-typescript\">import { classToPlain } from &#039;class-transformer&#039;;\nimport { Observable } from &#039;rxjs&#039;;\nimport { map } from &#039;rxjs\/operators&#039;;\nimport { CallHandler, ExecutionContext, Injectable, NestInterceptor, } from &#039;@nestjs\/common&#039;;\n\n@Injectable()\nexport class DataInterceptor implements NestInterceptor {\n  intercept(context: ExecutionContext, next: CallHandler): Observable&lt;any&gt; {\n    return next.handle().pipe(\n      map(data =&gt; {\n        return classToPlain(data);\n      }),\n    );\n  }\n}\n<\/code><\/pre>\n<p>The <code>next.handle()<\/code> method is an observable stream that you can interact with like any other observable. Here, we use the <code>map<\/code> operator from RXJS to transform the output from one object to another. Specifically, we are using <code>classToPlain<\/code> to apply any transformations added to our models (like we did with <code>Exclude<\/code> in <code>Mission<\/code>).<\/p>\n<p>To use the <code>DataInterceptor<\/code>, Nest provides a few different options to bind it to a request. We can use the <code>@UseInterceptors<\/code> decorator and either put it on a class if we want it to apply to the entire controller like so:<\/p>\n<pre><code class=\"language-typescript\">@UseInterceptors(DataInterceptor)\n@Controller(&#039;missions&#039;)\nexport class MissionsController { ... }\n<\/code><\/pre>\n<p>Alternatively, we can be more selective and put it only on the route handlers we want:<\/p>\n<pre><code class=\"language-typescript\">@UseInterceptors(DataInterceptor)\n@Get()\nasync getMissions() { ... }\n<\/code><\/pre>\n<p>A third option allows us to apply the interceptor to run globally by specifying it in the app module:<\/p>\n<p><code>gsr-server\/src\/app.module.ts<\/code>:<\/p>\n<pre><code class=\"language-typescript\">@Module({\n  providers: [\n    {\n      provide: APP_INTERCEPTOR,\n      useClass: DataInterceptor,\n    },\n  ],\n})\nexport class AppModule {}\n<\/code><\/pre>\n<blockquote><p>\n  Import <code>APP_INTERCEPTOR<\/code> from &#8216;@nestjs\/core&#8217; and <code>DataInterceptor<\/code> from &#8216;.\/util\/data.interceptor&#8217;.\n<\/p><\/blockquote>\n<p>This method is the one we will we use, so go ahead and add this to the list of providers in <code>AppModule<\/code>.<\/p>\n<p>Once saved, hit the <code>\/missions<\/code> endpoint again and you should see the list of missions minus the <code>createdAt<\/code>, <code>createdBy<\/code>, and <code>isDeleted<\/code> members.<\/p>\n<h2>Retrieve a Single Mission<\/h2>\n<p>We are now returning a list of missions, so next, let us see how we can specify the id of the mission in the URL to return a particular mission and display the mission in the app.<\/p>\n<p>Starting in the <code>MissionService<\/code>, the call to get the mission from the repository is fairly straight forward:<\/p>\n<p><code>gsr-server\/src\/missions\/missions.service.ts<\/code>:<\/p>\n<pre><code class=\"language-typescript\">async getMission(id: number): Promise&lt;Mission | undefined&gt; {\n  return this.missionsRepository.findOne(id, {\n    where: {\n      isDeleted: false,\n    },\n  });\n}\n\n<\/code><\/pre>\n<p>The <code>findOne<\/code> method on the repository takes the id of the object being looked for. If found, it returns the object, and if not, returns undefined. We also make sure not to return a mission if it is marked as deleted.<\/p>\n<p>Update the <code>MissionController<\/code> to call into this new service method:<\/p>\n<p><code>gsr-server\/src\/missions\/missions.controller.ts<\/code>:<\/p>\n<pre><code class=\"language-typescript\">@Get(&#039;:id&#039;)\nasync getMission(@Param(&#039;id&#039;) id: number) {\n  return this.missionsService.getMission(id);\n}\n<\/code><\/pre>\n<p>The <code>Get()<\/code> decorator here takes in a route parameter named <code>id<\/code>, and in the <code>getMission<\/code> method, we extract that parameter out using the new <code>@Param<\/code> decorator, which in turn assigns the value to <code>id<\/code>.<\/p>\n<p>If you request <code>http:\/\/localhost:3000\/missions\/1<\/code>, you should notice that nothing comes back. Why? Parameters are passed in as strings, but we expect the <code>id<\/code> to be a number, and the repo does not find the mission because of it. In the params to <code>getMission<\/code>, <code>id<\/code> is of type number, but, unfortunately, we are practically lying to TypeScript that the value is coming in as a number.<\/p>\n<p>We could parse the string value of <code>id<\/code> into a number manually inside the controller method before calling into the service, but once again this muddies our controller code with duplicated logic throughout. It would be nice to have a facility to do this for us automatically.<\/p>\n<p>Nest comes to the rescue again!<\/p>\n<h2>Nest Pipes<\/h2>\n<p>Fortunately, we can use another facet of Nest, called Pipes, to manipulate data that comes in from the request before it reaches the controller. Pipes are another type of Nest middleware, but unlike interceptors, they can transform the data before they reach the controller.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"544\" height=\"101\" data-src=\"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2019\/04\/nestpipe.png\" alt=\"\" class=\"aligncenter size-full wp-image-2755 lazyload\" data-srcset=\"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2019\/04\/nestpipe.png 544w, https:\/\/ionic.io\/blog\/wp-content\/uploads\/2019\/04\/nestpipe-300x56.png 300w\" data-sizes=\"auto, (max-width: 544px) 100vw, 544px\" src=\"data:image\/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==\" style=\"--smush-placeholder-width: 544px; --smush-placeholder-aspect-ratio: 544\/101;\" \/><noscript><img loading=\"lazy\" decoding=\"async\" width=\"544\" height=\"101\" src=\"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2019\/04\/nestpipe.png\" alt=\"\" class=\"aligncenter size-full wp-image-2755\" srcset=\"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2019\/04\/nestpipe.png 544w, https:\/\/ionic.io\/blog\/wp-content\/uploads\/2019\/04\/nestpipe-300x56.png 300w\" sizes=\"auto, (max-width: 544px) 100vw, 544px\" \/><\/noscript><\/p>\n<p>Because we are using TypeScript, Pipes know all the little details about your controller methods, including all the parameters, and the types of those parameters. We can take advantage of this information and use <code>class-transformer<\/code> library again to convert a plain object into something of a specific type. Let&#8217;s see how to do that.<\/p>\n<p>Use the Nest CLI in the <code>gsr-server<\/code> folder to generate a new pipe:<\/p>\n<pre><code class=\"language-bash\">nest g pipe util\/data\n<\/code><\/pre>\n<p>Then open up the <code>DataPipe<\/code> and update its <code>transform<\/code> method to:<\/p>\n<p><code>gsr-server\/src\/util\/data.pipe.ts<\/code>:<\/p>\n<pre><code class=\"language-typescript\">transform(value: any, metadata: ArgumentMetadata) {\n  const { metatype } = metadata;\n  if (!metatype) {\n    return value;\n  }\n  const convertedValue = plainToClass(metatype, value);\n  return convertedValue;\n}\n<\/code><\/pre>\n<blockquote><p>\n  Import <code>plainToClass<\/code> from &#8216;class-transformer&#8217;.\n<\/p><\/blockquote>\n<p>The <code>transform<\/code> method takes two arguments. The first is the original value of the parameter, and the second one is all the meta-data provided by TypeScript about the parameter.<\/p>\n<p>The <code>plainToClass<\/code> method can use this type information to convert the value into the particular type. In our use case, it takes the type of the <code>id<\/code> parameter, a number, and then converts the string parameter that gets passed in from the URL.<\/p>\n<p>Bind the <code>DataPipe<\/code> in the <code>AppModule<\/code> providers like so:<\/p>\n<p><code>gsr-server\/src\/util\/data.pipe.ts<\/code>:<\/p>\n<pre><code class=\"language-typescript\">{\n  provide: APP_PIPE,\n  useClass: DataPipe,\n}\n<\/code><\/pre>\n<blockquote><p>\n  Import <code>APP_PIPE<\/code> from &#8216;@nestjs\/core&#8217; and <code>DataPipe<\/code> from &#8216;.\/util\/data.pipe&#8217;.\n<\/p><\/blockquote>\n<p>Now, parameters passed into all controller handlers have their types converted automatically. Make a call to <code>http:\/\/localhost:3000\/missions\/1<\/code>, and you should see a single mission come back.<\/p>\n<h2>Wrapping Up<\/h2>\n<p>In part two of this series, we spent the majority of time replacing the hard-coded Missions array we had in the <code>MissionsService<\/code> with a real database backend. We used a library called TypeORM to manage our database access. TypeORM is an excellent companion library to Nest; they are both built with TypeScript and offer the same declarative style programming.<\/p>\n<p>Then, we explored Interceptors and Pipes, a couple of the Nest building blocks that allow you to extract common logic into reusable components and apply them in various ways to your Nest controllers.<\/p>\n<p>In the next post, we will finish building out the rest of GoSpaceRanger, including creating, updating, and deleting missions.<\/p>\n<p>Happy coding! \ud83d\ude80<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Welcome to part two of the Full-stack TypeScript with Ionic and NestJS series! In part one of the series, we went over the benefits of using TypeScript on both the client and server, shared an introduction to NestJS, and built a simple app, that\u2019s already up and running, called GoSpaceRanger. So far in GoSpaceRanger, we [&hellip;]<\/p>\n","protected":false},"author":66,"featured_media":2756,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"publish_to_discourse":"","publish_post_category":"","wpdc_auto_publish_overridden":"","wpdc_topic_tags":"","wpdc_pin_topic":"","wpdc_pin_until":"","discourse_post_id":"","discourse_permalink":"","wpdc_publishing_response":"","wpdc_publishing_error":"","_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[121],"tags":[60,3,148],"class_list":["post-2751","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-engineering","tag-angular","tag-ionic","tag-nest"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v23.0 (Yoast SEO v23.0) - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Full-Stack TypeScript with Ionic, Angular, and NestJS Part 2 - Ionic Blog<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/ionic.io\/blog\/full-stack-typescript-with-ionic-angular-and-nestjs-part-2\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Full-Stack TypeScript with Ionic, Angular, and NestJS Part 2\" \/>\n<meta property=\"og:description\" content=\"Welcome to part two of the Full-stack TypeScript with Ionic and NestJS series! In part one of the series, we went over the benefits of using TypeScript on both the client and server, shared an introduction to NestJS, and built a simple app, that\u2019s already up and running, called GoSpaceRanger. So far in GoSpaceRanger, we [&hellip;]\" \/>\n<meta property=\"og:url\" content=\"https:\/\/ionic.io\/blog\/full-stack-typescript-with-ionic-angular-and-nestjs-part-2\" \/>\n<meta property=\"og:site_name\" content=\"Ionic Blog\" \/>\n<meta property=\"article:published_time\" content=\"2019-04-25T17:28:00+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2020-10-15T22:29:58+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2019\/04\/ionic-nestjs-2.png\" \/>\n\t<meta property=\"og:image:width\" content=\"1440\" \/>\n\t<meta property=\"og:image:height\" content=\"798\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"Ely Lucas\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@elylucas\" \/>\n<meta name=\"twitter:site\" content=\"@ionicframework\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Ely Lucas\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"13 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/ionic.io\/blog\/full-stack-typescript-with-ionic-angular-and-nestjs-part-2#article\",\"isPartOf\":{\"@id\":\"https:\/\/ionic.io\/blog\/full-stack-typescript-with-ionic-angular-and-nestjs-part-2\"},\"author\":{\"name\":\"Ely Lucas\",\"@id\":\"https:\/\/ionic.io\/blog\/#\/schema\/person\/d4a019b9a30f6c3db51b24803ab2be9b\"},\"headline\":\"Full-Stack TypeScript with Ionic, Angular, and NestJS Part 2\",\"datePublished\":\"2019-04-25T17:28:00+00:00\",\"dateModified\":\"2020-10-15T22:29:58+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/ionic.io\/blog\/full-stack-typescript-with-ionic-angular-and-nestjs-part-2\"},\"wordCount\":2248,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/ionic.io\/blog\/#organization\"},\"image\":{\"@id\":\"https:\/\/ionic.io\/blog\/full-stack-typescript-with-ionic-angular-and-nestjs-part-2#primaryimage\"},\"thumbnailUrl\":\"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2019\/04\/ionic-nestjs-2.png\",\"keywords\":[\"Angular\",\"Ionic\",\"Nest\"],\"articleSection\":[\"Engineering\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/ionic.io\/blog\/full-stack-typescript-with-ionic-angular-and-nestjs-part-2#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/ionic.io\/blog\/full-stack-typescript-with-ionic-angular-and-nestjs-part-2\",\"url\":\"https:\/\/ionic.io\/blog\/full-stack-typescript-with-ionic-angular-and-nestjs-part-2\",\"name\":\"Full-Stack TypeScript with Ionic, Angular, and NestJS Part 2 - Ionic Blog\",\"isPartOf\":{\"@id\":\"https:\/\/ionic.io\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/ionic.io\/blog\/full-stack-typescript-with-ionic-angular-and-nestjs-part-2#primaryimage\"},\"image\":{\"@id\":\"https:\/\/ionic.io\/blog\/full-stack-typescript-with-ionic-angular-and-nestjs-part-2#primaryimage\"},\"thumbnailUrl\":\"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2019\/04\/ionic-nestjs-2.png\",\"datePublished\":\"2019-04-25T17:28:00+00:00\",\"dateModified\":\"2020-10-15T22:29:58+00:00\",\"breadcrumb\":{\"@id\":\"https:\/\/ionic.io\/blog\/full-stack-typescript-with-ionic-angular-and-nestjs-part-2#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/ionic.io\/blog\/full-stack-typescript-with-ionic-angular-and-nestjs-part-2\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/ionic.io\/blog\/full-stack-typescript-with-ionic-angular-and-nestjs-part-2#primaryimage\",\"url\":\"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2019\/04\/ionic-nestjs-2.png\",\"contentUrl\":\"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2019\/04\/ionic-nestjs-2.png\",\"width\":1440,\"height\":798},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/ionic.io\/blog\/full-stack-typescript-with-ionic-angular-and-nestjs-part-2#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/ionic.io\/blog\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Full-Stack TypeScript with Ionic, Angular, and NestJS Part 2\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/ionic.io\/blog\/#website\",\"url\":\"https:\/\/ionic.io\/blog\/\",\"name\":\"ionic.io\/blog\",\"description\":\"Build amazing native and progressive web apps with the web\",\"publisher\":{\"@id\":\"https:\/\/ionic.io\/blog\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/ionic.io\/blog\/?s={search_term_string}\"},\"query-input\":\"required name=search_term_string\"}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/ionic.io\/blog\/#organization\",\"name\":\"Ionic\",\"url\":\"https:\/\/ionic.io\/blog\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/ionic.io\/blog\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2020\/10\/white-on-color.png\",\"contentUrl\":\"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2020\/10\/white-on-color.png\",\"width\":1920,\"height\":854,\"caption\":\"Ionic\"},\"image\":{\"@id\":\"https:\/\/ionic.io\/blog\/#\/schema\/logo\/image\/\"},\"sameAs\":[\"https:\/\/x.com\/ionicframework\"]},{\"@type\":\"Person\",\"@id\":\"https:\/\/ionic.io\/blog\/#\/schema\/person\/d4a019b9a30f6c3db51b24803ab2be9b\",\"name\":\"Ely Lucas\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/ionic.io\/blog\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/224137763c00c380285e911184f2139f2f4e2f15ecc2fcd9528feebc6d2ddab6?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/224137763c00c380285e911184f2139f2f4e2f15ecc2fcd9528feebc6d2ddab6?s=96&d=mm&r=g\",\"caption\":\"Ely Lucas\"},\"sameAs\":[\"https:\/\/x.com\/elylucas\"],\"url\":\"https:\/\/ionic.io\/blog\/author\/ely\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Full-Stack TypeScript with Ionic, Angular, and NestJS Part 2 - Ionic Blog","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/ionic.io\/blog\/full-stack-typescript-with-ionic-angular-and-nestjs-part-2","og_locale":"en_US","og_type":"article","og_title":"Full-Stack TypeScript with Ionic, Angular, and NestJS Part 2","og_description":"Welcome to part two of the Full-stack TypeScript with Ionic and NestJS series! In part one of the series, we went over the benefits of using TypeScript on both the client and server, shared an introduction to NestJS, and built a simple app, that\u2019s already up and running, called GoSpaceRanger. So far in GoSpaceRanger, we [&hellip;]","og_url":"https:\/\/ionic.io\/blog\/full-stack-typescript-with-ionic-angular-and-nestjs-part-2","og_site_name":"Ionic Blog","article_published_time":"2019-04-25T17:28:00+00:00","article_modified_time":"2020-10-15T22:29:58+00:00","og_image":[{"width":1440,"height":798,"url":"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2019\/04\/ionic-nestjs-2.png","type":"image\/png"}],"author":"Ely Lucas","twitter_card":"summary_large_image","twitter_creator":"@elylucas","twitter_site":"@ionicframework","twitter_misc":{"Written by":"Ely Lucas","Est. reading time":"13 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/ionic.io\/blog\/full-stack-typescript-with-ionic-angular-and-nestjs-part-2#article","isPartOf":{"@id":"https:\/\/ionic.io\/blog\/full-stack-typescript-with-ionic-angular-and-nestjs-part-2"},"author":{"name":"Ely Lucas","@id":"https:\/\/ionic.io\/blog\/#\/schema\/person\/d4a019b9a30f6c3db51b24803ab2be9b"},"headline":"Full-Stack TypeScript with Ionic, Angular, and NestJS Part 2","datePublished":"2019-04-25T17:28:00+00:00","dateModified":"2020-10-15T22:29:58+00:00","mainEntityOfPage":{"@id":"https:\/\/ionic.io\/blog\/full-stack-typescript-with-ionic-angular-and-nestjs-part-2"},"wordCount":2248,"commentCount":0,"publisher":{"@id":"https:\/\/ionic.io\/blog\/#organization"},"image":{"@id":"https:\/\/ionic.io\/blog\/full-stack-typescript-with-ionic-angular-and-nestjs-part-2#primaryimage"},"thumbnailUrl":"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2019\/04\/ionic-nestjs-2.png","keywords":["Angular","Ionic","Nest"],"articleSection":["Engineering"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/ionic.io\/blog\/full-stack-typescript-with-ionic-angular-and-nestjs-part-2#respond"]}]},{"@type":"WebPage","@id":"https:\/\/ionic.io\/blog\/full-stack-typescript-with-ionic-angular-and-nestjs-part-2","url":"https:\/\/ionic.io\/blog\/full-stack-typescript-with-ionic-angular-and-nestjs-part-2","name":"Full-Stack TypeScript with Ionic, Angular, and NestJS Part 2 - Ionic Blog","isPartOf":{"@id":"https:\/\/ionic.io\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/ionic.io\/blog\/full-stack-typescript-with-ionic-angular-and-nestjs-part-2#primaryimage"},"image":{"@id":"https:\/\/ionic.io\/blog\/full-stack-typescript-with-ionic-angular-and-nestjs-part-2#primaryimage"},"thumbnailUrl":"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2019\/04\/ionic-nestjs-2.png","datePublished":"2019-04-25T17:28:00+00:00","dateModified":"2020-10-15T22:29:58+00:00","breadcrumb":{"@id":"https:\/\/ionic.io\/blog\/full-stack-typescript-with-ionic-angular-and-nestjs-part-2#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/ionic.io\/blog\/full-stack-typescript-with-ionic-angular-and-nestjs-part-2"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/ionic.io\/blog\/full-stack-typescript-with-ionic-angular-and-nestjs-part-2#primaryimage","url":"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2019\/04\/ionic-nestjs-2.png","contentUrl":"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2019\/04\/ionic-nestjs-2.png","width":1440,"height":798},{"@type":"BreadcrumbList","@id":"https:\/\/ionic.io\/blog\/full-stack-typescript-with-ionic-angular-and-nestjs-part-2#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/ionic.io\/blog"},{"@type":"ListItem","position":2,"name":"Full-Stack TypeScript with Ionic, Angular, and NestJS Part 2"}]},{"@type":"WebSite","@id":"https:\/\/ionic.io\/blog\/#website","url":"https:\/\/ionic.io\/blog\/","name":"ionic.io\/blog","description":"Build amazing native and progressive web apps with the web","publisher":{"@id":"https:\/\/ionic.io\/blog\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/ionic.io\/blog\/?s={search_term_string}"},"query-input":"required name=search_term_string"}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/ionic.io\/blog\/#organization","name":"Ionic","url":"https:\/\/ionic.io\/blog\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/ionic.io\/blog\/#\/schema\/logo\/image\/","url":"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2020\/10\/white-on-color.png","contentUrl":"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2020\/10\/white-on-color.png","width":1920,"height":854,"caption":"Ionic"},"image":{"@id":"https:\/\/ionic.io\/blog\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/x.com\/ionicframework"]},{"@type":"Person","@id":"https:\/\/ionic.io\/blog\/#\/schema\/person\/d4a019b9a30f6c3db51b24803ab2be9b","name":"Ely Lucas","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/ionic.io\/blog\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/224137763c00c380285e911184f2139f2f4e2f15ecc2fcd9528feebc6d2ddab6?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/224137763c00c380285e911184f2139f2f4e2f15ecc2fcd9528feebc6d2ddab6?s=96&d=mm&r=g","caption":"Ely Lucas"},"sameAs":["https:\/\/x.com\/elylucas"],"url":"https:\/\/ionic.io\/blog\/author\/ely"}]}},"jetpack_sharing_enabled":true,"jetpack_featured_media_url":"https:\/\/ionic.io\/blog\/wp-content\/uploads\/2019\/04\/ionic-nestjs-2.png","_links":{"self":[{"href":"https:\/\/ionic.io\/blog\/wp-json\/wp\/v2\/posts\/2751","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/ionic.io\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/ionic.io\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/ionic.io\/blog\/wp-json\/wp\/v2\/users\/66"}],"replies":[{"embeddable":true,"href":"https:\/\/ionic.io\/blog\/wp-json\/wp\/v2\/comments?post=2751"}],"version-history":[{"count":0,"href":"https:\/\/ionic.io\/blog\/wp-json\/wp\/v2\/posts\/2751\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/ionic.io\/blog\/wp-json\/wp\/v2\/media\/2756"}],"wp:attachment":[{"href":"https:\/\/ionic.io\/blog\/wp-json\/wp\/v2\/media?parent=2751"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/ionic.io\/blog\/wp-json\/wp\/v2\/categories?post=2751"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/ionic.io\/blog\/wp-json\/wp\/v2\/tags?post=2751"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}