<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Kevin Merckx</title>
    <description>The latest articles on DEV Community by Kevin Merckx (@kevinmerckx_47).</description>
    <link>https://dev.to/kevinmerckx_47</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F782832%2F9dab4e9e-6930-4526-85f8-e65861ba2d89.jpg</url>
      <title>DEV Community: Kevin Merckx</title>
      <link>https://dev.to/kevinmerckx_47</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/kevinmerckx_47"/>
    <language>en</language>
    <item>
      <title>JavaScript is not meant for backend</title>
      <dc:creator>Kevin Merckx</dc:creator>
      <pubDate>Sat, 08 Feb 2025 12:10:12 +0000</pubDate>
      <link>https://dev.to/kevinmerckx_47/javascript-is-not-meant-for-backend-3j15</link>
      <guid>https://dev.to/kevinmerckx_47/javascript-is-not-meant-for-backend-3j15</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimages.unsplash.com%2Fphoto-1436812911242-3d475df4bdd1%3Fcrop%3Dentropy%26cs%3Dtinysrgb%26fit%3Dmax%26fm%3Djpg%26ixid%3DM3wxMTc3M3wwfDF8c2VhcmNofDd8fHVuc2FmZXxlbnwwfHx8fDE3MzY1NDMwOTF8MA%26ixlib%3Drb-4.0.3%26q%3D80%26w%3D2000" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimages.unsplash.com%2Fphoto-1436812911242-3d475df4bdd1%3Fcrop%3Dentropy%26cs%3Dtinysrgb%26fit%3Dmax%26fm%3Djpg%26ixid%3DM3wxMTc3M3wwfDF8c2VhcmNofDd8fHVuc2FmZXxlbnwwfHx8fDE3MzY1NDMwOTF8MA%26ixlib%3Drb-4.0.3%26q%3D80%26w%3D2000" alt="JavaScript is not meant for backend" width="2000" height="1333"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I recently started learning Go. It has been advertised to me as a great programming language to create web services with a very good built-in concurrency library.&lt;/p&gt;

&lt;p&gt;While going through the tutorials, I noticed the way Go makes developers handle errors and how different it is compared to Javascript. In this post, I want to go through this difference and will conclude by stating my preference.&lt;/p&gt;

&lt;p&gt;Javascript is not typed. Functions can return whatever they want: numbers, booleans, functions, strings, etc. It's up to developers to document functions properly and/or use JSDoc, Typescript and alike. Let's look at a very simple example together.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function main() {
  const stringified = JSON.stringify({ aBigInt: 2n });
  console.log(stringified);
}

main();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The code above will result in an exception that makes the program crash:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  const stringified = JSON.stringify({ aBigInt: 2n });
                           ^

TypeError: Do not know how to serialize a BigInt
    at JSON.stringify (&amp;lt;anonymous&amp;gt;)
    at main (/home/kmerckx/dev/blog/index.js:2:28)
    at Object.&amp;lt;anonymous&amp;gt; (/home/kmerckx/dev/blog/index.js:6:1)
    at Module._compile (node:internal/modules/cjs/loader:1565:14)
    at Object..js (node:internal/modules/cjs/loader:1708:10)
    at Module.load (node:internal/modules/cjs/loader:1318:32)
    at Function._load (node:internal/modules/cjs/loader:1128:12)
    at TracingChannel.traceSync (node:diagnostics_channel:322:14)
    at wrapModuleLoad (node:internal/modules/cjs/loader:219:24)
    at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:170:5)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If that piece of code that serializes an object would be running on a HTTP server, it would likely crash it. To get around that issue, developers (or the framework they use) have to wrap the call to &lt;code&gt;JSON.stringify&lt;/code&gt; in a &lt;code&gt;try...catch&lt;/code&gt;. A modified version of the script could be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function main() {
  try {
    const stringified = JSON.stringify({ aBigInt: 2n });
    console.log(stringified);
  } catch (error) {
    console.error('We got an error here, can not print the stringified object', error);
  }
}

main();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The program doesn't crash and exits with code &lt;code&gt;0&lt;/code&gt;. What we are experiencing here is a consequence of JavaScript error handling: errors can be thrown and it's up to you to catch them. Within a simple program, it's not a big deal: you call standard ECMAScript functions, put some try catch around them, done. As soon as your program is more complex, those standard functions end up being called pretty deep in the call stack. Every level of this stack can receive errors that bubble up from the levels below, making the error handling very hard to figure out.&lt;/p&gt;

&lt;p&gt;You would think that Typescript could help in this endeavor but it doesn't. The error that you catch is of type &lt;code&gt;unknown&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;A language like Go has a built-in error type and lets developers handle errors as values. It forces you to handle errors. You can not ignore them. In the following example, you can see that in action:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;f, err := os.Open("filename.ext")
if err != nil {
    log.Fatal(err)
}
// do something with the open *File f
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Example from &lt;a href="https://go.dev/blog/error-handling-and-go" rel="noopener noreferrer"&gt;https://go.dev/blog/error-handling-and-go&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I like the simplicity of JavaScript but I came to realize that the error handling was one of the major flaws of its design: a simple scripting language that lets you walk very fast on the happy path. Unfortunately, web services are rarely made of happy paths. You might have to deal with malformed data, network issues, etc.&lt;/p&gt;

&lt;p&gt;I work a lot with JavaScript and while I think it's not meant for backend development, I also think there is a lot of value in using it with Typescript in a full-stack team to rapidly create products. In the second part of this post, I will present an attempt to make JavaScript error handling a lot nicer. It does have its limits and I will also present them.&lt;/p&gt;

&lt;p&gt;I really like Go's approach and the solution I implemented is inspired from it. It is especially powerful when used with Typescript.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { makeSuccess, makeFailure, SafeResult } from '@km/saferjs'; // this is not published on NPM!!

function someSafeFunction(): SafeResult&amp;lt;number, SomeCustomError | TypeError&amp;gt; {
  try {
    return makeSuccess(
      ... // your logic here
    );
    // you can also return a makeFailure(...)
  } catch(error) {
    // maybe it's a TypeError: error instanceof TypeError
    return makeFailure(error);
    // error handling goes here
    return makeFailure(new SomeCustomErrorClass());
  }
}

const { result, error } = someFunction();
// at this point Typescript knows that result is either null or a number
// and error is either null or one of the type SomeCustomError, TypeError

if (error) {
  // handle the error
  // at this point, you can early-throw or -return
  // Typescript will understand that after this if-block, result is defined.
} else {
  // result is a number
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The type inference is perfectly done by Typescript, giving your a lot more safety at transpile time. I also came up with two helper functions &lt;code&gt;isFailure&lt;/code&gt; and &lt;code&gt;isSuccess&lt;/code&gt;that can be used as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const someResult = someFunction();

if (isFailure(someResut)) {
  // handle error
}

if (isSuccess(someResult)) {
  // happy days!
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After implementing that approach and adopting it in the code I write, I realized it suffers on major drawback: none of the JS standard functions follow this patter and they all throw errors. Making the code in my projects be perfectly safe to use would mean that I have to wrap all standard function calls. Tedious.&lt;/p&gt;

&lt;p&gt;I can make Nodejs backend very safe with such an approach but I came to realize that, if it's not built-in the foundation of the language, it's never going to be a good developer experience. JavaScript is just not meant for backend.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>TL8 goes 100% open source</title>
      <dc:creator>Kevin Merckx</dc:creator>
      <pubDate>Sat, 04 Jan 2025 18:51:05 +0000</pubDate>
      <link>https://dev.to/kevinmerckx_47/tl8-goes-100-open-source-4o7k</link>
      <guid>https://dev.to/kevinmerckx_47/tl8-goes-100-open-source-4o7k</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimages.unsplash.com%2Fphoto-1599595344070-c456bea6ee98%3Fcrop%3Dentropy%26cs%3Dtinysrgb%26fit%3Dmax%26fm%3Djpg%26ixid%3DM3wxMTc3M3wwfDF8c2VhcmNofDJ8fG9wZW58ZW58MHx8fHwxNzM2MDE1ODU5fDA%26ixlib%3Drb-4.0.3%26q%3D80%26w%3D2000" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimages.unsplash.com%2Fphoto-1599595344070-c456bea6ee98%3Fcrop%3Dentropy%26cs%3Dtinysrgb%26fit%3Dmax%26fm%3Djpg%26ixid%3DM3wxMTc3M3wwfDF8c2VhcmNofDJ8fG9wZW58ZW58MHx8fHwxNzM2MDE1ODU5fDA%26ixlib%3Drb-4.0.3%26q%3D80%26w%3D2000" alt="TL8 goes 100% open source" width="800" height="494"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I opened the source code of TL8. It is available on Github under two separate repositories: &lt;a href="https://github.com/kevinmerckx/tl8" rel="noopener noreferrer"&gt;https://github.com/kevinmerckx/tl8&lt;/a&gt; and &lt;a href="https://github.com/kevinmerckx/tl8-app" rel="noopener noreferrer"&gt;https://github.com/kevinmerckx/tl8-app&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I started TL8 as a side project almost exactly three years ago. It proved to be very useful in a few projects of mine, which was already a good achievement in itself. Furthermore, the application was downloaded by 50 different users in the past 9 months (I lost the data before that...). TL8 is an application that helps development teams translate their web application. I was expecting to get users from all over the world and that is the case! TL8 has been used in Ireland, Germany, Brazil, Poland, USA, Spain, France, Romania, Canada, Belgium, Italy, Egypt, Argentina, Syria, etc.&lt;/p&gt;

&lt;p&gt;I based my decision of making TL8 open source on 4 key arguments:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;many developers mentioned that not being open-source was a concern to them&lt;/li&gt;
&lt;li&gt;some components in TL8 could be useful to the community&lt;/li&gt;
&lt;li&gt;it could give a second life to the project and motivate me and others to pursue its development&lt;/li&gt;
&lt;li&gt;my strategy to generate some revenues through donations failed (I might have been naive)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Overall, it was a positive experience: a great technical achievement and important lessons learned on the way. I will explain that further in an upcoming post.&lt;/p&gt;

</description>
      <category>tl8</category>
    </item>
    <item>
      <title>TL8 goes React (Beta)</title>
      <dc:creator>Kevin Merckx</dc:creator>
      <pubDate>Fri, 29 Mar 2024 12:03:07 +0000</pubDate>
      <link>https://dev.to/kevinmerckx_47/tl8-goes-react-beta-o9c</link>
      <guid>https://dev.to/kevinmerckx_47/tl8-goes-react-beta-o9c</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcuvt5zl9d2nv02t9hn3s.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcuvt5zl9d2nv02t9hn3s.png" alt="TL8 goes React (Beta)" width="516" height="276"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;TL8 now supports React. I assumed it would not require any change in the TL8 application code and should only require me to write the React TL8 counterpart (the one that developers have to put in their React application). And I was happily surprised to be right!&lt;/p&gt;

&lt;p&gt;TL8 is based on a home-made protocol that makes it talk to the Angular and React plugins. This protocol is framework agnostic. That is why making TL8 compatible with React was very straight-forward.&lt;/p&gt;

&lt;p&gt;I have also made the TL8 React library 100% open-source and am planning to do the same for the Angular library. Several people asked me whether TL8 was open-source. It is partially open-source now.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;tl8-react&lt;/code&gt; provides a translation system and the necessary pieces to be used with the TL8 application. It is available in Beta on NPM: &lt;a href="https://www.npmjs.com/package/tl8-react" rel="noopener noreferrer"&gt;https://www.npmjs.com/package/tl8-react&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The latest TL8 application is available on &lt;a href="https://tl8.io/" rel="noopener noreferrer"&gt;https://tl8.io/&lt;/a&gt; and works out of the box with your React application.&lt;/p&gt;

&lt;p&gt;Enjoy.&lt;/p&gt;

</description>
      <category>tl8</category>
    </item>
    <item>
      <title>The power of End-to-End tests</title>
      <dc:creator>Kevin Merckx</dc:creator>
      <pubDate>Tue, 26 Dec 2023 21:05:16 +0000</pubDate>
      <link>https://dev.to/kevinmerckx_47/the-power-of-end-to-end-tests-24on</link>
      <guid>https://dev.to/kevinmerckx_47/the-power-of-end-to-end-tests-24on</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimages.unsplash.com%2Fphoto-1512375305577-4dc349fcef0b%3Fcrop%3Dentropy%26cs%3Dtinysrgb%26fit%3Dmax%26fm%3Djpg%26ixid%3DM3wxMTc3M3wwfDF8c2VhcmNofDczfHxhdXRvbWF0aW9ufGVufDB8fHx8MTcwMzYyNDY0NHww%26ixlib%3Drb-4.0.3%26q%3D80%26w%3D2000" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimages.unsplash.com%2Fphoto-1512375305577-4dc349fcef0b%3Fcrop%3Dentropy%26cs%3Dtinysrgb%26fit%3Dmax%26fm%3Djpg%26ixid%3DM3wxMTc3M3wwfDF8c2VhcmNofDczfHxhdXRvbWF0aW9ufGVufDB8fHx8MTcwMzYyNDY0NHww%26ixlib%3Drb-4.0.3%26q%3D80%26w%3D2000" alt="The power of End-to-End tests" width="800" height="539"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this article, I will advocate for using End-to-End (E2E) tests. I will start by defining what E2E tests are and what they are not. After this, I will try to convince you to use them as one of the essential bricks of your future and current projects. The last section is providing answers to the most common criticisms addressed to E2E tests.&lt;/p&gt;

&lt;h2&gt;
  
  
  Definition
&lt;/h2&gt;

&lt;p&gt;E2E tests ensure that an entire system verifies a set of requirements. There are two implications to that definition:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A set of requirements is defined.&lt;/li&gt;
&lt;li&gt;We have the ability to run an entire system in our testing setup.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;E2E tests are written in a way that we can verify that the requirements are fulfilled by the system. They can be as simple as &lt;em&gt;"Users can sign into the application using the Login form"&lt;/em&gt; and as complex as describing a sequence of actions that users will likely go through while using the system.&lt;/p&gt;

&lt;p&gt;What a good E2E testing setup should not do:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Mock parts of the application, especially the critical ones, like the database and the ORM (Object Relational Mapping). Ideally, a E2E testing setup doesn't mock anything.&lt;/li&gt;
&lt;li&gt;Tests should not describe how the system works, rather focus on how users interact with the system.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why use E2E tests?
&lt;/h2&gt;

&lt;p&gt;I see two main reasons why every project should have a strong emphasis on E2E tests:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;They guarantee that requirements are fulfilled.&lt;/strong&gt; They verify that, given an input (given by the user), some output is returned or that the system reached a certain state. We are making sure that the system is doing what is expected. Not how it's done. Therefore, they highly focus on making sure the value is delivered.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;They speed up development.&lt;/strong&gt; Yes, you read me correctly. Let's look at two examples: backend and frontend development.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Backend development
&lt;/h3&gt;

&lt;p&gt;Imagine that you are working on implementing an API delivered through HTTP. Whether you want it or not, you are going to end up calling your API endpoints and checking that they behave like you expect. Calling your API endpoints manually requires you to use Postman, or Chrome, or any other client. With a good E2E test setup, you can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;write your tests,&lt;/li&gt;
&lt;li&gt;change your code,&lt;/li&gt;
&lt;li&gt;and see the results of the tests as frequently as hitting the save button of your IDE.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That way, you don't have to trigger the tests manually. You code, you see the results. Imagine your screen being split in two windows: one is your IDE, one is the testing framework constant running the tests for you.&lt;/p&gt;

&lt;h3&gt;
  
  
  Frontend development
&lt;/h3&gt;

&lt;p&gt;Testing your frontend from end to end brings even more value. Manually interacting with a user interface is slow and tedious. &lt;strong&gt;Being able to automate those interactions saves enormous amounts of time.&lt;/strong&gt; You can have your testing environment set up in a way that saving files automatically triggers the tests you pre-selected and verifies that they do what is required. You can also use those tests to reach a certain state of your application and work from there.&lt;/p&gt;

&lt;p&gt;The tests you are writing to automate interactions can then be used and should be meant to last. They become part of the requirements that must be verified. You achieved two goals: your software is tested and an excellent developer experience (DevX). You save time and deliver quality. It's all about the value.&lt;/p&gt;

&lt;h2&gt;
  
  
  Common criticisms
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;E2E tests are slow:&lt;/strong&gt; E2E tests, especially for frontend, are slower to run that integration or unit tests. That is true but also, what do you care? On a developer's machine, one can always select the tests they want to run. As part of  a continuous integration pipeline, a few minutes more won't make a huge difference on your budget. It will take more time to complete until delivery but the value they bring seems to completely outweigh those longer jobs. Furthermore, in a Continuous Delivery setup, releasing software to production regularly is better done when we have the guarantee that the software is doing what it is supposed to do. And there is nothing better than E2E tests to achieve that. &lt;strong&gt;You can then release your software more often, as it requires less manual testing.&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Writing tests takes time:&lt;/strong&gt; as most skills, you get better at it by practicing. The first time you write a test, you must learn the testing framework, formulate exactly what you want to test, put it in code. And like many skills, you will be slow at the beginning. The good news is that you won't get any slower! You will get better at it pretty fast. Invest in yourself, learn this skill and save your future self from ever having to test things manually. Furthermore, we now have access to AI based code generation tools that can write the tests for you in a matter of seconds.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Maintaining tests take time:&lt;/strong&gt; yes, just like any code you write. The advantage of E2E tests is that they should resist changes pretty well, assuming that the requirements of the system don't change. E2E tests are very useful to guarantee that requirements are fulfilled. Therefore, E2E tests most likely break due to a change of requirements. When it happens, they are a reminder that they must be adjusted (replaced or modified) as well.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Thanks for reading this post. I hope you are convinced now that writing E2E tests should be part of your workflow. I was skeptical at first (cf. &lt;a href="https://dev.to/kevinmerckx_47/integration-testing-setup-with-nestjs-and-mongodb-43mp"&gt;https://blog.merckx.fr/integration-testing-setup-with-nestjs-and-mongodb/&lt;/a&gt;). Writing E2E tests take practice. Once it's there, you will never want to go back.&lt;/p&gt;

</description>
      <category>devrel</category>
    </item>
    <item>
      <title>How to protect endpoints of a Nestjs application - Revisited</title>
      <dc:creator>Kevin Merckx</dc:creator>
      <pubDate>Sat, 23 Dec 2023 09:33:38 +0000</pubDate>
      <link>https://dev.to/kevinmerckx_47/how-to-protect-endpoints-of-a-nestjs-application-revisited-45n6</link>
      <guid>https://dev.to/kevinmerckx_47/how-to-protect-endpoints-of-a-nestjs-application-revisited-45n6</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimages.unsplash.com%2Fphoto-1516478379578-ea8bea43365f%3Fcrop%3Dentropy%26cs%3Dtinysrgb%26fit%3Dmax%26fm%3Djpg%26ixid%3DM3wxMTc3M3wwfDF8c2VhcmNofDI1fHxzdWdhciUyMGNvYXRpbmd8ZW58MHx8fHwxNzAzMzI0MDY5fDA%26ixlib%3Drb-4.0.3%26q%3D80%26w%3D2000" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimages.unsplash.com%2Fphoto-1516478379578-ea8bea43365f%3Fcrop%3Dentropy%26cs%3Dtinysrgb%26fit%3Dmax%26fm%3Djpg%26ixid%3DM3wxMTc3M3wwfDF8c2VhcmNofDI1fHxzdWdhciUyMGNvYXRpbmd8ZW58MHx8fHwxNzAzMzI0MDY5fDA%26ixlib%3Drb-4.0.3%26q%3D80%26w%3D2000" alt="How to protect endpoints of a Nestjs application - Revisited" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Two years ago, I wrote a post about &lt;a href="https://blog.merckx.fr/globally-protect-routes-of-a-nestjs-application/" rel="noopener noreferrer"&gt;protecting API endpoints of a Nestjs application&lt;/a&gt;. To summarize it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;use the declarative approach of Nestjs and protect the whole application by default behind a guard.&lt;/li&gt;
&lt;li&gt;provide your project with a decorator that you can add on controllers and controllers' methods to opt out of the default guard protection.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I realized there was a nicer syntax than &lt;code&gt;@SetMetadata(AUTH_GUARD_CONFIG, { disabled: true } as AuthGuardConfig)&lt;/code&gt;. Simply create a function that does it, just with a much better name:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export const AllowUnauthorized = () =&amp;gt; SetMetadata(AUTH_GUARD_CONFIG, { disabled: true } as AuthGuardConfig);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it!&lt;/p&gt;

</description>
      <category>nestjs</category>
    </item>
    <item>
      <title>tl8 3 is out</title>
      <dc:creator>Kevin Merckx</dc:creator>
      <pubDate>Mon, 30 Jan 2023 11:21:24 +0000</pubDate>
      <link>https://dev.to/kevinmerckx_47/tl8-3-is-out-20h1</link>
      <guid>https://dev.to/kevinmerckx_47/tl8-3-is-out-20h1</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimages.unsplash.com%2Fphoto-1601388152430-4ad0f14c0788%3Fcrop%3Dentropy%26cs%3Dtinysrgb%26fit%3Dmax%26fm%3Djpg%26ixid%3DMnwxMTc3M3wwfDF8c2VhcmNofDF8fGZsb3d8ZW58MHx8fHwxNjc1MDc1NjQz%26ixlib%3Drb-4.0.3%26q%3D80%26w%3D2000" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimages.unsplash.com%2Fphoto-1601388152430-4ad0f14c0788%3Fcrop%3Dentropy%26cs%3Dtinysrgb%26fit%3Dmax%26fm%3Djpg%26ixid%3DMnwxMTc3M3wwfDF8c2VhcmNofDF8fGZsb3d8ZW58MHx8fHwxNjc1MDc1NjQz%26ixlib%3Drb-4.0.3%26q%3D80%26w%3D2000" alt="tl8 3 is out" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;TL8 1 was a great proof of concept and proved to be useful. TL8 2 was a step to improve the user experience. TL8 3 is now available on &lt;a href="https://tl8.io" rel="noopener noreferrer"&gt;tl8.io&lt;/a&gt; and is bringing three new features:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the Markdown editor&lt;/li&gt;
&lt;li&gt;the Full Editor&lt;/li&gt;
&lt;li&gt;import &amp;amp; export of work in progress&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Markdown Editor
&lt;/h2&gt;

&lt;p&gt;The Markdown editor is feature that is coming handy for all Angular applications that use markdown to format the content of translation keys.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fevyjfxx4s2si2c4is6da.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fevyjfxx4s2si2c4is6da.png" alt="tl8 3 is out" width="800" height="458"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;The Markdown Editor in action&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Full Editor
&lt;/h2&gt;

&lt;p&gt;The Full Editor enables users to go through translation keys of the entire application without navigating to the according views. Users can search for translations and use the tree view to easily find and edit translations.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv1b0gc99kqzia2zq79qu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv1b0gc99kqzia2zq79qu.png" alt="tl8 3 is out" width="800" height="407"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Import &amp;amp; Export
&lt;/h2&gt;

&lt;p&gt;The Import &amp;amp; Export of work in progress is a first step to support collaboration workflows. Users can now work on the same application in parallel and integrate each other's work into theirs. The workflow of import-export is made through "work-in-progress" TL8 files. One user can export their work, hand the &lt;code&gt;.tl8&lt;/code&gt; file to someone else who can import it and integrate the changes into theirs. The application lets you know about conflicts and gives the opportunity to users to pick which version they wish to keep.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frfxyt4o8z0h7ztkk8t6q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frfxyt4o8z0h7ztkk8t6q.png" alt="tl8 3 is out" width="800" height="458"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;The import workflow here letting the user resolving conflicts.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Design adjustments
&lt;/h2&gt;

&lt;p&gt;Along with those 3 features, TL8 has been slightly redesigned: the sidebar now displays the language switch, the sidebar toggle and the switch from Live to Full Editor at the bottom.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's coming next?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;TL8 will soon move to the next level. A live collaboration is currently in Alpha. This should help users work on bigger projects as a team.&lt;/li&gt;
&lt;li&gt;Getting a first version of an application translated to a new language should not be hard. TL8 will help achieve that.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Many thanks to &lt;a href="https://www.linkedin.com/in/asset-ismagambetov" rel="noopener noreferrer"&gt;Asset Ismagambetov&lt;/a&gt; for the help and support to pull that new version.&lt;/p&gt;

</description>
      <category>tl8</category>
    </item>
    <item>
      <title>tl8 1.0.0 is out</title>
      <dc:creator>Kevin Merckx</dc:creator>
      <pubDate>Fri, 08 Apr 2022 21:38:40 +0000</pubDate>
      <link>https://dev.to/kevinmerckx_47/tl8-100-is-out-a5c</link>
      <guid>https://dev.to/kevinmerckx_47/tl8-100-is-out-a5c</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimages.unsplash.com%2Fphoto-1617360547704-3da8b5363369%3Fcrop%3Dentropy%26cs%3Dtinysrgb%26fit%3Dmax%26fm%3Djpg%26ixid%3DMnwxMTc3M3wwfDF8c2VhcmNofDh8fGJveHxlbnwwfHx8fDE2NDk0NTM0Nzk%26ixlib%3Drb-1.2.1%26q%3D80%26w%3D2000" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimages.unsplash.com%2Fphoto-1617360547704-3da8b5363369%3Fcrop%3Dentropy%26cs%3Dtinysrgb%26fit%3Dmax%26fm%3Djpg%26ixid%3DMnwxMTc3M3wwfDF8c2VhcmNofDh8fGJveHxlbnwwfHx8fDE2NDk0NTM0Nzk%26ixlib%3Drb-1.2.1%26q%3D80%26w%3D2000" alt="tl8 1.0.0 is out" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I released tl8 last year. It came with a few integration issues. The main one was that I built the application with Electron and embedded a web view to render the application to be translated. Problem: some web apps have security settings or workflows that don't allow for such a rendering.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;With tl8 1.0.0, all Angular apps can be translated.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It took some time but it's here. The application is available for Mac, Windows and Linux. You can check the home page for more information: &lt;a href="https://tl8.io/" rel="noopener noreferrer"&gt;https://tl8.io/&lt;/a&gt;.  The web application no longer exists as it would be too much work to maintain it and would need iframes to run and would therefore suffer from the limitations I mentionned above. The journey to get around the limitations of Electron involved several &lt;code&gt;BrowerViews&lt;/code&gt;. One of them is dedicated to run the target application and doesn't have any limitation regarding the content it can run!&lt;/p&gt;

&lt;p&gt;1.0.0 provides a solid user experience that enables you to easily change translations and content in an Angular application. It also comes with some bug fixes.&lt;/p&gt;

&lt;p&gt;There are features and improvements planned for the next iteration that will be described in a further blog post.&lt;/p&gt;

&lt;p&gt;--&lt;/p&gt;

&lt;p&gt;KM&lt;/p&gt;

</description>
      <category>tl8</category>
      <category>angular</category>
    </item>
    <item>
      <title>An Angular technique that might surprise you</title>
      <dc:creator>Kevin Merckx</dc:creator>
      <pubDate>Fri, 11 Feb 2022 14:11:33 +0000</pubDate>
      <link>https://dev.to/kevinmerckx_47/an-angular-technique-that-might-surprise-you-4nc4</link>
      <guid>https://dev.to/kevinmerckx_47/an-angular-technique-that-might-surprise-you-4nc4</guid>
      <description>&lt;p&gt;Special thanks to &lt;a href="https://twitter.com/ngfelixl" rel="noopener noreferrer"&gt;https://twitter.com/ngfelixl&lt;/a&gt; for helping me structure this work.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F243q07zohxp4fjn9gz7x.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F243q07zohxp4fjn9gz7x.jpg" alt="An Angular technique that might surprise you" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I was recently working on an Angular application that had a specific requirement. The application shell loads feature modules under specific routes. Each module should have the ability to expose an item in the application shell toolbar. With one colleague we discussed how we could achieve that.&lt;/p&gt;

&lt;p&gt;If you can't wait to see it in action, here is the link to the repo: &lt;a href="https://github.com/kevinmerckx/ng-feature-extension" rel="noopener noreferrer"&gt;https://github.com/kevinmerckx/ng-feature-extension&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  First naive attempt
&lt;/h2&gt;

&lt;p&gt;We considered using the Angular CDK and its portal API. The limitation appeared pretty quickly: the menu item declaration, from within the template of the root component of the feature module will &lt;strong&gt;only be evaluated when the feature is loaded by the router&lt;/strong&gt;. Therefore, this approach is not suitable.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;We need an "offline" way to declare this toolbar item, without the entire feature module to be loaded.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Solution
&lt;/h2&gt;

&lt;p&gt;The solution I suggest is based on three pillars:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;injection tokens&lt;/li&gt;
&lt;li&gt;extension modules&lt;/li&gt;
&lt;li&gt;component outlets&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's describe each pillar first.&lt;/p&gt;

&lt;h3&gt;
  
  
  Injection tokens
&lt;/h3&gt;

&lt;p&gt;Injection tokens are an important part of Angular. They give developers the opportunity to augment the application. For instance, to declare a directive as validator you use &lt;code&gt;NG_VALIDATORS&lt;/code&gt;. When you want to declare a custom control value accessor (cf. &lt;a href="https://dev.to/kevinmerckx_47/create-a-custom-angular-form-control-3one"&gt;https://dev.to/kevinmerckx_47/create-a-custom-angular-form-control-3one&lt;/a&gt;), you use &lt;code&gt;NG_VALUE_ACCESSOR&lt;/code&gt;. When you use them, Angular gives you the ability to extend its API.&lt;/p&gt;

&lt;h3&gt;
  
  
  Extension modules
&lt;/h3&gt;

&lt;p&gt;When you create a feature module, you usually do so by exporting one Angular module. You then load it in the main module, lazily or not. Keep in mind that you are allowed to split your feature module into several smaller modules. You can provide the shell of your feature through one module and export another one that provides a smaller set of features. Let's call the later kind Extension Modules.&lt;/p&gt;

&lt;h3&gt;
  
  
  Component Outlets
&lt;/h3&gt;

&lt;p&gt;This API is provided by Angular and gives developers the ability to inject components in a template.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;ng-container&lt;/span&gt; &lt;span class="na"&gt;*ngComponentOutlet=&lt;/span&gt;&lt;span class="s"&gt;"theComponentToLoad"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/ng-container&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With those 3 pillars, we can create a mechanism that enables a feature module to use offline an extension API provided by the shell application.&lt;/p&gt;

&lt;p&gt;First, you should declare an interface that extensions of feature modules must implement.&lt;/p&gt;

&lt;p&gt;For instance, if you want a module to be able to add an item in your application toolbar, your interface could look like that:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Type&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@angular/core&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Observable&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;rxjs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Extension&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;toolbarItem&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Type&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;route&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Observable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// here we also provide the route to load when the item is clicked&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, you must declare the injection token that each feature module can provide. Let's call it &lt;code&gt;FEATURE_EXTENSION&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;InjectionToken&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@angular/core&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;FEATURE_EXTENSION&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;InjectionToken&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;FEATURE_EXTENSION&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It is now possible for our &lt;code&gt;toolbar&lt;/code&gt; component to use this token at runtime:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Inject&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@angular/core&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Extension&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;FEATURE_EXTENSION&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../shared&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;toolbar&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;templateUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./toolbar.component.html&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;styleUrls&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./toolbar.component.css&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ToolbarComponent&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(@&lt;/span&gt;&lt;span class="nd"&gt;Inject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;FEATURE_EXTENSION&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nx"&gt;extensions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Extension&lt;/span&gt;&lt;span class="p"&gt;[])&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It is now time to use the &lt;code&gt;ngComponentOutlet&lt;/code&gt; directive from the toolbar template:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt;
  &lt;span class="na"&gt;*ngFor=&lt;/span&gt;&lt;span class="s"&gt;"let extension of extensions"&lt;/span&gt;
  &lt;span class="na"&gt;tabIndex=&lt;/span&gt;&lt;span class="s"&gt;"0"&lt;/span&gt;
  &lt;span class="na"&gt;[routerLink]=&lt;/span&gt;&lt;span class="s"&gt;"extension.route | async"&lt;/span&gt;
  &lt;span class="na"&gt;[routerLinkActive]=&lt;/span&gt;&lt;span class="s"&gt;"'active'"&lt;/span&gt;
  &lt;span class="na"&gt;[routerLinkActiveOptions]=&lt;/span&gt;&lt;span class="s"&gt;"{ exact: true }"&lt;/span&gt;
&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;ng-container&lt;/span&gt; &lt;span class="na"&gt;*ngComponentOutlet=&lt;/span&gt;&lt;span class="s"&gt;"extension.toolbarItem"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/ng-container&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Our application shell and toolbar are now ready to receive feature module extensions!&lt;/p&gt;

&lt;p&gt;Let's move on to a feature module that we call the "Planning" module. This module consists of two things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a classic feature shell module that loads components depending on the route: &lt;code&gt;PlanningShellModule&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;a lightweight extension module: &lt;code&gt;PlanningExtensionModule&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The &lt;code&gt;PlanningShellModule&lt;/code&gt; has nothing particular and is loaded by the router (optionnaly lazily). The &lt;code&gt;PlanningExtensionModule&lt;/code&gt; is declared as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;CommonModule&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@angular/common&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;NgModule&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@angular/core&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;rxjs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Extension&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;FEATURE_EXTENSION&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ToolbarItemModule&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;path/to/some/shared/folder&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;PlanningToolbarItemComponent&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./planning-toolbar-item.component&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;NgModule&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;imports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;CommonModule&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ToolbarItemModule&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;providers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;provide&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;FEATURE_EXTENSION&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;useValue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;toolbarItem&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;PlanningToolbarItemComponent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;route&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;planning&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;Extension&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;multi&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PlanningExtensionModule&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The most important piece is in within the &lt;code&gt;providers&lt;/code&gt; property where we provide a &lt;code&gt;FEATURE_EXTENSION&lt;/code&gt; value with our toolbar item component &lt;code&gt;PlanningToolbarItemComponent&lt;/code&gt; to load and the route to navigate to when clicked. Note the use of &lt;code&gt;multi: true&lt;/code&gt; that makes sure we can declare several times this provider from other feature modules!&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;PlanningToolbarItemComponent&lt;/code&gt; can make use of all the components, directives and pipes that are declared in the &lt;code&gt;ToolbarItemModule&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;You can now display custom content in the toolbar of the application shell from a feature extension module.&lt;/p&gt;

&lt;p&gt;Feel free to check this repository &lt;a href="https://github.com/kevinmerckx/ng-feature-extension" rel="noopener noreferrer"&gt;https://github.com/kevinmerckx/ng-feature-extension&lt;/a&gt; for the full code of this fully functioning proof of concept. Here is a screenshot:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx9rnkjlwe0d9wfghvrs9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx9rnkjlwe0d9wfghvrs9.png" alt="An Angular technique that might surprise you" width="544" height="406"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;At the top the toolbar, with 3 items. Plan and Code both use a customized toolbar item, provided by their respective extension module.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;To summarize, by combining &lt;code&gt;InjectionToken&lt;/code&gt; with &lt;code&gt;multi: true&lt;/code&gt;, &lt;code&gt;ngComponentOutlet&lt;/code&gt; and by splitting feature modules into a shell and an extension modules, we managed to provide a nice way for feature modules to customize the application shell through a nice API defined by an &lt;code&gt;Extension&lt;/code&gt; interface.&lt;/p&gt;




&lt;p&gt;KM&lt;/p&gt;

&lt;p&gt;Photo by &lt;a href="https://unsplash.com/@lanceanderson?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Lance Anderson&lt;/a&gt; on &lt;a href="https://unsplash.com/s/photos/architecture?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Unsplash&lt;/a&gt;&lt;/p&gt;

</description>
      <category>angular</category>
      <category>architecture</category>
    </item>
    <item>
      <title>How to protect endpoints of a Nestjs application</title>
      <dc:creator>Kevin Merckx</dc:creator>
      <pubDate>Thu, 30 Dec 2021 00:04:05 +0000</pubDate>
      <link>https://dev.to/kevinmerckx_47/how-to-protect-endpoints-of-a-nestjs-application-5d5b</link>
      <guid>https://dev.to/kevinmerckx_47/how-to-protect-endpoints-of-a-nestjs-application-5d5b</guid>
      <description>&lt;p&gt;Security is a major concern when writing a web service. Nestjs provides awesome features that enables developers to structure code in a very declarative way. For instance, one can protect applications against unauthorized access by using Guards. Guards are injectable blocks that can be added to protect a specific route, an entire controller or an entire application. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;By default, I prefer to restrict all routes and refine the route that requires special handling.&lt;/strong&gt; This is why I apply guards at the top-most level possible. Let's imagine for a moment that your service is protected by an authentication layer, let's say cookie based. Putting the whole API behind an authentication guard is the easiest way to secure it against unauthorized access. You can do that in Nestjs with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;NestFactory&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Reflector&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@nestjs/core&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;AppModule&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./app.module&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;AuthGuard&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./guards/auth-guard&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;bootstrap&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;NestFactory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;AppModule&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// here we guard the whole application with one Guard&lt;/span&gt;
  &lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;useGlobalGuards&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;AuthGuard&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nf"&gt;bootstrap&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Any access to the routes provided by the application is going through this guard, enabling you to protect them. Here is the example of a very dummy guard, where nobody can access anything, as we return false every time:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;CanActivate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ExecutionContext&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Injectable&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@nestjs/common&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Observable&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;rxjs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;


&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Injectable&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AuthGuard&lt;/span&gt; &lt;span class="k"&gt;implements&lt;/span&gt; &lt;span class="nx"&gt;CanActivate&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;canActivate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ExecutionContext&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;Observable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;However, there are several use cases where you need to disable the guard from checking for authorization. For instance, if you have a &lt;code&gt;/login&lt;/code&gt; endpoint. In that case, you need to specifically tell the guard to not do anything for this route. You preferably should do it the Nestjs way. Here is one.&lt;/p&gt;

&lt;p&gt;Guards can access the execution context. The execution context contains information about the request and can be used to create guards, filters and interceptors. Nestjs provides a decorator &lt;code&gt;SetMetadata&lt;/code&gt; that you can add to endpoints to add metadata to the execution context. Therefore, if we add information on a specific route or controller, we can retrieve it from the guard.&lt;/p&gt;

&lt;p&gt;Let's consider the following controller:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Controller&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;SetMetadata&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@nestjs/common&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;AuthGuardConfig&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;AUTH_GUARD_CONFIG&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./guards/auth-guard&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Controller&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AppController&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;guarded&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nf"&gt;guarded&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;This is open.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;open&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;SetMetadata&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;AUTH_GUARD_CONFIG&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;disabled&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;AuthGuardConfig&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;This is open.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The first endpoint &lt;code&gt;/guarded&lt;/code&gt; is guarded by the guard by default. The second one is not, as specified by the &lt;code&gt;@SetMetadata(AUTH_GUARD_CONFIG, { disabled: true })&lt;/code&gt;.&lt;br&gt;
Here is the code of the guard:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;CanActivate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ExecutionContext&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Injectable&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@nestjs/common&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Reflector&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@nestjs/core&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Observable&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;rxjs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;AuthGuardConfig&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;disabled&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;AUTH_GUARD_CONFIG&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Symbol&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;AUTH_GUARD_CONFIG&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Injectable&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AuthGuard&lt;/span&gt; &lt;span class="k"&gt;implements&lt;/span&gt; &lt;span class="nx"&gt;CanActivate&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;reflector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Reflector&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

  &lt;span class="nf"&gt;canActivate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ExecutionContext&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;Observable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handlerConfig&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;reflector&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;AuthGuardConfig&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nx"&gt;AUTH_GUARD_CONFIG&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getHandler&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;controllerConfig&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;reflector&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;AuthGuardConfig&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nx"&gt;AUTH_GUARD_CONFIG&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getClass&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;controllerConfig&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;disabled&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;handlerConfig&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;disabled&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The guard uses the reflector to get ahold of the metadata symbol &lt;code&gt;AUTH_GUARD_CONFIG&lt;/code&gt;. It does it at the controller level with &lt;code&gt;context.getClass()&lt;/code&gt; and at the method handler level &lt;code&gt;context.getHandler()&lt;/code&gt; If a route specifies this metadata and puts the &lt;code&gt;disabled&lt;/code&gt; parameter to &lt;code&gt;true&lt;/code&gt;, the guard will read it and return true and therefore authorize the access. If a controller does it, all the routes of this controller will be authorized.&lt;br&gt;
The last remaining piece to adjust is that your guard, when declared globally for your app, needs to access the reflector. This is how you can achieve it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;NestFactory&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Reflector&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@nestjs/core&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;AppModule&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./app.module&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;AuthGuard&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./guards/auth-guard&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;bootstrap&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;NestFactory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;AppModule&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;useGlobalGuards&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;AuthGuard&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Reflector&lt;/span&gt;&lt;span class="p"&gt;)));&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nf"&gt;bootstrap&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here is the link to a Github repository for easier reference and hope it helps: &lt;a href="https://github.com/kevinmerckx/app-guard-nestjs" rel="noopener noreferrer"&gt;https://github.com/kevinmerckx/app-guard-nestjs&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;KM&lt;br&gt;
Photo by Rowan Heuvel on Unsplash&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>auth</category>
      <category>typescript</category>
    </item>
    <item>
      <title>Integration Testing Setup with Nestjs and MongoDB</title>
      <dc:creator>Kevin Merckx</dc:creator>
      <pubDate>Tue, 31 Aug 2021 14:01:01 +0000</pubDate>
      <link>https://dev.to/kevinmerckx_47/integration-testing-setup-with-nestjs-and-mongodb-43mp</link>
      <guid>https://dev.to/kevinmerckx_47/integration-testing-setup-with-nestjs-and-mongodb-43mp</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimages.unsplash.com%2Fphoto-1575470522418-b88b692b8084%3Fcrop%3Dentropy%26cs%3Dtinysrgb%26fit%3Dmax%26fm%3Djpg%26ixid%3DMnwxMTc3M3wwfDF8c2VhcmNofDN8fGJsb2Nrc3xlbnwwfHx8fDE2MzA0MTgyMTE%26ixlib%3Drb-1.2.1%26q%3D80%26w%3D2000" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimages.unsplash.com%2Fphoto-1575470522418-b88b692b8084%3Fcrop%3Dentropy%26cs%3Dtinysrgb%26fit%3Dmax%26fm%3Djpg%26ixid%3DMnwxMTc3M3wwfDF8c2VhcmNofDN8fGJsb2Nrc3xlbnwwfHx8fDE2MzA0MTgyMTE%26ixlib%3Drb-1.2.1%26q%3D80%26w%3D2000" alt="Integration Testing Setup with Nestjs and MongoDB" width="800" height="522"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Originall posted on my blog: &lt;a href="https://blog.merckx.fr/integration-testing-setup-with-nestjs-and-mongodb/" rel="noopener noreferrer"&gt;https://blog.merckx.fr/integration-testing-setup-with-nestjs-and-mongodb/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Automated testing provides tremendous value when creating software. It enables you to follow a Test Driven Development approach: you can write your tests and design the API and its requirements upfront, then write the code to make the tests pass.&lt;/p&gt;

&lt;p&gt;Very often comes the usual questions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;do I create unit tests, integration tests or E2E tests?&lt;/li&gt;
&lt;li&gt;what should be mocked?&lt;/li&gt;
&lt;li&gt;what am I testing?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;While many debates still go on, there are pretty clear rules of thumbs one should follow:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;E2E tests provide a very good answer to the question &lt;strong&gt;Can we release?&lt;/strong&gt; but a very poor one to &lt;strong&gt;Why do the tests fail?&lt;/strong&gt;. They are expensive to write.&lt;/li&gt;
&lt;li&gt;Unit tests do the exact opposite. They are very good to locate the origin of the failure but are bad to know if you can actually release if they all pass. They are effortless to write.&lt;/li&gt;
&lt;li&gt;Integration tests provide a good balance between the two. They are testing the integration points of the components and you can assume that, from one release to the other, if the interfaces between your components didn't change and your integration tests pass, the release can be deployed. They are cheap to write. Not as cheap as unit tests, but far cheaper than E2E tests.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is why I recommend to focus on integration tests. When writing integration tests, you should always keep in mind that they should be easy to write. Mocking functionnality requires writing code and therefore should be avoided. You should aim at integrating as much as you can from the code that will actually run into your tests.&lt;/p&gt;

&lt;p&gt;I use Nestjs in 90% of the projects I work on. In 90% of those projects, I use MongoDB as a database. Writing integration tests for a module should be as easy as writing unit tests without having to mock all the functionnalities around the tested module. Therefore, we must find a way to integrate a real Mongo database when running our integration tests. This is what is going to be presented in the next lines.&lt;/p&gt;

&lt;h2&gt;
  
  
  Do yourself a favor and create a friendly developer environment
&lt;/h2&gt;

&lt;p&gt;We are going to use Docker to set our development environment up. You might not be friend with Docker but you better become. Docker is a friend that will enable the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;once set up, you can work offline. You don't need to host development databases in the cloud.&lt;/li&gt;
&lt;li&gt;you work with containers that you can later on use in production&lt;/li&gt;
&lt;li&gt;you can create many workflows that suit your needs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So go ahead and install Docker on your machine. You need five minutes to do that &lt;a href="https://docs.docker.com/get-docker/" rel="noopener noreferrer"&gt;https://docs.docker.com/get-docker/&lt;/a&gt; and then you can come back.&lt;/p&gt;

&lt;h2&gt;
  
  
  Containerize your application
&lt;/h2&gt;

&lt;p&gt;At this point, you have Docker running on your machine and a Nestjs project that uses Mongo as a database. We are going to use &lt;a href="https://docs.docker.com/compose/" rel="noopener noreferrer"&gt;Docker Compose&lt;/a&gt; to create several containers that run different services. The following &lt;code&gt;docker-compose.yml&lt;/code&gt; file describes an environment with two services: &lt;code&gt;api&lt;/code&gt; and &lt;code&gt;mongo&lt;/code&gt;. &lt;code&gt;mongo&lt;/code&gt; creates a container that runs a MongoDB server and &lt;code&gt;api&lt;/code&gt; is a container that runs NodeJS 14 that exposes ports &lt;code&gt;3333&lt;/code&gt; and &lt;code&gt;9229&lt;/code&gt;. That way, you can reach your Nest application and the debugger.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;3.9"&lt;/span&gt;
&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;api&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;node:14&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;.:/app&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;3333:3333&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;9229:9229&lt;/span&gt;
    &lt;span class="na"&gt;depends_on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;mongo&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;NODE_ENV&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;development&lt;/span&gt;
  &lt;span class="na"&gt;mongo&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mongo:4.4.8&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./.docker/mongodb/data/db/:/data/db/&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./.docker/mongodb/data/log/:/var/log/mongodb/&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You are almost fully set up. Let's describe a few useful workflows.&lt;/p&gt;

&lt;h2&gt;
  
  
  Start the things you need
&lt;/h2&gt;

&lt;p&gt;We have configured containers. It's time to start and test our NestJS application. Save the following command (as a script in your &lt;code&gt;package.json&lt;/code&gt; or as a shell script in your repository:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker-compose run &lt;span class="nt"&gt;--service-ports&lt;/span&gt; &lt;span class="nt"&gt;-w&lt;/span&gt; /app api bash
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will start the services &lt;code&gt;api&lt;/code&gt; and &lt;code&gt;mongo&lt;/code&gt; and start a bash shell. In this shell, you can use NPM and Node the same way you would do it without Docker! Try your usual commands &lt;code&gt;npm install&lt;/code&gt; and &lt;code&gt;npm start&lt;/code&gt; and &lt;code&gt;npm test&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;I usually save this command in my &lt;code&gt;package.json&lt;/code&gt; under the &lt;code&gt;start:env&lt;/code&gt; script:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"scripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"start:env"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"docker-compose run -w /app api bash"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Run the tests once
&lt;/h2&gt;

&lt;p&gt;If you want to run tests in your CI, use the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker-compose run &lt;span class="nt"&gt;-w&lt;/span&gt; /app api npm run &lt;span class="nb"&gt;test&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;where the &lt;code&gt;test&lt;/code&gt; script is for instance:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; jest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Write integration tests
&lt;/h2&gt;

&lt;p&gt;Imagine you have a NestJS application with a &lt;code&gt;PostModule&lt;/code&gt; that has a controller &lt;code&gt;PostController&lt;/code&gt; that has two API endpoints:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;GET /post&lt;/code&gt;: returns all the posts stored in the database&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;POST /post&lt;/code&gt;: creates a new post and stores it in the database&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This module also has a service &lt;code&gt;PostService&lt;/code&gt; that &lt;code&gt;PostController&lt;/code&gt; instantiates and uses. The service accesses the database. To test your module, one can create tests for the &lt;code&gt;PostService&lt;/code&gt; and the &lt;code&gt;PostController&lt;/code&gt;. The controller doesn't directly access the database and needs the service to do that. When writing tests for the controller, you have the following choices:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;you can mock the service completely&lt;/li&gt;
&lt;li&gt;you can mock the database access&lt;/li&gt;
&lt;li&gt;you can use the real implementation of the whole module, therefore test the integration of its components: the controller, the service, the database access&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;We are going for the solution 3. For each integration test, we are going to create a completely new database and delete it when we are finished. Have a look at the following spec file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;getConnectionToken&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;MongooseModule&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@nestjs/mongoose&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;NestExpressApplication&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@nestjs/platform-express&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Test&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@nestjs/testing&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Connection&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;mongoose&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;supertest&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;supertest&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;IPost&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../model/post&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;PostModule&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../post.module&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;PostController&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;NestExpressApplication&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;apiClient&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;supertest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getHttpServer&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="nf"&gt;beforeEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;moduleRef&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;Test&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createTestingModule&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;imports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="nx"&gt;MongooseModule&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forRoot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;mongodb://mongo:27017&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;dbName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;test&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}),&lt;/span&gt; &lt;span class="c1"&gt;// we use Mongoose here, but you can also use TypeORM&lt;/span&gt;
        &lt;span class="nx"&gt;PostModule&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;compile&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;moduleRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;createNestApplication&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;NestExpressApplication&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3333&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nf"&gt;afterEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;await &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;getConnectionToken&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;Connection&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dropDatabase&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;close&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;creates a post&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;apiClient&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/post&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
          &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;I am all setup with Nestjs and Mongo for more integration testing. TDD rocks!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;})&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;201&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="na"&gt;posts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;IPost&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;apiClient&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/post&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;posts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;I am all setup with Nestjs and Mongo for more integration testing. TDD rocks!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;posts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;likes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A few notes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;we do not mock anything&lt;/li&gt;
&lt;li&gt;we test the whole &lt;code&gt;PostModule&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;beforeEach&lt;/code&gt; and &lt;code&gt;afterEach&lt;/code&gt; are our hooks to create and delete databases. We specify to Mongoose which database name to use and we drop the database with &lt;code&gt;(app.get(getConnectionToken()) as Connection).db.dropDatabase()&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;we use &lt;code&gt;supertest&lt;/code&gt; to create a consumer for our API&lt;/li&gt;
&lt;li&gt;we only add our module &lt;code&gt;PostModule&lt;/code&gt; to the app&lt;/li&gt;
&lt;li&gt;if you would to start the whole application, you would be very close to an actual End-to-end test&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I believe that you are set up right now. You have at your disposal an environment where you can write as many integration tests as you can. You can now adopt a TDD approach and deploy a fully tested API.&lt;/p&gt;

&lt;p&gt;Note: you can find an example of the setup we described at &lt;a href="https://github.com/kevinmerckx/nesjts-with-mongo" rel="noopener noreferrer"&gt;https://github.com/kevinmerckx/nesjts-with-mongo&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;KM&lt;/p&gt;

&lt;p&gt;Photo by &lt;a href="https://unsplash.com/@glencarrie?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Glen Carrie&lt;/a&gt; on &lt;a href="https://unsplash.com/s/photos/blocks?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Unsplash&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Resources
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/kevinmerckx/nesjts-with-mongo" rel="noopener noreferrer"&gt;An example to setup your repository&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.agilealliance.org/glossary/tdd/#q=~(infinite~false~filters~(postType~(~'page~'post~'aa_book~'aa_event_session~'aa_experience_report~'aa_glossary~'aa_research_paper~'aa_video)~tags~(~'tdd))~searchTerm~'~sort~false~sortDirection~'asc~page~1)" rel="noopener noreferrer"&gt;TDD&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.testim.io/blog/end-to-end-testing-vs-integration-testing/" rel="noopener noreferrer"&gt;End-to-End Testing vs Integration Testing&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://microsoft.github.io/code-with-engineering-playbook/automated-testing/e2e-testing/testing-comparison/" rel="noopener noreferrer"&gt;Unit vs Integration vs System vs E2E Testing&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://codeahoy.com/2016/07/05/unit-integration-and-end-to-end-tests-finding-the-right-balance/" rel="noopener noreferrer"&gt;Unit, Integration and End-To-End Tests - Finding the Right Balance&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.atlassian.com/continuous-delivery/software-testing/types-of-software-testing" rel="noopener noreferrer"&gt;The different types of software testing&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>devrel</category>
      <category>nestjs</category>
    </item>
    <item>
      <title>Impersonation with Nestjs</title>
      <dc:creator>Kevin Merckx</dc:creator>
      <pubDate>Wed, 07 Jul 2021 20:29:41 +0000</pubDate>
      <link>https://dev.to/kevinmerckx_47/impersonation-with-nestjs-8n6</link>
      <guid>https://dev.to/kevinmerckx_47/impersonation-with-nestjs-8n6</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimages.unsplash.com%2Fphoto-1554497342-902a4f8da8ed%3Fcrop%3Dentropy%26cs%3Dtinysrgb%26fit%3Dmax%26fm%3Djpg%26ixid%3DMnwxMTc3M3wwfDF8c2VhcmNofDF8fHdob3xlbnwwfHx8fDE2MjU2ODk2NTU%26ixlib%3Drb-1.2.1%26q%3D80%26w%3D2000" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimages.unsplash.com%2Fphoto-1554497342-902a4f8da8ed%3Fcrop%3Dentropy%26cs%3Dtinysrgb%26fit%3Dmax%26fm%3Djpg%26ixid%3DMnwxMTc3M3wwfDF8c2VhcmNofDF8fHdob3xlbnwwfHx8fDE2MjU2ODk2NTU%26ixlib%3Drb-1.2.1%26q%3D80%26w%3D2000" alt="Impersonation with Nestjs" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Originally posted on my blog: &lt;a href="https://blog.merckx.fr/impersonation-with-nestjs/" rel="noopener noreferrer"&gt;https://blog.merckx.fr/impersonation-with-nestjs/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Impersonation is the ability of users to act as other users. Usually it consists in administrators of a system having the ability to interact as standard users on the same system. Gitlab, for instance, provides this feature. It is also part of the feature to provide a way to revert the impersonation.&lt;/p&gt;

&lt;p&gt;In this post, we present one approach to implement this feature and we illustrate principles with code from Nestjs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Assumptions
&lt;/h2&gt;

&lt;p&gt;We assume you already have some sort of user session implementation: a cookie that either directly contains information (client-side cookie, signed with a secret) about the current user or an identifier that links to such information in a store.&lt;/p&gt;

&lt;p&gt;We also assume that a REST API that filters in data that belong to the user.&lt;/p&gt;

&lt;p&gt;With Nestjs, we will assume that the request object contains a property called &lt;code&gt;user&lt;/code&gt; that contains the current information about the user. We will also assume that this property is filled in by a guard, based on the session. We will also assume that the session is implement with a client-side cookie that contains the current user identifier. We will also assume that TypeOrm is used to provide CRUD endpoints and that resources are filtered by user.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;CustomRequest&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;express&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Request&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;CustomSession&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Crud&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;...,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;CrudAuth&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;property&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;user&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Controller&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;entity&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyEntityController&lt;/span&gt; &lt;span class="k"&gt;implements&lt;/span&gt; &lt;span class="nx"&gt;CrudController&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="err"&gt;…&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The last assumption is that the Nestjs application has a guard that checks whether the user is authenticated and that adds a &lt;code&gt;user&lt;/code&gt; property to the request object.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Injectable&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;IsAuthenticatedGuard&lt;/span&gt; &lt;span class="k"&gt;implements&lt;/span&gt; &lt;span class="nx"&gt;CanActivate&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;InjectRepository&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;users&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Repository&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;canActivate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ExecutionContext&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;switchToHttp&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;getRequest&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;session&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;session&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;CustomSession&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;users&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findOne&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;where&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="p"&gt;}});&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Principles
&lt;/h2&gt;

&lt;p&gt;We are going to change as less code as possible but still make pretty explicit what happens. The main idea is to store two pieces of information in the user session:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the actual logged in user&lt;/li&gt;
&lt;li&gt;the impersonated user&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Therefore, we change the session structure to the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;CustomSession&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;loggedInUser&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nl"&gt;impersonatedUser&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We must know provide two API endpoints that enable the user to impersonate and to stop the impersonation.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The impersonation endpoints&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;impersonate&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nf"&gt;removeImpersonation&lt;/span&gt;&lt;span class="p"&gt;(@&lt;/span&gt;&lt;span class="nd"&gt;Session&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;CustomSession&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;impersonatedUser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;loggedInUser&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;users/:id/impersonate&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;impersonate&lt;/span&gt;&lt;span class="p"&gt;(@&lt;/span&gt;&lt;span class="nd"&gt;Param&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Session&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;CustomSession&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;users&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findOne&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;where&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="p"&gt;}});&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;NotFoundException&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;impersonatedUser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, when logging in, we must fill in the two properties &lt;code&gt;session.impersonatedUser&lt;/code&gt; and &lt;code&gt;session.loggedInUser&lt;/code&gt;. Here is an example:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The modified login route&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/login&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;login&lt;/span&gt;&lt;span class="p"&gt;(@&lt;/span&gt;&lt;span class="nd"&gt;Session&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;CustomSession&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Body&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;username&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;username&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Body&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;password&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;impersonatedUser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;loggedInUser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;authService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;validateUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;username&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;UnauthorizedException&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;impersonatedUser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;loggedInUser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;serializeUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;loggedInUser&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Our authentication guard must fill in the &lt;code&gt;request.user&lt;/code&gt; with the impersonated user.  Here is an example:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The modified authentication guard&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  async canActivate(
    context: ExecutionContext,
  ): Promise&amp;lt;boolean&amp;gt; {
    const request = context.switchToHttp().getRequest();
    const session = request.session as CustomSession;
    if (!session.impersonatedUser) {
      return false;
    }
    request.user = await this.users.findOne({ where: { id: session.impersonatedUser.id }});
    return true;
  }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Our authentication fills in the session with the logged in user and the impersonated user information. Our guard fills in the user property with the impersonated user from the user session. Our CRUD controllers can now filter data by user.&lt;/p&gt;

&lt;p&gt;Let's walk through the mechanism.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The user logs in. A &lt;code&gt;POST&lt;/code&gt; request is sent to the &lt;code&gt;login&lt;/code&gt; endpoint. The session is filled in with &lt;code&gt;impersonatedUser&lt;/code&gt; and &lt;code&gt;loggedInUser&lt;/code&gt; properties.&lt;/li&gt;
&lt;li&gt;The user starts impersonating by reaching the &lt;code&gt;/admin/users/1234/impersonate&lt;/code&gt; endpoint. Once reached, the session is modified: the &lt;code&gt;impersonatedUserId&lt;/code&gt; is filled in with information about user &lt;code&gt;1234&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The user reaches a CRUD endpoint, let's say &lt;code&gt;/entity&lt;/code&gt;. The authentication guard gets the &lt;code&gt;impersonatedUserId&lt;/code&gt;property from the session and adds a &lt;code&gt;user&lt;/code&gt; property to the request object based on it.&lt;/li&gt;
&lt;li&gt;TypeOrm filters the &lt;code&gt;entity&lt;/code&gt; by the information stored in the &lt;code&gt;user&lt;/code&gt;property of the request object.&lt;/li&gt;
&lt;li&gt;The user stops the impersonation by reaching &lt;code&gt;/admin/impersonate&lt;/code&gt; endpoint. The session is modified: the &lt;code&gt;impersonatedUserId&lt;/code&gt; is filled in with the &lt;code&gt;loggedInUserId&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Do not forget to protect the impersonation endpoint!&lt;/p&gt;

&lt;p&gt;That's it! With this approach, we make minimal changes to the code base and we enable a great feature: Impersonation.&lt;/p&gt;




&lt;p&gt;KM&lt;/p&gt;

&lt;p&gt;Photo by &lt;a href="https://unsplash.com/@iamfelicia?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Felicia Buitenwerf&lt;/a&gt; on &lt;a href="https://unsplash.com/s/photos/who?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Unsplash&lt;/a&gt;&lt;/p&gt;

</description>
      <category>nestjs</category>
    </item>
    <item>
      <title>Avoid global styles in your Angular projects</title>
      <dc:creator>Kevin Merckx</dc:creator>
      <pubDate>Thu, 27 May 2021 16:09:56 +0000</pubDate>
      <link>https://dev.to/kevinmerckx_47/avoid-global-styles-in-your-angular-projects-2fal</link>
      <guid>https://dev.to/kevinmerckx_47/avoid-global-styles-in-your-angular-projects-2fal</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimages.unsplash.com%2Fphoto-1466784828399-9a9921e8bdfd%3Fcrop%3Dentropy%26cs%3Dtinysrgb%26fit%3Dmax%26fm%3Djpg%26ixid%3DMnwxMTc3M3wwfDF8c2VhcmNofDF8fG1lc3N8ZW58MHx8fHwxNjIyMTMxNzMw%26ixlib%3Drb-1.2.1%26q%3D80%26w%3D2000" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimages.unsplash.com%2Fphoto-1466784828399-9a9921e8bdfd%3Fcrop%3Dentropy%26cs%3Dtinysrgb%26fit%3Dmax%26fm%3Djpg%26ixid%3DMnwxMTc3M3wwfDF8c2VhcmNofDF8fG1lc3N8ZW58MHx8fHwxNjIyMTMxNzMw%26ixlib%3Drb-1.2.1%26q%3D80%26w%3D2000" alt="Avoid global styles in your Angular projects" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Originally posted on my blog: &lt;a href="https://blog.merckx.fr/avoid-using-global-styles-in-your-angular-projects/" rel="noopener noreferrer"&gt;https://blog.merckx.fr/avoid-using-global-styles-in-your-angular-projects/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;CSS is the language used to style HTML pages. It has a simple set of rules to compute values of properties of every DOM element on a page. Angular provides view encapsulation to make sure component's styles only apply to the given component. However, the style of the DOM elements generated by those components are still affected by global styles. This makes debugging CSS hard.&lt;/p&gt;

&lt;p&gt;In every project I worked on, custom CSS code is always at least 10% of total amount of code (in number of lines of code). And we always tend to underestimate the effort needed to maintain it. I never actually measured the time spent working on CSS files but I wouldn't be surprised if it would be around 10% of my time as well. CSS deserves a better place in our all web projects.&lt;/p&gt;

&lt;p&gt;In a &lt;a href="https://medium.com/@benlorantfy/avoid-global-styles-3992a759f616" rel="noopener noreferrer"&gt;good article&lt;/a&gt;, &lt;a href="https://medium.com/@benlorantfy" rel="noopener noreferrer"&gt;Ben Lorantfy&lt;/a&gt; compared global styles in CSS with global variables in JS. To summarize, they both share the following issues:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;break encapsulation&lt;/li&gt;
&lt;li&gt;poor readability&lt;/li&gt;
&lt;li&gt;break information hiding&lt;/li&gt;
&lt;li&gt;namespace pollution&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Unfortunately, it is very rare to use a UI library that doesn't come with global styles. Bootstrap, Material Design, Prime NG and NG Zorro all come with global styles. However, it doesn't mean that you should add more mess to the mess.&lt;/p&gt;

&lt;p&gt;Global styles and especially classes are handy because they enable developers to apply styles to elements by labelling (hopefully, those labels are semantically meaningful but that's another debate). That is something we want to keep in a new approach. The attribute we want to get rid of is that &lt;strong&gt;global styles are globally applied&lt;/strong&gt;. Instead, we want &lt;strong&gt;global styles that are locally applied&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;In this post, I'm going to present an approach based on SASS mixins. I quote &lt;a href="https://sass-lang.com/documentation/at-rules/mixin" rel="noopener noreferrer"&gt;the SASS language's website&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Mixins allow you to define styles that can be re-used throughout your stylesheet.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  File structure
&lt;/h2&gt;

&lt;p&gt;The first thing to this approach is to organize your SASS code the same way you would organize your JS/HTML code. Don't neglect it. I put all the global styles under a folder called &lt;code&gt;styles&lt;/code&gt;. I suggest putting all the mixins in under the &lt;code&gt;styles/mixins&lt;/code&gt;. Modularize mixins in meaningful packages: containers, lists, tables, inputs, buttons, typography etc. At this point, I would suggest something that would look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;styles/
|__ mixins/
    |__ typography.sass
    |__ containers.sass
    |__ quote.sass
    |__ tables/
        |__ compact-table.sass
        |__ data-table.sass

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Mixins in actions
&lt;/h2&gt;

&lt;p&gt;Let's have a look at the &lt;code&gt;quote&lt;/code&gt; mixin. This mixin can add some quote-like style to an element: a grey background, some padding, some font style and color.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;quote.sass&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sass"&gt;&lt;code&gt;&lt;span class="k"&gt;@mixin&lt;/span&gt; &lt;span class="nf"&gt;quote&lt;/span&gt;
  &lt;span class="nl"&gt;font-style&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;italic&lt;/span&gt;
  &lt;span class="nl"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;rgb&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;240&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="m"&gt;240&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="m"&gt;240&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nl"&gt;border-left&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2px&lt;/span&gt; &lt;span class="nb"&gt;solid&lt;/span&gt; &lt;span class="nf"&gt;rgb&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;200&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="m"&gt;200&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="m"&gt;200&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;rgb&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;100&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="m"&gt;100&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="m"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;10px&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here is how we can use our mixin.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;app.component.html&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;p&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"main-quote"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Lorem ipsum dolor sit amet, consectetur adipisicing elit.&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;p&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"second-quote"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Molestiae tempore officiis animi sint, corporis officia, vel eaque in, quaerat exercitationem ut.&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;app.component.sass&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sass"&gt;&lt;code&gt;&lt;span class="k"&gt;@use&lt;/span&gt; &lt;span class="s1"&gt;'mixins/quote'&lt;/span&gt;

&lt;span class="nc"&gt;.main-quote&lt;/span&gt;
  &lt;span class="k"&gt;@include&lt;/span&gt; &lt;span class="nd"&gt;quote&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;quote&lt;/span&gt;
  &lt;span class="nl"&gt;font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;20px&lt;/span&gt;

&lt;span class="nc"&gt;.second-quote&lt;/span&gt;
  &lt;span class="k"&gt;@include&lt;/span&gt; &lt;span class="nd"&gt;quote&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;quote&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At this point, there are several things to note.&lt;/p&gt;

&lt;h2&gt;
  
  
  Styles stay local
&lt;/h2&gt;

&lt;p&gt;We don't have any style applied globally. We apply global mixins (available to the SASS pre-processor) to local styles.&lt;/p&gt;

&lt;h2&gt;
  
  
  It keeps the template clean
&lt;/h2&gt;

&lt;p&gt;We assign one class to each &lt;code&gt;&amp;lt;p&amp;gt;&lt;/code&gt;, the classes are then defined in the SASS file of the component. We can then apply several mixins to each class.&lt;/p&gt;

&lt;p&gt;While assigning one class to each &lt;code&gt;&amp;lt;p&amp;gt;&lt;/code&gt; seems to be a tedious process, it actually makes sure our template stays clean: we don't overload class attributes. Style definitions are specified in the SASS file.&lt;/p&gt;

&lt;h2&gt;
  
  
  "Class check" for free
&lt;/h2&gt;

&lt;p&gt;The SASS pre-processor will complain if a mixin doesn't exist, while CSS won't complain if you have a typo in a class.&lt;/p&gt;

&lt;p&gt;I will try this approach along with the one described in &lt;a href="https://dev.to/kevinmerckx_47/an-elegant-way-to-enable-css-customizable-angular-components-m48"&gt;An elegant way to enable CSS-customizable Angular components&lt;/a&gt; in the next big project I have to lead. I'm curious about the results. The intermediate results on a small project were already promising.&lt;/p&gt;




&lt;p&gt;KM&lt;/p&gt;

&lt;p&gt;Photo by &lt;a href="https://unsplash.com/@ricardoviana?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Ricardo Viana&lt;/a&gt; on &lt;a href="https://unsplash.com/s/visual/603b0e9c-d0d6-4d15-b61e-c5f35b1edcd4?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Unsplash&lt;/a&gt;&lt;/p&gt;

</description>
      <category>angular</category>
    </item>
  </channel>
</rss>
