#nestjs controller routing
Explore tagged Tumblr posts
Video
youtube
Nestjs Controller Tutorial with Example for JavaScript Developers | #nes... Full Video Link - https://youtu.be/Ui4PXXbY1P8 Check out this new video on the CodeOneDigest YouTube channel! Learn nestjs controller with example. Learn how to create controller route, access request object, status code etc. #video #nestjs #controller #nodejs #javascript #codeonedigest@java @awscloud @AWSCloudIndia @YouTube @codeonedigest #typescript #javascript #nestjs #javascript #node #nestjs #nestjstutorial #javascript #nestjsmicroservices #nestjscontroller #nestjscontrollertest #nestjscontroller #nestjscreatecontroller #nestjsfulltutorial #nestjsfullcourse #nestjsproject #nestjsrouting #nestjstipsandtricks #nestjsroutingincontroller #nestjsprojecttutorial #nestjsprojectfromscratch #nestjsexampleproject #nestjstesting #nestjsprojectsetup #nestjscontrollertest #nestjscontrollerproject #nestjscontrollerrouting
#youtube#nestjs#nestjs controller#nestjs routing#nestjs controller routing#nestjs route#nestjs controller explained#nestjs tutorial
0 notes
Text
When to Choose NestJS Over Express.js for Your Node.js Backend

As the demand for web applications continues to grow, developers are always on the lookout for efficient, scalable, and maintainable frameworks for building backend systems. In the world of Node.js, two of the most popular frameworks are NestJS and Express.js. The decision of which framework to use often comes down to the project’s requirements, the complexity of the application, and the development team’s familiarity with the tools. In this blog, we will explore the differences between NestJS vs. Express.js and provide insights on when to choose NestJS over Express.js for your Node.js backend.
Understanding NestJS and Express.js
Before diving into when to use NestJS over Express.js, it’s important to first understand the two frameworks. Both are designed to simplify backend development using Node.js, but they take different approaches.
Express.js
Express.js is a minimalistic and flexible web application framework for Node.js. It provides a simple set of features for web and mobile applications, including routing, middleware support, and templates. Express is often favored for its simplicity and low overhead, making it an ideal choice for building small to medium-sized applications where flexibility and speed are key.
However, as applications grow in complexity, managing routes, controllers, and handling business logic in Express can become cumbersome. Express lacks a clear structure, which can lead to difficulties in scaling and maintaining larger applications.
NestJS
NestJS, on the other hand, is a framework built on top of Express (or Fastify) that leverages TypeScript and incorporates an architecture inspired by Angular. It follows a modular architecture pattern, providing out-of-the-box tools for building scalable, maintainable, and testable applications. NestJS uses decorators, dependency injection, and other features that encourage clean code practices and help organize application components more effectively.
While NestJS has a steeper learning curve compared to Express due to its opinionated structure and reliance on TypeScript, it is an excellent choice for large-scale, enterprise-level applications.
When to Choose NestJS Over Express.js?
1. For Large-Scale Applications
If you’re building a large, complex application that will grow over time, NestJS is the better choice. Its modular structure helps organize code into separate components such as modules, controllers, and services, which makes the application easier to maintain as it scales.
In contrast, Express’s minimalistic nature can become a disadvantage as your application grows in size. As your codebase increases, you may find yourself needing to implement custom solutions for things like validation, authentication, and error handling that are built-in with NestJS.
2. When TypeScript Is a Requirement
NestJS is built with TypeScript by default, providing a strong typing system that improves code reliability and maintainability. TypeScript’s ability to catch errors early in the development process leads to better quality code and fewer bugs, making it ideal for large-scale applications or projects with multiple developers.
While Express can be used with TypeScript, it doesn’t offer the same level of native TypeScript support that NestJS provides. If you’re working on a project where TypeScript is a requirement or if you want to take advantage of TypeScript’s features like static typing and interfaces, NestJS is a clear winner.
3. When You Need Built-in Tools for Common Features
NestJS comes with a set of built-in features that help speed up development. For instance, it provides built-in support for dependency injection, which allows you to manage your application's components and services in a more organized manner. Additionally, NestJS offers support for features like routing, middleware, validation, and data transformation out of the box.
Express, on the other hand, is much more lightweight and doesn’t offer such features by default. While there are plenty of third-party packages available to implement these features, using them can increase the complexity of your project and add extra overhead.
4. When You Need to Build Microservices
Microservices have become a popular architectural pattern for building scalable and maintainable applications. NestJS makes it easy to build microservices with its built-in support for communication protocols like HTTP, WebSockets, and gRPC. It also provides tools for integrating with message brokers such as Kafka or RabbitMQ, making it an excellent choice for building a microservices-based architecture.
If your project requires microservices, NestJS provides the necessary tools and patterns to make the process seamless. While you can build microservices with Express, it lacks the out-of-the-box features that NestJS offers for such architectures.
5. When You Need a Strong Developer Community and Ecosystem
NestJS has gained a lot of traction in recent years, with a growing community of developers contributing to its ecosystem. The framework provides a rich set of integrations with other technologies such as GraphQL, MongoDB, Redis, and more. It also includes detailed documentation and guides to help developers get started quickly.
In comparison, while Express has been around longer and has a larger community, it is not as structured, and there are fewer built-in integrations with modern tools and technologies. As your project grows, this lack of ecosystem may make it more challenging to find solutions for specific problems.
6. When You Want to Focus on Clean, Maintainable Code
NestJS promotes the use of clean architecture principles, such as the separation of concerns and dependency injection. This makes it easier for developers to organize their code and keep it maintainable, especially in larger applications.
With Express, while you can follow good design patterns, the framework itself is more flexible and doesn’t enforce any particular architecture, which may lead to disorganized code as the project expands. If you’re building a project where clean, maintainable code is a priority, NestJS offers a more structured approach.
7. Mobile App Development and Cost Estimation
If your project involves integrating a backend for a mobile app, it’s essential to consider the mobile app’s potential cost and complexity. For instance, when using a backend with Express.js or NestJS, you might need to calculate how many resources, endpoints, and APIs are required to deliver the mobile application’s functionality. A mobile app cost calculator can help you determine the budget for mobile app development, including backend integration.
If you’re uncertain about which backend technology to choose for mobile app development, NestJS provides a more scalable and maintainable solution for building APIs that power mobile applications, especially for large projects or apps requiring complex business logic.
If you're interested in exploring the benefits of NestJS vs. Express js services for your business, we encourage you to book an appointment with our team of experts. Book an Appointment Conclusion
Choosing between NestJS and Express.js largely depends on the size, complexity, and long-term goals of your project. If you're working on a small, straightforward application and need flexibility, Express.js may be the right choice. However, for large-scale, maintainable, and scalable applications, NestJS offers significant advantages, including its modular architecture, TypeScript support, built-in tools, and microservice capabilities.
If you’re planning on integrating a backend solution into a mobile app or require expert assistance in backend web applications development, consider consulting with a professional team to ensure your project’s success.
0 notes
Text
10 Best Node.js Frameworks for Product Development in 2024

As a leading London web development company, we at Idiosys UK understand the ever-evolving landscape of technology. We constantly strive to equip our developers with the most robust and efficient tools to deliver exceptional web application development services to our clients. In this vein, Node.js has emerged as a game-changer, offering unparalleled speed, scalability, and flexibility for building dynamic web applications. But with a plethora of Node.js frameworks available, choosing the right one can be daunting.
Why Node.js for Web Development?
London, a vibrant hub of innovation, requires state-of-the-art solutions for its enterprises. Node.js, with its single-threaded, event-driven architecture, perfectly aligns with this need. Its non-blocking, I/O model enables fast and efficient handling of concurrent requests, making it ideal for real-time applications like chat, e-commerce, and social media platforms.
But the power lies not just in Node.js itself, but in its robust ecosystem of frameworks. These frameworks provide pre-built modules and functionalities, streamlining the development process and boosting efficiency. Choosing the right framework for your project can be the difference between a mediocre application and a resounding success.
So, let’s dive into the top 10 Node.js frameworks for product development in 2023, catering specifically to the needs of London’s dynamic web development scene:
1. Express.js: The undisputed king of Node.js frameworks, Express offers a lightweight, minimalist foundation for building APIs and web applications. Its vast community and extensive documentation make it a go-to choose for London web developers seeking rapid development and easy maintenance.
2. NestJS: Built on top of Express, NestJS adds structure and organization to your codebase. Its modular architecture and TypeScript integration promote code clarity and maintainability, making it ideal for building complex enterprise applications.
3. Meteor.js: This full-stack framework excels at building real-time applications with its isomorphic codebase. It allows developers to write JavaScript code for both server and client, simplifying development and reducing code duplication. A perfect fit for London’s thriving startup ecosystem, Meteor fosters rapid prototyping and MVP development.
4. Koa.js: A lightweight alternative to Express, Koa prioritizes flexibility and control. Its core is minimal, allowing developers to build custom middleware stacks tailored to their specific requirements. This makes it ideal for creating highly specialized and performant web applications.
5. Sails.js: Built on the MVC architecture, Sails offers a strong foundation for building data-driven web applications. Its focus on rapid development and out-of-the-box features makes it popular for building prototypes and MVPs. London web development companies looking for a quick and efficient solution can find Sails.js a valuable ally.
6. Feathers.js: This microservices-based framework promotes modularity and scalability. Its API-first approach makes it ideal for building loosely coupled, extensible applications. London’s growing demand for API-driven services makes Feathers.js a compelling choice for modern web development projects.
7. Hapi.js: Security and stability are Hapi’s forte. Its focus on security features and routing makes it a preferred choice for building enterprise-grade applications. London’s financial and tech sectors, with their stringent security requirements, can benefit greatly from Hapi’s robust architecture.
8. LoopBack.js: This framework offers a comprehensive toolkit for building APIs and web applications. Its built-in features for data modeling, user authentication, and API management make it a rapid development platform for London web development companies seeking efficiency and scalability.
9. MEAN Stack: This popular stack combines the power of MongoDB, Express, Angular, and Node.js. It offers a complete solution for building full-stack JavaScript applications, making it ideal for London web developers looking for a unified development environment.
10. Total.js: This full-stack framework provides a comprehensive set of features for building web applications, including routing, templating, and databases. Its focus on code organization and maintainability makes it a good choice for large-scale projects.
Choosing the Right Framework for Your London Web Development Project:
While each framework offers unique strengths, choosing the right one depends on your specific project requirements. Consider factors like:
Project complexity and size: For smaller projects, lightweight frameworks like Express or Koa might suffice. Complex enterprise applications might benefit from NestJS or Sails.js.
Team skillset and experience: Choose a framework your developers are comfortable with or are willing to learn.
Security needs: Hapi.js or LoopBack.js offer robust security features for sensitive applications.
Scalability requirements: Consider frameworks like Meteor.js or Feathers.js for applications expected.
Choosing the right Node.js framework is crucial for building a successful web application. By understanding your project’s needs and exploring the options presented in this guide, you can make an informed decision that sets your development journey on the right track. Remember, London is full of with talented website developers and innovative web development companies around you. You just must take right decision.
0 notes
Link
Master NestJS – The JavaScript Node.js Framework
Learn to develop and test enterprise-grade Node.js applications in TypeScript. Learn modern workflows using Docker.
What you’ll learn
Master NestJS – The JavaScript Node.js Framework Developing robust REST APIs Enterprise-Grade Node programming using Nest Testing with Unit & End to End Tests Robust Development Workflow using Docker Using modern database abstraction (TypeORM) Description NestJS is the best way to enter the world of JavaScript/TypeScript Node.js programming. It’s an easy-to-learn and powerful framework. This course will guide you from the very basics into more advanced concepts, including:
Routing and controllers
Databases including TypeORM (Repository, Query Builder, Relations)
Using Docker in your local development workflow
Data validation and serialization
All about NestJS modules, Dependency Injection, and Providers
Configuring, logging, error handling
Authentication including Passport.js, Bcrypt
JSON Web Tokens (JWT) tokens explained, generation and usage
Authorization (making sure the user has privileges)
Using Postman (including collections, environments, automating Postman)
Unit testing
End to End testing (including connecting to a database)
The course comes with full source code included and available on GitHub at all times. Including a separate branch for every lecture with code changes. I’ve made sure everything is as clear and simple as possible, so there are a lot of diagrams and visual aids included (and available for download too!). Join the community in the Q&A forums and on our Discord channel – talk to other students, share your progress, questions and insights! I made extra effort to organize the topics in a way that would make you enjoy the process of learning. The course is short and to the point but covers plenty of topics in surprising detail! get more courses from the course catalog.
1 note
·
View note
Text
Studying the Best Node.JS Frameworks in 2022
The IT sector is innovating with the passing day, with ever-changing revolutions and advancements in technology. Tech solutions have gone through major upgrades to meet the requirements of the tech sector and ensure that business requirements are not only being met but are also being exceeded where necessary. The need for diverse applications and advancements in technology gave rise to the use of Node JS frameworks and the solutions that come because of it.

Node JS has helped create and power a number of frameworks around us today. Currently, Node JS ranks as the fastest platform for web application development on the server side of things. The framework provides developers with solutions that can help them build scalable and convenient web applications.
The Node.JS framework comes with cross-platform properties and is hosted as an open-sourced solution. The solution can conveniently be used to create codes positioned outside of the browser. Node JS comes with a single-threaded event loop architectural model. This model adds to the popularity of the JavaScript framework and allows it to reach new heights and grow beyond expectations in time. You can hire a Node JS developers to truly understand the benefits on offer.
This article discusses some of the best frameworks for Node js developers. These frameworks have played an integral part in web development in the recent past, and you should be well aware of the potential they host.
Express.js
Express.js is one of the best solutions to come out of Node.js. This Node JS API framework was established by developer TJ Holowaychuck and provides all developers and users with convenient software solutions they can follow in the long run.
The Express.js solution is an amalgamation of features that eventually make the final product. All developers working on this solution can use it to develop enterprise level applications that are either single paged or double paged. Some of the solutions on the platform are even considered to be hybrid.
This framework is developed on Node.js and basically consists of an amalgam of features that can come together to provide scalable solutions. Some of the key features of the Express.js solution include:
· The platform comes together with a model view controller that allows developers to build apps that are eccentrics.
· The platform works to achieve routing libraries or routing tables.
· The platform allows heavy load packages that can extend and improve the functionality of this framework.
· The solution helps support HTTP methods, some 14 plus engine templates and gives an improved performance.
Pros:
· Simple to use with a low learning curve.
· Comes with exciting customizations
· Flexible to user needs
· Perfect for developing a short app cycle
Cons:
· Code organization can be hard to understand
· UI is a bit complex
NestJS
NestJS is a fairly fast and flexible framework on the NodeJS environment. The solution can be used to create fast server-side applications that are reliable in nature and can be streamlined to a certain extent. The framework utilizes a set of typing models such as Functional Programming, Functional Reactive Programming and Object Oriented Programming to simplify the process of production and operations on the system.
Some of the features that you can come to expect from NestJS include:
· The platform can help build healthy solutions for front end development on frameworks such as Angular JS.
· Nest JS can arrange codes across different modules in a methodical manner.
· The platform can be used to create web applications consisting of key features from contemporaries.
Also Read: [Hire Node.js Developer to Build Your Next Application ]
Pros:
· Scalable technology that can assist growth in the future.
· The ecosystem is vibrant in nature and comes with open source libraries
· The platform is event based and fast to run
·Strong support for corporate programming.
Cons:
· The tool is a bit immature
· Has some design issues
· Performance can get congested
Hapi.js
Hapi.js is a REST API Framework present on the Node JS library. The solution helps assist the intermediation and connection between client-side and server-side applications. The platform is considered to be the ideal substitute for Express.js and can provide solutions where necessary. Hapi.js comes with the ability to create and master multiple server functions. Since Hapi.js is an open-source framework, it can behave similarly to what server frameworks behave like.
Some of the exciting features that you can expect from the Hapi.js framework include:
· The framework provides dynamic content that can easily be arranged on a JavaScript engine.
· The architecture for the framework is highly scalable, allowing developers to use plugins that help enhance the overall scope of the apps.
· The solution comes with enhanced API references that provide support for extended documents on the go.
Pros:
· The architecture for Hapi.js is based on plugins and easy to use.
· The solution is configuration centric and relatively simple to grasp.
· The service supports microservices
· The web server for Hapi.js supports a wide array of microservices
· The libraries on the solution are robust in nature
Cons:
· All endpoints need to be tested vigorously and manually.
· Users get to go for refactoring manually
Socket.io
Socket.io is a popular framework developed on Node.js that is utilized for producing real-time computer applications and processes. The good part about the Socket.io framework is that it is famous among all developers today and provides accuracy and perfection that can hasten the speed of production.
Another reason going in favor of this framework is that it has an uncomplicated API, which can give users the results they expect from the service.
Key features of Socket.io include:
· The framework assists in detecting anomalies and auto-correcting errors.
· The framework works tirelessly to build a flow of bidirectional data between the web and the servers.
· The framework can help developers maintain multiple browsers and feed streams to them from the server.
Pros:
· Socket.io is capable of performing real-time analytics on data
· The framework can help users with multiplexing
· Socket authentication process is fairly smooth
· Allows fairly fast customization of objects
Cons:
· Socket.io cannot work on web applications that require regular updates and procedures.
· The platform helps maintain connections on a web server
Meteor.JS
Meteor.JS is a popular API Framework on Node JS. The solution is used for developing mobile apps and web applications that can run seamlessly without delay. Meteor.js has the potential to turn app development into a more accessible solution for all involved. The platform can make for a secure space for everyone involved.
Meteor can also help develop real time applications, which are a need of the hour today in this environment. Some of the key features to know about Meteor.JS include;
· The framework allows automated renovation of all mobile applications and ensures that you don’t have to do them at your end.
· The architecture for JS is lightweight and easy to configure. The easy configuration can significantly help reduce code complexity and lines.
· The framework can easily integrate with Vue, React and Mango.
Pros:
· Catchphrases are synced for simple operations
· Abundant packages and libraries are available
· The community is robust and helpful
· The architecture is simple to run and lighter in weight
Cons:
· Excessive
· Not possible to make a mobile web applications.
Koa.js
Koa.js is a similar Node.js framework that is made by the same developers that were initially behind Exopress.js as well. The framework is small in size, but it is a fairly expressive and robust framework that can actively be used on the internet.
Developers on the Koa.js framework can use it to create web apps, including APIs and other solutions. The framework comes with no middleware inside the centre, which is why it can be streamlined and reduced to perfection. Some of the benefits of Koa.js as a framework include:
· The development solution comes with an enhanced option to allow developers the ability to work from the onset.
· The generators on the platform can significantly limit the use of callbacks through error handling.
· The middleware comes packed in a bundle, which ensures server writing is rapid and enjoyable.
Pros:
· Lightweight in nature
· The framework can support keyword syncing, which leads to better results and even better overall collaboration.
· The generator functions on the platform go above the required numerical.
Cons:
· The support community for Koa.js is a bit smaller than the support community for some of the other solutions and places.
· The framework isn’t compatible with middleware styled by express.
Conclusion:
We have mentioned some of the best Node JS frameworks in this article and hope that you can work on them for more success in your professional endeavors. You can read through the information on Node JS to know more about this framework and how it is required for stable and scalable solutions.
The article does a good job to develop key features and the pros and cons of each system. Node JS developers can use this info to choose the best framework for the next time they work with Node JS on their system.
0 notes
Text
Top 5 Node.js Frameworks For Web App Development in 2021
In recent years, many programming languages and translators have emerged. They had all their qualities and highlights to make the app or web improvement measure useful. Regardless, the prevalence of javascript has remained strong and has become consistent due to ease of programming and joint effort.
JavaScript has been popular with web and app development company in bangalore developers for a long time. The JavaScript programming language has a variety of libraries that it imparts to the Node.js Framework.
In this article, I will discuss a couple of the best Node Js frameworks for a measure of improvement of the top quality and speed Android application development company in India. These Node.js structures are shortlisted due to their famous works among the leading list of Bangalore mobile app development companies
Express.JS:
Everyone loves the Express.js framework for Node.js. It's the most popular web application framework, and giants like Uber, Twitter, and IBM already use Express.js. It is a unique framework that helps developers to create Mobile apps development company India and workspace apps at a substantially faster speed.
Plus, it has huge features that make versatility and speed your top concern. Being lightweight, it gets along well with the open access modules of the NPM public database.
Equipped with an amazing API, it guarantees the best performance without dividing the difference into functions of an ideal Node.js framework.
Main features of the Express.js framework
a) High performance to allow multiple operations
b) Server-side programming packages to speed up the process with smaller lines of code
c) It acts as a routing table or a set of routing libraries.
d) HTTP helpers that make programs reusable.
d) Content negotiation: for better communication between the client and the server
e) It comes with a model view controller function that helps to create original applications.
Koa.js:
Koa is planned by designers similar to Express.js and offers more expressive and vigorous highlights for web and application improvement measures. This one stands out among other Node Js frameworks. it is more modest than your other options. However, that doesn't change the way Koa JS is a highly expressive Node.Js framework.
koa.js
Koa.js Framework main features
a) The framework provides an effective error handling solution for better quality;
b) Koa.js is extremely light but very expressive;
c) Requires Node v7.6.0 or higher for ES2015, as well as support for asynchronous function;
d) Methods to perform tasks such as content negotiation, proxy support, redirection, and cache update have been included.
Socket.io
Socket.io is one of the Node.js frameworks used best android app development company India to create ongoing PC applications.These frameworks are well known among designers as they provide precision and speed up the process.Socket.io also has a basic and clear API, which works consistently with every help.
Socket.io
Socket.io Framework Main Features
a) He is incredibly friendly and helps with scheduled correction and anomaly detection etc.
b) Have developers create web and bi-directional information flow server.
c) Makes developers stream clear streams to different programs from the server.
Hapi:
Hapi is one of India's top 10 mobile apps development companies India a free access open source platform and platform. Since the platform is stable and rich in security aspects, it has been known to create proxy servers, REST APIs, and other desktop applications. It has a splendid collection of built-in plugins, so you don't have to think about using rogue middleware.
The simple idea for designing this system is to have a great team running many projects simultaneously with fantastic implementation resources. Plus, it has a wide variety of built-in extensions, so you don't have to think about using rogue middleware.
Hapi Framework main features:
a) Provide broad support to recycled modules.
b) Offers support for large modules.
c) Amazing plan for scattered and large teams.
Nest.js:
It is a progressive Node.js framework that creates dynamic and adaptable enterprise-grade applications and offers full adaptability with its extensive libraries.
Since the framework retains similarity to a subset of Javascript (for example, it worked with Typescript), it adheres to perfect code architecture while maintaining the complexity of high .stepping stopping application code. In addition, the house offers incredible coordination with sister frameworks such as Fastify and Express.
Home is the best combination of best mobile application development companies in bangalore object-oriented functional reactive programming (FRP). Consequently, it is conceivable that it combines cost-effectiveness of the developer and application execution while saving significant time.
Nest.js Framework main features:
Create a healthy front-end development in AngularJS.
NestJS 'modular form is such that it methodically organizes code into different modules.
It can be used to create web applications that have a different functionality than its contemporaries.
Conclution
These Node.js frameworks that we talked about earlier can be useful for a developer to assemble continuous applications. They can be used to optimize scalability and build cross-platform applications efficiently.
Furthermore, we had shortlisted these systems based on their notoriety and USP in contrast to their contending JS structures. Some brands like LinkedIn, PayPal, Walmart, etc., use these structures to develop their applications.
Eventually, we hope that our blog has been useful for the information you were looking for. In case you need to browse more app related websites, check out different MobileAppDaily articles.
FuGenx is Bangalore's most awarded mobile app development company offering services like iOS app development companies India Development, iot apps development company India e-commerce development, mobile app development, UI / UX design and 360 digital marketing to transform companies.
FuGenx Services:
A) ai development company India
B) Mobile application development
C) ml development company India
d) iPhone apps development companies India
E) deep Learning company in India
F ) Top data science companies in India
0 notes
Text
Building an Authentication System with Ionic 4 and NestJS
Whether you celebrate Christmas or not, today is your happy day as I’ve prepared this special for all Devdactic followers!
Since I wanted to give back something to all the loyal followers of this blog, I created a little gift on one of the basics that you’ll hopefully enjoy!
Todays post is not really a tutorial, but a description of the code template that contains both a NestJS backend and also an Ionic app. As a result, once you run both parts you will have a full working authentication template ready for your next app!
You can get the whole gift package by entering your email in the box below.
Let’s talk about how and why it works, and what you need to set up upfront.
Prerequisite
It’s a good idea for both parts of the template to install Ionic and the Nest CLI locally to later build out the projects like this:
npm i -g @nestjs/cli npm i -g ionic
Of course you could also simply install the dependencies inside the project, but having both of them globally is anyway a good idea.
Also, the backend needs a MongoDB for holding the users. Therefore, install MongoDB on your local machine and while you are at it, I recommend to get a good GUI tool for managing your database like Studio 3T.
The Nest Backend
Before you run the backend you need to set a few values, and for this you have to rename the dummy.env file to .env which is the environment used for the application.
In there you can specify the port, the URI to the MongoDB (which should work like it is, the database will automatically be created) and finally a secret for the JWT authentication.
You need to make sure to have your MongoDB up and running now, and then you can go ahead and install all dependencies and run the backend like this:
cd ./api npm install nest start --watch
You should see some logging about the routes being set up, and if everything works your fresh API is now running at port 5000!
The routes of the API are also included in the HolidayGift.postman_collection which you can simply import to Postman to now test your API.
The routes are:
The API contains everything to register users, to login, get user data and delete accounts. Basically all CRUD operations for the user domain plus a login functionality.
In terms of code, you can find all the routes inside the src/users/users.controller.ts:
import { UserDto } from './dto/user.dto'; import { UsersService } from './users.service'; import { Controller, Get, Res, HttpStatus, Post, Body, Put, NotFoundException, Delete, Param, UseGuards } from '@nestjs/common'; import { AuthGuard } from '@nestjs/passport'; @Controller('users') export class UsersController { constructor(private userService: UsersService) {} @Post() async addUser(@Res() res, @Body() createUserDto: UserDto) { try { const user = await this.userService.addUser(createUserDto); return res.status(HttpStatus.OK).json({ msg: 'User has been created successfully', user }); } catch (e) { return res.status(HttpStatus.CONFLICT).json({ msg: 'User already exists' }); } } @UseGuards(AuthGuard()) @Get(':userID') async getUser(@Res() res, @Param('userID') userID) { const user = await this.userService.getUser(userID); if (!user) throw new NotFoundException('User does not exist!'); return res.status(HttpStatus.OK).json(user); } @UseGuards(AuthGuard()) @Put(':userID') async updateUser( @Res() res, @Param('userID') userID, @Body() createUserDto: UserDto, ) { const user = await this.userService.updateUser(userID, createUserDto); if (!user) throw new NotFoundException('User does not exist!'); return res.status(HttpStatus.OK).json({ msg: 'User has been successfully updated', user, }); } @UseGuards(AuthGuard()) @Delete(':userID') async deleteUser(@Res() res, @Param('userID') userID) { const user = await this.userService.deleteUser(userID); if (!user) throw new NotFoundException('User does not exist'); return res.status(HttpStatus.OK).json({ msg: 'User has been deleted', user, }); } @UseGuards(AuthGuard()) @Get() async getAllUser(@Res() res) { const users = await this.userService.getAllUser(); return res.status(HttpStatus.OK).json(users); } }
As you can see, all routes are also protected with a guard, and we are using JWT authentication in this API.
The logic for authentication can also be seen inside the src/authauth/users.service.ts:
import { Injectable } from '@nestjs/common'; import { JwtService } from '@nestjs/jwt'; import { LoginUserDto } from '../users/dto/login-user.dto'; import { UsersService } from '../users/users.service'; import { JwtPayload } from './interfaces/jwt-payload.interface'; @Injectable() export class AuthService { constructor(private usersService: UsersService, private jwtService: JwtService){ } async validateUserByPassword(loginAttempt: LoginUserDto): Promise<any> { let userToAttempt: any = await this.usersService.findOneByEmail(loginAttempt.email); return new Promise((resolve) => { if (!userToAttempt) { resolve({success: false, msg: 'User not found'}); } userToAttempt.checkPassword(loginAttempt.password, (err, isMatch) => { if(err) resolve({success: false, msg: 'Unexpected error. Please try again later.'}); if(isMatch){ resolve({success: true, data: this.createJwtPayload(userToAttempt)}); } else { resolve({success: false, msg: 'Wrong password'}) } }); }); } createJwtPayload(user){ let data: JwtPayload = { id: user._id, email: user.email }; let jwt = this.jwtService.sign(data); return { exp: 36000, token: jwt } } async validateUser(payload: JwtPayload): Promise<any> { return await this.usersService.getUser(payload.id); } }
So you can register without a JWT of course, but all other routes are protected and you need to add the Authorization filed to your header with a value of “Bearer yourJWT”.
The Ionic App
There’s not much to say about the Ionic app, simply install the dependencies like always and then run it:
cd ./app npm install ionic serve
Inside your src/environments/environment.ts you can configure which backend will be used, and by default it will use my Heroku deployment – you should change this soon to your own local backend!
The logic of the app includes a login and register page, and a protected inside area that only users can enter because it’s protected by the auth-guard. Additionally there is another guard that is applied to all pages that are not protected in order to automatically log in users if they were authenticated before!
The code is a pretty simple check, and because it’s a guard you won’t see a page until we really receive the authentication state from the storage. You can find it inside the src/guards/auto-login.guard.ts:
import { Injectable } from '@angular/core'; import { CanActivate, Router } from '@angular/router'; import { Observable } from 'rxjs'; import { ApiService } from '../services/api.service'; import { take, map } from 'rxjs/operators'; @Injectable({ providedIn: 'root' }) export class AutoLoginGuard implements CanActivate { constructor(private api: ApiService, private router: Router) { } canActivate(): Observable<boolean> { return this.api.user.pipe( take(1), map(user => { if (!user) { return true; } else { this.router.navigateByUrl('/app'); return false; } }) ) } }
Besides that, all API interaction takes place inside the src/services/api.service.ts including the management of the JWT, for which we use once again the @auth0/angular-jwt package:
import { environment } from './../../environments/environment'; import { Platform } from '@ionic/angular'; import { Injectable } from '@angular/core'; import { Storage } from '@ionic/storage'; import { BehaviorSubject, Observable, from } from 'rxjs'; import { take, map, switchMap } from 'rxjs/operators'; import { JwtHelperService } from "@auth0/angular-jwt"; import { HttpClient } from '@angular/common/http'; import { Router } from '@angular/router'; const helper = new JwtHelperService(); export const TOKEN_KEY = 'jwt-token'; export interface User { first_name: string; last_name: string; email: string; avatar: string; bio: string; createdAt: string; _id: string; expanded?: boolean; } @Injectable({ providedIn: 'root' }) export class ApiService { public user: Observable<any>; private userData = new BehaviorSubject(null); constructor(private storage: Storage, private http: HttpClient, private plt: Platform, private router: Router) { this.loadStoredToken(); } loadStoredToken() { let platformObs = from(this.plt.ready()); this.user = platformObs.pipe( switchMap(() => { return from(this.storage.get(TOKEN_KEY)); }), map(token => { if (token) { let decoded = helper.decodeToken(token); this.userData.next(decoded); return true; } else { return null; } }) ); } login(credentials: {email: string, password: string }) { return this.http.post(`${environment.apiUrl}/auth`, credentials).pipe( take(1), map(res => { // Extract the JWT return res['token']; }), switchMap(token => { let decoded = helper.decodeToken(token); this.userData.next(decoded); let storageObs = from(this.storage.set(TOKEN_KEY, token)); return storageObs; }) ); } register(credentials: {email: string, password: string }) { return this.http.post(`${environment.apiUrl}/users`, credentials).pipe( take(1), switchMap(res => { console.log('result: ', res); return this.login(credentials); }) ); } getUserToken() { return this.userData.getValue(); } getUserData() { const id = this.getUserToken()['id']; return this.http.get<User>(`${environment.apiUrl}/users/${id}`).pipe( take(1) ); } getAllUsers(): Observable<User[]> { return this.http.get<User[]>(`${environment.apiUrl}/users`).pipe( take(1) ); } updateUser(id, data) { return this.http.put(`${environment.apiUrl}/users/${id}`, data).pipe( take(1) ); } removeUser(id) { return this.http.delete(`${environment.apiUrl}/users/${id}`).pipe( take(1) ); } logout() { this.storage.remove(TOKEN_KEY).then(() => { this.router.navigateByUrl('/'); this.userData.next(null); }); } }
As a final word: The JWT package needs to whitelist domains for which the JWT will be injected into HTTP calls. If you follow the next step and deploy your API somewhere, you need to make sure that you add your new backend URL inside the src/app/app.module.ts:
import { NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { RouteReuseStrategy } from '@angular/router'; import { IonicModule, IonicRouteStrategy } from '@ionic/angular'; import { SplashScreen } from '@ionic-native/splash-screen/ngx'; import { StatusBar } from '@ionic-native/status-bar/ngx'; import { AppComponent } from './app.component'; import { AppRoutingModule } from './app-routing.module'; import { IonicStorageModule, Storage } from '@ionic/storage'; import { HttpClientModule } from '@angular/common/http'; import { TOKEN_KEY } from './services/api.service'; import { JwtModule, JWT_OPTIONS } from '@auth0/angular-jwt'; export function jwtOptionsFactory(storage) { return { tokenGetter: () => { return storage.get(TOKEN_KEY); }, whitelistedDomains: ['localhost:5000', 'holidaygift.herokuapp.com'] // Add your Heroku URL in here! } } @NgModule({ declarations: [AppComponent], entryComponents: [], imports: [BrowserModule, IonicModule.forRoot(), AppRoutingModule, IonicStorageModule.forRoot(), HttpClientModule, JwtModule.forRoot({ jwtOptionsProvider: { provide: JWT_OPTIONS, useFactory: jwtOptionsFactory, deps: [Storage] } })], providers: [ StatusBar, SplashScreen, { provide: RouteReuseStrategy, useClass: IonicRouteStrategy } ], bootstrap: [AppComponent] }) export class AppModule {}
Now let’s see how you can deploy the backend.
Deployment
For the dummy deployment I used Heroku, and you can use it as well to quickly get your API up and running not only on your local machine.
You can basically follow the official Heroku guide to create a new app and push your code to it.
In addition you need to perform 2 further steps.
Add the mLab integration
The API needs a database, and you can easily add a cloud hosted MongoDB to your Heroku app inside the resources tab like this:
Environment Variables
The database will autoamtically write a variable like we did with our local environment file, but you also need to add the value for the JWT_SECRET which you can do inside the settings tab:
Over to You
Now you can use the Heroku URL and use it in your Ionic app, and you have a full blown authentication app in your hands.
Hopefully this is the starting point for your next project, and perhaps you already had some plans for the holiday season?
Definitely let me know if you enjoy the template by tweeting at me or tag me on Instagram!
I would love to see the template in action. You can also find a short video explanation of the authentication template in the video below.
Thanks for all your support and see you again next year, Simon
youtube
The post Building an Authentication System with Ionic 4 and NestJS appeared first on Devdactic.
via Devdactic https://ift.tt/2sk2PUH
0 notes
Text
10 Best Node.js Frameworks for Product Development in 2024
As a leading London web development company, we at Idiosys UK understand the ever-evolving landscape of technology. We constantly strive to equip our developers with the most robust and efficient tools to deliver exceptional web application development services to our clients. In this vein, Node.js has emerged as a game-changer, offering unparalleled speed, scalability, and flexibility for building dynamic web applications. But with a plethora of Node.js frameworks available, choosing the right one can be daunting.
Why Node.js for Web Development?
London, a vibrant hub of innovation, requires state-of-the-art solutions for its enterprises. Node.js, with its single-threaded, event-driven architecture, perfectly aligns with this need. Its non-blocking, I/O model enables fast and efficient handling of concurrent requests, making it ideal for real-time applications like chat, e-commerce, and social media platforms.
But the power lies not just in Node.js itself, but in its robust ecosystem of frameworks. These frameworks provide pre-built modules and functionalities, streamlining the development process and boosting efficiency. Choosing the right framework for your project can be the difference between a mediocre application and a resounding success.
So, let’s dive into the top 10 Node.js frameworks for product development in 2023, catering specifically to the needs of London’s dynamic web development scene:
1. Express.js: The undisputed king of Node.js frameworks, Express offers a lightweight, minimalist foundation for building APIs and web applications. Its vast community and extensive documentation make it a go-to choose for London web developers seeking rapid development and easy maintenance.
2. NestJS: Built on top of Express, NestJS adds structure and organization to your codebase. Its modular architecture and TypeScript integration promote code clarity and maintainability, making it ideal for building complex enterprise applications.
3. Meteor.js: This full-stack framework excels at building real-time applications with its isomorphic codebase. It allows developers to write JavaScript code for both server and client, simplifying development and reducing code duplication. A perfect fit for London’s thriving startup ecosystem, Meteor fosters rapid prototyping and MVP development.
4. Koa.js: A lightweight alternative to Express, Koa prioritizes flexibility and control. Its core is minimal, allowing developers to build custom middleware stacks tailored to their specific requirements. This makes it ideal for creating highly specialized and performant web applications.
5. Sails.js: Built on the MVC architecture, Sails offers a strong foundation for building data-driven web applications. Its focus on rapid development and out-of-the-box features makes it popular for building prototypes and MVPs. London web development companies looking for a quick and efficient solution can find Sails.js a valuable ally.
6. Feathers.js: This microservices-based framework promotes modularity and scalability. Its API-first approach makes it ideal for building loosely coupled, extensible applications. London’s growing demand for API-driven services makes Feathers.js a compelling choice for modern web development projects.
7. Hapi.js: Security and stability are Hapi’s forte. Its focus on security features and routing makes it a preferred choice for building enterprise-grade applications. London’s financial and tech sectors, with their stringent security requirements, can benefit greatly from Hapi’s robust architecture.
8. LoopBack.js: This framework offers a comprehensive toolkit for building APIs and web applications. Its built-in features for data modeling, user authentication, and API management make it a rapid development platform for London web development companies seeking efficiency and scalability.
9. MEAN Stack: This popular stack combines the power of MongoDB, Express, Angular, and Node.js. It offers a complete solution for building full-stack JavaScript applications, making it ideal for London web developers looking for a unified development environment.
10. Total.js: This full-stack framework provides a comprehensive set of features for building web applications, including routing, templating, and databases. Its focus on code organization and maintainability makes it a good choice for large-scale projects.
Choosing the Right Framework for Your London Web Development Project:
While each framework offers unique strengths, choosing the right one depends on your specific project requirements. Consider factors like:
Project complexity and size: For smaller projects, lightweight frameworks like Express or Koa might suffice. Complex enterprise applications might benefit from NestJS or Sails.js.
Team skillset and experience: Choose a framework your developers are comfortable with or are willing to learn.
Security needs: Hapi.js or LoopBack.js offer robust security features for sensitive applications.
Scalability requirements: Consider frameworks like Meteor.js or Feathers.js for applications expected.
Choosing the right Node.js framework is crucial for building a successful web application. By understanding your project’s needs and exploring the options presented in this guide, you can make an informed decision that sets your development journey on the right track. Remember, London is full of with talented website developers and innovative web development companies around you. You just must take right decision.
0 notes
Text
Handling Multiple File Uploads with NestJS
In previous tutorials, we have covered how to POST data to a NestJS server, but when it comes to uploading files to a NestJS (or any) server, things get just a little bit tricker.
In this tutorial, we are going to walk through setting up a controller in NestJS that can handle receiving file uploads from a front-end application. I will also give a basic example of how to upload from the client-side as well (e.g. sending the files from an Ionic application) to actually make use of the server. In a future tutorial, I will likely create a more in-depth example that includes creating a custom Ionic component that can handle multi-file uploads nicely.
We will need to cover some new NestJS concepts in this tutorial in order to complete it - we will start off by covering those, and then we will get into the code.
Before we Get Started
This tutorial assumes that you already have a basic working knowledge of NestJS. If you do not already feel comfortable with creating a basic NestJS server, creating routes, and POSTing data I would recommend completing these tutorials first:
An Introduction to NestJS for Ionic Developers
Using Providers and HTTP Requests in a NestJS Backend
Sending Data with POST Requests to a NestJS Backend
Most of my tutorials do have a focus on using Ionic with NestJS, but it does not really matter if you aren’t using Ionic on the front-end.
@UseInterceptors, FilesInterceptor, and @UploadedFiles
Before we step through the code required to handle file uploads in a NestJS controller, we are going to talk through some concepts we will be using that I haven’t covered in previous NestJS tutorials.
The @UseInterceptors decorator allows us to “intercept” and change requests to and from the server. The basic use of our server involves the user making requests from the client-side to our controllers that implement GET or POST routes, and the server sending a response back to the user. An “interceptor” sits in the middle of this process and can listen to/modify the messages being sent.
We can create our own interceptors if we wish to do whatever we like, but in this case, we are going to use the built-in FilesInterceptor which the @nestjs/common package provides for us. The role of the FilesInterceptor is to extract files from the incoming request and to provide it to us through the @UploadedFiles decorator (similarly to how we extract the body of a POST request using @Body and a DTO).
If you were just uploading a single file you would use FileInterceptor instead of FilesInterceptor. If you were uploading multiple files with multiple different field names, you could also use the FileFieldsInterceptor.
Implementing the Controller
Now that we have a little bit of knowledge about these new concepts, let’s see how we would go about implementing them in a controller.
import { Controller, Post, UseInterceptors, FilesInterceptor, UploadedFiles, Body} from '@nestjs/common'; import { FileDto } from './dto/file.dto'; import * as path from 'path'; const pngFileFilter = (req, file, callback) => { let ext = path.extname(file.originalname); if(ext !== '.png'){ req.fileValidationError = 'Invalid file type'; return callback(new Error('Invalid file type'), false); } return callback(null, true); } @Controller('upload') export class UploadController { constructor(){ } @Post() @UseInterceptors(FilesInterceptor('files[]', 20, { fileFilter: pngFileFilter })) logFiles(@UploadedFiles() images, @Body() fileDto: FileDto){ console.log(images); console.log(fileDto); return 'Done'; } }
This controller creates a POST route at /upload which will accept up to 20 uploaded .png files and log out the image data and the body of the POST request.
As you can see, we are making use of @UseInterceptors and the FilesInterceptor here. The first parameter supplied to the interceptor is the field name from the multipart/form-data sent to the server that contains the array of files (this is so the interceptor knows where to grab the files from, your field name might be different). The second parameter allows us to supply the maximum number of files that can be uploaded, and the third parameter allows us to supply a MulterOptions object.
NestJS uses the popular multer behind the scenes, and you can configure this using the same options you can with multer regularly. In this case, we are supplying a pngFileFilter function which will only allow file names with an extension of .png to be uploaded.
The fileDto is not important here, this is just regular data being posted to the server along with the files.
Sending Files to the Server
To get files from the client to the server, we will need to POST the files as multipart/form-data from a file input to our /upload route. I already have an example of sending files as multipart/form-data from an Ionic application in a previous tutorial I have written about displaying upload/download progress in Ionic.
However, the basic idea is that you would assemble the file data for sending like this:
// Create a form data object let formData = new FormData(); // Optional, if you want to use a DTO on your server to grab this data formData.append('title', data.title); // Append each of the files files.forEach((file) => { formData.append('files[]', file.rawFile, file.name); });
NOTE: The field name we use for the files matches up to the name given to the FilesInterceptor.
You would then just POST that formData object to your NestJS server. Once you do this, you should see the server log out something like the following:
[ { fieldname: 'files[]', originalname: 'image1.png', encoding: '7bit', mimetype: 'image/png', buffer: <Buffer 89 50 4e 47 0d 0a 1a 0a 00 00 00 0d 49 48 44 52 00 00 01 52 00 00 02 58 08 02 00 00 00 bf c4 f9 43 00 00 00 09 70 48 59 73 00 00 0b 13 00 00 0b 13 01 ... >, size: 109693 }, { fieldname: 'files[]', originalname: 'image2.png', encoding: '7bit', mimetype: 'image/png', buffer: <Buffer 89 50 4e 47 0d 0a 1a 0a 00 00 00 0d 49 48 44 52 00 00 01 2c 00 00 00 fa 08 02 00 00 00 94 0f ed a4 00 00 00 09 70 48 59 73 00 00 0b 13 00 00 0b 13 01 ... >, size: 20538 } ]
As you can see above, I’ve uploaded two files: image1.png and image2.png. I could then do whatever I like with these files or their metadata on the server. Perhaps you would want to use the filesystem to store those files somewhere, maybe you want to run some image compression on those images and then return them to the user, or maybe you want to do something else entirely.
Summary
Although there is more to the story than just sending the file data to the server (obviously we are sending it there for some reason, so presumably you’ll want to do something with it), NestJS provides a rather simple implementation for grabbing that data.
As I mentioned earlier, I will likely create another tutorial in the future that focuses on nicely handling multi-file uploads from the client side with Ionic & Angular.
If there is a particular type of tutorial that you would like to see that involves uploading files to a server, let me know in the comments!
via joshmorony - Learn Ionic & Build Mobile Apps with Web Tech https://ift.tt/2TRDz42
0 notes
Text
Adding JWT Authentication to an Ionic Application with MongoDB and NestJS
Many Ionic applications will require the concept of an authenticated user who is authorised to perform certain actions - perhaps only authenticated users may access your application at all, or perhaps you want to restrict certain types of functionality in your application to certain types of users.
There are many different options that can be used to add this functionality to your application, including services like Firebase and Auth0 which do most of the heavy lifting for you and provide a simple API for authenticating users. However, you can also create your own authentication/authorisation functionality, which may be a more attractive option if you are taking a self-hosted approach to your backend.
In this tutorial, we are going to cover how to create our own authentication system for an Ionic application with MongoDB (to store users other data) and NestJS (to handle HTTP requests to the backend). The basic flow will work like this:
A user will create an account (if they do not have one already)
The account will be stored in the MongoDB database (if it has not been already)
The user will supply their email and password to sign in to the application
If the sign in is successful, the user will be supplied with a JWT that identifies them
Requests to any restricted routes will require that the JWT is sent along with the request in order to access it
I will not be covering what JSON Web Tokens (JWT) are in this tutorial. If you are not already familiar with the concept, I would recommend reading this article. In short, a JWT supplied to a user cannot be modified by the user (without breaking the signature), and so if we supply a JWT to the user that says they are Natalie, we can trust that is true since we know the user couldn’t have just edited it themselves on the client-side. If the someone were to try to modify a JWT (e.g. changing Natalie to Josh) then when the JWT is checked on the server we would be able to tell that it was tampered with (and thus reject the request). This concept means we can check a users authorisation without needing their password after they have signed in initially.
A critical point about a JWT is that they cannot be modified not that they can’t be read. A JWT is encoded and that may give the illusion that you could store sensitive data in the JWT, but you should definitely never do this as a JWT can be easily decoded by anybody. A JWT is good for storing information like a user_id, an email, or a username, but never something sensitive like a password. Another important thing to keep in mind about a JWT is that anybody who has it has the ability to be authorised as the “true” owner of the JWT (e.g. if someone managed to steal a JWT from someone, they may be able to perform actions that they should not be authorised to do). We will be taking a very simple approach in this tutorial, but keep in mind that other security measures are often used in conjunction with a JWT.
IMPORTANT: This tutorial is for learning purposes only. It has not been rigorously tested and it is not a plug-and-play solution. Authentication/authorisation and security in general, are important and complex topics. If you are creating anything where security is important, you should always engage the help of an expert with relevant knowledge.
Before We Get Started
Although this tutorial is completely standalone, it continues on from the concepts that we have covered in the previous NestJS tutorials:
An Introduction to NestJS for Ionic Developers
Using Providers and HTTP Requests in a NestJS Backend
Sending Data with POST Requests to a NestJS Backend
Using MongoDB with Ionic and NestJS
If you have not already read these, or you are not already familiar with the basic NestJS concepts, I would recommend that you read those first as I won’t be explaining those concepts in this tutorial.
In order to work with MongoDB on your machine, you will need to have it installed. If you do not already have MongoDB installed on your machine, you can find information on how to do that here. I also released a video recently that covers installing MongoDB on macOS: Installing MongoDB with Homebrew on macOS.
Once you have installed MongoDB, you will need to make sure to open a separate terminal window and run the following command:
mongod
This will start the MongoDB daemon, meaning that the database will be running in the background on your computer and you will be able to interact with it.
1. Create a New NestJS Application
We will start by creating a fresh new NestJS application, which we can do with the following command:
nest new nest-jwt-auth
We are also going to take care of installing all of the dependencies we require as well.
npm install --save @nestjs/mongoose mongoose
This will install mongoose and the associated NestJS package that we will use to interact with our MongoDB database.
npm install --save bcrypt
We will be using bcrypt to hash the user passwords that we will be storing in the database.
npm install --save passport npm install --save passport-jwt npm install --save @nestjs/jwt npm install --save @nestjs/passport
We will be using the Passport library to implement authentication “strategies” - this helps us define the process that will be used to determine whether a user is authorised to access certain routes or not. We will be implementing a JWT strategy, so we also require the JWT packages.
Before we move on, we are also going to enable CORS which will allow us to make cross-domain requests to our NestJS server.
Modify src/main.ts to reflect the following:
import { NestFactory } from '@nestjs/core'; import { AppModule } from './app.module'; async function bootstrap() { const app = await NestFactory.create(AppModule); app.enableCors(); await app.listen(3000); } bootstrap();
2. Set up the MongoDB Connection
In order to interact with our MongoDB database, we will need to set up the connection in the root module of our NestJS application.
Modify src/app.module.ts to reflect the following:
import { Module } from '@nestjs/common'; import { MongooseModule } from '@nestjs/mongoose'; import { AppController } from './app.controller'; import { AppService } from './app.service'; @Module({ imports: [ MongooseModule.forRoot('mongodb://localhost/authexample') ], controllers: [AppController], providers: [AppService], }) export class AppModule {}
In this particular example, we will be using a database called authexample but you can name this whatever you like (there is no need to “create” the database beforehand).
3. Create the Users Module
Now that we have all of the plumbing out of the way, we can move on to building our authentication functionality. We are going to start off by creating a users module that will contain all of the functionality related to creating and finding users.
Run the following command to create the users module
nest g module Users
By using the g command to generate the module for us, the NestJS CLI will automatically import the module into our root app.module.ts module for us. If you create your modules manually, you will also need to manually add the module to your root module.
We can also use the NestJS CLI to automatically create our users controller for us (which will handle the various routes available on the server) and our users service (which will handle any logic for us).
Run the following commands:
nest g controller users nest g service users
The controller and the service will also automatically be added to the users module since we have used the generate command. We will get to implementing the controller and the service soon, but there are still some additional files we need to create.
Create a file at src/users/dto/create-user.dto.ts and add the following:
export class CreateUserDto { readonly email: string; readonly password: string; }
If you recall, we use DTOs (Data Transfer Objects) to define the structure of the data that we want to be able to POST to our server (from our Ionic application or from whatever frontend we are using). This particular DTO defines the data that we will be sending when we want to create a new user. We also need to define a DTO for when a user wants to log in.
Create a file at src/users/dto/login-user.dto.ts and add the following:
export class LoginUserDto { readonly email: string; readonly password: string; }
These two DTOs are exactly the same, so technically, we don’t really need both in this case. However, it would be common that when creating a user you might also want to accept some additional information (perhaps an age, address, account type, and so on).
Create a file at src/users/user.interface.ts and add the following:
export interface User { email: string }
This file just defines a simple type that we will be able to use with our User objects in the application.
Create a file at src/users/user.schema.ts and add the following:
import * as mongoose from 'mongoose'; import * as bcrypt from 'bcrypt'; export const UserSchema = new mongoose.Schema({ email: { type: String, unique: true, required: true }, password: { type: String, required: true } }); // NOTE: Arrow functions are not used here as we do not want to use lexical scope for 'this' UserSchema.pre('save', function(next){ let user = this; // Make sure not to rehash the password if it is already hashed if(!user.isModified('password')) return next(); // Generate a salt and use it to hash the user's password bcrypt.genSalt(10, (err, salt) => { if(err) return next(err); bcrypt.hash(user.password, salt, (err, hash) => { if(err) return next(err); user.password = hash; next(); }); }); }); UserSchema.methods.checkPassword = function(attempt, callback){ let user = this; bcrypt.compare(attempt, user.password, (err, isMatch) => { if(err) return callback(err); callback(null, isMatch); }); };
Now we are getting into something a bit more substantial, and this is actually a core part of how our authentication system will work. As we have talked about in previous tutorials, a Mongoose schema allows to more easily work with data in our MongoDB database. In this case, we are creating a schema to represent a User.
The interesting part here is the save function we are adding as well as the custom method. With Mongoose, we can specify a function we want to run whenever a document is going to be saved in the database. What will happen here is that when we want to create a new User we will supply the email and the password that the user gives us, but we don’t want to just immediately save that to the database. If we did that, the password would just be stored in plain text - we want to hash the user’s password first.
Hashing is a one-way process (unlike encryption, which can be reversed) that we use to avoid storing a user’s password in plain-text in a database. Instead of checking a user’s password against the value stored in the database directly, we check the hashed version of the password they supply against the hashed version stored in the database. This way, we (as the database owner or anyone with access) won’t be able to actually see what the user’s password is, and perhaps more importantly if the database were compromised by an attacker they would not be able to retrieve the user’s passwords either. You should never store a user’s password without hashing it.
What happens with our save function above is that rather than saving the original value, it will use bcrypt to convert the password field into a hashed version of the value supplied. Before doing that, we use isModified to check if the password value is being changed (if we were just updating some other information on the user, we don’t want to re-hash the password field otherwise they would no longer be able to log in).
We define the checkPassword method on the User schema so that we have an easy way to compare a password from a login attempt to the hashed value that is stored. Before we can continue, we will need to set up our new User schema in our users module (which will allow us to use it in our users service).
Modify src/users/users.module.ts to reflect the following:
import { Module } from '@nestjs/common'; import { MongooseModule } from '@nestjs/mongoose'; import { PassportModule } from '@nestjs/passport'; import { UsersController } from './users.controller'; import { UsersService } from './users.service'; import { UserSchema } from './user.schema'; @Module({ imports: [ MongooseModule.forFeature([{name: 'User', schema: UserSchema}]), PassportModule.register({ defaultStrategy: 'jwt', session: false }) ], exports: [UsersService], controllers: [UsersController], providers: [UsersService] }) export class UsersModule {}
The important part here is the addition of forFeature which will make our User schema available to use throughout this module. We have also added JWT as the default strategy for the PassportModule here - this is something we are going to get into more in the Auth module, but we will need to add this PassportModule import into any module that contains routes we want to protect with our JWT authorisation. Now we can move on to implementing our service.
Modify src/users/user.service.ts to reflect the following:
import { Model } from 'mongoose'; import { Injectable } from '@nestjs/common'; import { InjectModel } from '@nestjs/mongoose'; import { User } from './user.interface'; import { CreateUserDto } from './dto/create-user.dto'; @Injectable() export class UsersService { constructor(@InjectModel('User') private userModel: Model<User>) {} async create(createUserDto: CreateUserDto) { let createdUser = new this.userModel(createUserDto); return await createdUser.save(); } async findOneByEmail(email): Model<User> { return await this.userModel.findOne({email: email}); } }
As you can see in the constructor we are injecting our User model, and we will be able to use all of the methods that it makes available. We create two functions in this service. The create function will accept the data for creating a new user, and it will use that data to create a new user in MongoDB. The findOneByEmail function will allow us to find a MongoDB record that matches the supplied email address (which will be useful when we are attempting authentication).
Finally, we just need to implement the controller.
Modify src/users/users.controller.ts to reflect the following:
import { Controller, Get, Post, Body } from '@nestjs/common'; import { CreateUserDto } from './dto/create-user.dto'; import { UsersService } from './users.service'; @Controller('users') export class UsersController { constructor(private usersService: UsersService) { } @Post() async create(@Body() createUserDto: CreateUserDto) { return await this.usersService.create(createUserDto); } }
For now, we just need a single route. This will allow us to make a POST request to /users containing the data required to create a new user. Later, we are going to add an additional “protected” route here that will only be able to be accessed by authorised users.
4. Create the Auth Module
Now we can move on to the Auth module which is going to handle authenticating users, creating JWTs, and checking the validity of JWTs when accessing a protected route. As I mentioned before, we are going to use Passport to create a JWT “strategy” which basically means the code/logic we want to run when attempting to authorise a user for a particular route.
First, we will need to create the module itself:
nest g module Auth
We will also create a controller and service for this module as well:
nest g controller auth nest g service auth
As we had to do in the Users module, we will also need to create some additional files for our Auth module. We will start by creating an interface for our JWTs.
Create a file at src/auth/interfaces/jwt-payload.interface.ts and add the following:
export interface JwtPayload { email: string; }
This is the type for the “payload” of our JWT (i.e. the data contained within the JWT). We are just using an email which we can then use to identify the user by matching it against an email for a user stored in our MongoDB database. You could add other information to your JWT as well, but remember, do not store sensitive information like passwords in a JWT.
Modify src/auth/auth.service.ts to reflect the following:
import { Injectable, UnauthorizedException } from '@nestjs/common'; import { JwtService } from '@nestjs/jwt'; import { LoginUserDto } from '../users/dto/login-user.dto'; import { UsersService } from '../users/users.service'; import { JwtPayload } from './interfaces/jwt-payload.interface'; @Injectable() export class AuthService { constructor(private usersService: UsersService, private jwtService: JwtService){ } async validateUserByPassword(loginAttempt: LoginUserDto) { // This will be used for the initial login let userToAttempt = await this.usersService.findOneByEmail(loginAttempt.email); return new Promise((resolve) => { // Check the supplied password against the hash stored for this email address userToAttempt.checkPassword(loginAttempt.password, (err, isMatch) => { if(err) throw new UnauthorizedException(); if(isMatch){ // If there is a successful match, generate a JWT for the user resolve(this.createJwtPayload(userToAttempt)); } else { throw new UnauthorizedException(); } }); }); } async validateUserByJwt(payload: JwtPayload) { // This will be used when the user has already logged in and has a JWT let user = await this.usersService.findOneByEmail(payload.email); if(user){ return this.createJwtPayload(user); } else { throw new UnauthorizedException(); } } createJwtPayload(user){ let data: JwtPayload = { email: user.email }; let jwt = this.jwtService.sign(data); return { expiresIn: 3600, token: jwt } } }
Our auth service provides three different methods. The first two handle the two different authentication processes available. We have a validateUserByPassword method that will be used when the user is initially logging in with their email and password. This method will find the user in the MongoDB database that matches the supplied email and then it will invoke the custom checkPassword method we added to the User schema. If the hash of the supplied password matches the hash stored in the database for that user, the authentication will succeed. In that case, the method will return a JWT by calling the createJwtPayload method.
The createJwtPayload method will add the user’s email address to the payload, and then it will sign the JWT using the sign method of the JwtService that was injected into the constructor. This is what ensures that the JWT cannot be tampered with as it is signed by a secret key known only to the server (which we will need to set up in a moment).
The validateUserByJwt method will be used when a user has already logged in and has been given a JWT. This will simply check that the email contained in the JWT represents a real user, and if it does it will return a new JWT (and the success of this method will be used to determine whether or not a user can access a particular route).
Modify src/auth/auth.controller.ts to reflect the following:
import { Controller, Post, Body } from '@nestjs/common'; import { AuthService } from './auth.service'; import { LoginUserDto } from '../users/dto/login-user.dto' @Controller('auth') export class AuthController { constructor(private authService: AuthService) { } @Post() async login(@Body() loginUserDto: LoginUserDto){ return await this.authService.validateUserByPassword(loginUserDto); } }
Our controller is quite simple, we just have a single POST route set up which will allow our frontend application to POST a users email and password to the /auth endpoint. This will then invoke the validateUserByPassword method, and if it is successful it will return the JWT for the user.
Create a file at src/auth/strategies/jwt.strategy.ts and add the following:
import { Injectable, UnauthorizedException } from '@nestjs/common'; import { ExtractJwt, Strategy } from 'passport-jwt'; import { AuthService } from '../auth.service'; import { PassportStrategy } from '@nestjs/passport'; import { JwtPayload } from '../interfaces/jwt-payload.interface'; @Injectable() export class JwtStrategy extends PassportStrategy(Strategy) { constructor(private authService: AuthService){ super({ jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(), secretOrKey: 'thisismykickasssecretthatiwilltotallychangelater' }); } async validate(payload: JwtPayload){ const user = await this.authService.validateUserByJwt(payload); if(!user){ throw new UnauthorizedException(); } return user; } }
This is the “strategy” that we will use to authorise a user when they are attempting to access a protected route - this is where the Passport package comes in. In the constructor, we supply passport with the settings we want to use. We will be extracting the JWT from the Bearer header that we will send along with any requests to the server, and the secret key that we will use to sign the JWTs is thisismykickasssecretthatiwilltotallychangelater. You need to change this to a secret value that isn’t known to anybody else - if somebody knows the secret key you are using to sign your JWTs then they can easily create their own JWTs containing whatever information they like, and your server will see those JWTs as valid.
IMPORTANT: Don’t forget to change the secretOrKey value.
The validate method handles checking that the JWT supplied is valid by invoking the validateUserByJwt method that we created earlier.
Modify src/auth/auth.module.ts to reflect the following:
import { Module } from '@nestjs/common'; import { JwtModule } from '@nestjs/jwt'; import { AuthService } from './auth.service'; import { AuthController } from './auth.controller'; import { JwtStrategy } from './strategies/jwt.strategy'; import { UsersModule } from '../users/users.module'; import { PassportModule } from '@nestjs/passport'; @Module({ imports: [ PassportModule.register({ defaultStrategy: 'jwt', session: false }), JwtModule.register({ secretOrPrivateKey: 'thisismykickasssecretthatiwilltotallychangelater', signOptions: { expiresIn: 3600 } }), UsersModule ], controllers: [AuthController], providers: [AuthService, JwtStrategy] }) export class AuthModule {}
Now we just need to make a few changes to our Auth module. Once again, we set up the PassportModule with the default strategy that will be used as we need to import this into any module where we want to add protected routes. We set up the NestJS JwtModule with the values we want to use with our JWT (make sure to use the same secret key value as before, but make sure it is different to the one I am using).
5. Create a Restricted Route
With everything above in place, we now have an API that supports:
Creating new users
Authenticating users with an email and password
Supplying users with a JWT
Authenticating users with a JWT
Restricting particular routes by enforcing that users require a valid JWT in order to access it
Although this is in place, we don’t actually have any protected routes. Let’s create a test route in our users controller.
Modify src/users/users.controller.ts to reflect the following:
import { Controller, Get, Post, Body, UseGuards } from '@nestjs/common'; import { CreateUserDto } from './dto/create-user.dto'; import { UsersService } from './users.service'; import { AuthGuard } from '@nestjs/passport'; @Controller('users') export class UsersController { constructor(private usersService: UsersService) { } @Post() async create(@Body() createUserDto: CreateUserDto) { return await this.usersService.create(createUserDto); } // This route will require successfully passing our default auth strategy (JWT) in order // to access the route @Get('test') @UseGuards(AuthGuard()) testAuthRoute(){ return { message: 'You did it!' } } }
To protect a particular route, all we need to do is add @UseGuards(@AuthGuard()) to it and it will use our default JWT strategy to protect that route. With this in place, if we were to make a GET request to /users/test it would only work if we sent the JWT along with the request in the headers.
6. Test in an Ionic Application
With everything in place, let’s test it!
Everything we have done above really doesn’t have much to do with Ionic at all, you could use this backend with many types of frontends. In the end, all we will be doing is making GET and POST HTTP requests to the NestJS backend. Although you do not have to use Ionic, I am going to show you some rough code that you can use to test the functionality.
NOTE: The following code is purely for testing the API and is in no way designed well. Your Ionic application should not look like this. Keep in mind that you will need to have the HttpClientModule set up in order for the following code to work.
Modify src/home/home.page.ts to reflect the following:
import { Component } from '@angular/core'; import { HttpClient, HttpHeaders } from '@angular/common/http'; @Component({ selector: 'app-home', templateUrl: 'home.page.html', styleUrls: ['home.page.scss'], }) export class HomePage { public createEmail: string; public createPassword: string; public signInEmail: string; public signInPassword: string; public jwt: string; constructor(private http: HttpClient){ } createAccount(){ let credentials = { email: this.createEmail, password: this.createPassword } this.http.post('http://localhost:3000/users', credentials).subscribe((res) => { console.log(res); }); } signIn(){ let credentials = { email: this.signInEmail, password: this.signInPassword } this.http.post('http://localhost:3000/auth', credentials).subscribe((res: any) => { console.log(res); // NOTE: This is just for testing, typically you would store the JWT in local storage and retrieve from there this.jwt = res.token; }); } testRoute(){ let headers = new HttpHeaders().set('Authorization', 'Bearer ' + this.jwt) this.http.get('http://localhost:3000/users/test', {headers: headers}).subscribe((res) => { console.log(res); }); } logout(){ this.jwt = null; } }
Modify src/home/home.page.html to reflect the following:
<ion-header> <ion-toolbar> <ion-title> Ionic Blank </ion-title> </ion-toolbar> </ion-header> <ion-content padding> <h2>Create Account</h2> <ion-input [(ngModel)]="createEmail" type="text" placeholder="email"></ion-input> <ion-input [(ngModel)]="createPassword" type="password" placeholder="password"></ion-input> <ion-button (click)="createAccount()" color="primary">Test Create Account</ion-button> <h2>Sign In</h2> <ion-input [(ngModel)]="signInEmail" type="text" placeholder="email"></ion-input> <ion-input [(ngModel)]="signInPassword" type="password" placeholder="password"></ion-input> <ion-button (click)="signIn()" color="primary">Test Sign In</ion-button> <ion-button (click)="testRoute()" color="light">Test Protected Route</ion-button> <ion-button (click)="logout()" color="light">Test Logout</ion-button> </ion-content>
The important part in the code above is that we are setting the Authorization header and sending our JWT as a bearer token. In order to run this example, you will need to make sure that you:
Have the MongoDB daemon running with mongod
Have your NestJS backend being served by running npm run start
Have your Ionic application served with ionic serve
If you are using the code above you should be able to go through the process of:
Creating a user
Signing in with that user
Accessing the protected route
Logging out (and you will no longer be able to access the protected route)
After creating a user or signing in, you should receive a JWT in the server response that will look something like this:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6InRlc3RAZ21haWwuY29tIiwiaWF0IjoxNTQ0NTcyNzM3LCJleHAiOjE1NDQ1NzYzMzd9.6p0XH9KkGsde9S38nDOkPudYk02dZK6xxtd3qqWFg3M
If you were to paste this JWT in the debugger at jwt.io you would be able to see that the payload of this JWT is:
{ "email": "[email protected]", "iat": 1544572737, "exp": 1544576337 }
However, you might notice that it says “Invalid Signature”. This is good, we should only get a valid signature when the secret key the JWT was signed with is supplied. If you were to first add the key thisismykickasssecretthatiwilltotallychangelater to the “Verify Signature” section under “your-256-bit-secret”, and then add the JWT to the “Encoded” section you will see that the signature is valid. Since this key is only known to our server, only our server can validate or create JWTs.
In the test code, we are just saving the JWT on this.jwt but you would typically save this in some kind of local storage.
If you wanted to test the security of the application you could even try modifying the values of the JWT manually, or supplying your own manually created JWTs to see if you can fool the authorisation process. After you have created a user, if you were to open a MongoDB shell in your terminal by running mongo you should be able to run the following commands:
use authexample users.find()
To retrieve a list of all of the users you have created. The users will look something like this:
{ "_id" : ObjectId("5c0dc18d349bc9479600c171"), "email" : "[email protected]", "password" : "$2b$10$2WLRRE/IWW.1yXcEyt0sZeFS/257w6SAaigbMNMfcqX1JNZ1KKXGO", "__v" : 0 }
You can see the password hashing in action here. I’ll let you in on a little secret - the test password I used for this was password. But, there is no way you could know that just by looking at the value stored in the database:
$2b$10$2WLRRE/IWW.1yXcEyt0sZeFS/257w6SAaigbMNMfcqX1JNZ1KKXGO
Since this value is hashed (not encrypted) it means that this value should not be able to be reversed. We can’t read what the password is, and neither could an attacker.
Summary
This tutorial wasn’t exactly a simple one but without too much work we now have a fully functional authentication/authorisation system that can remember users after their initial login. I’d like to stress again that this is primarily for educational purposes and has not been seriously tested - please make sure to do your own research and testing if you intend to use any of this code in a production environment.
via joshmorony - Learn Ionic & Build Mobile Apps with Web Tech https://ift.tt/2C7R8CG
0 notes
Text
Getting Started with Nest.js
If you have ever worked on a Node.js application before, either built a REST API or an enterprise application, you must have realised how tedious and daunting it was to maintain, especially whenever the application start to scale. The more you add new features to the application, the larger the codebase.
Creating a proper structure for such application can result into serious headache if not properly managed, especially as a result of application specific configurations. This is why Nest.js was created.
Nest.js was built mainly to eliminate disorganized codebases and give Node.js application a moderate and reasonable structure out of the box. Heavily inspired by Angular, Nest.js was built with TypeScript and uses Express.js under hood. This rightly makes it compatible with the majority of express middleware.
In this post, I will introduce and take you through the process of getting started with Nest.js. You will learn about several ways to install the framework on your machine and why you need to consider using it for your next project. In the process of doing this, you will create a very simple RESTful API that enables users to fetch, create and delete books in a bookstore.
This is a very simple application but yet broad enough to give you comprehensive insight on how to craft an application with Nest.js.
Familiarity with TypeScript and a reasonable knowledge of JavaScript will help you get the best out of this tutorial. Experienced with building applications with Angular will be a plus but not a requirement as the article will give you a proper guide on how to easily begin.
You need to install Node and npm. It is advisable to also install nodemon globally on your machine.
Nest.js is a server-side Node.js framework for building efficient, reliable and scalable applications. Built by Kamil and backed by quite a number of reputable organizations and individuals.
Nest.js was introduced to solve the architectural problem of Node.js by giving backend applications a modular structure for organising code into separate modules.
Fully built with TypeScript, it comes with the benefits of code type checking and dependency injection which helps to facilitate the process of development of applications. If you are conversant with the structure of Angular applications, you are going to feel so comfortable with the key concepts of Nest.js and getting started with it will be quite an easy task. Anyways, this post will provide you with the required details needed to start building applications with Nest.js.
In addition, the following list shows some of the benefits of Nest.js as explained here by Kamil:
it surrounds your route handler body with try..catch blocks
it makes every route handler async
it creates a global express router
Free Node eBook
Build your first Node apps and learn server-side JavaScript.
Thank you!
You have successfully joined the Scotchy super duper web dev awesome mailing list.
it creates a separated router for each controller
it binds error-handling middleware
it binds body-parser middleware (both json and extended urlencoded)
Now that you have been briefed about this awesome framework, let’s take a look at the building blocks of Nest.js.
The following are the building blocks used when building Nest.js applications:
Controllers
Typical to most web frameworks, controllers in Nest.js are responsible for handling any incoming requests and returning responses to the client side of the application. For example, if you make an API call to a particular endpoint, say /home, the controller will receive this request and based on the available resources, it will returned the appropriate response.
Nest.js was structured in a way that the routing mechanism is able to control which controller will be responsible for handling a particular request.
Defining a basic controller in Nest.js is as good as creating a TypeScript file and including a decorator @Controller() just like the code snippet below:
// users.controller.ts import { Controller, Get } from '@nestjs/common'; @Controller('users') export class UsersController { @Get() findAll() { return 'This will return all the users'; } }
The prefix of users within the Controller decorator will prompt the UsersController to handle any /users GET request within an application and return the appropriate response as specified. Other HTTP request handled by the controller includes POST , PUT, DELETE as we will see later in the tutorial.
Once a controller is created, it needs to be added to the module definition before Nest.js can easily recognise it. This could be the root ApplicationModule or any other module created within the application. More about this in the module section of this post.
As mentioned earlier, Nest.js was heavily inspired by Angular and similar to an Angular application, one can easily create a provider and inject it into controllers or other providers too as well. These providers are also called services and based on the philosophy of Nest.js, it was designed to abstract any form of complexity and logic to a class called service.
A service provider in Nest.js is just a normal JavaScript class with a special @Injectable() decorator at the top.
For example, you can simply create a service to fetch users as shown below:
// users.service.ts import { Injectable } from '@nestjs/common'; import { User } from './interfaces/user.interface'; @Injectable() export class UsersService { private readonly users: User[] = []; create(user: User) { this.users.push(user); } findAll(): User[] { return this.users; } }
The provider created above is a class with two methods create() and findAll(), which can be used to create and return all users respectively. And to easily help with type checking an interface was used to specify the type of elements that should be received by the methods.
Modules are more like the most important basic building block in Nest.js. They are TypeScript files decorated with @Module decorator. This attached decorator provides metadata that Nest makes use of to organize the application structure. With modules you can easily group related files into one.
Each Nest.js application must have at least one module, usually referred to as the root module. This root module is the top-level module and usually enough for a small application but it is advisable to break a large application into multiple modules as it helps to maintain the structure of the application.
If you have an application that manages a lot of data or functionality about users , we can group both the controller, services and other related files into a single module, say UsersModule for example:
import { Module } from '@nestjs/common'; import { UsersController } from './users.controller.ts'; import { UsersService } from './users.service.ts'; @Module({ controllers: [UsersController], providers: [UsersService] }) export class UsersModule {}
From the preceding file, we are exported a UsersModule that contains both the UsersController and UsersService. With this in place, we can then proceed to import and use the UsersModule within the root module of the application as shown in the following code snippet:
... import { UsersModule } from './users/users.module'; @Module({ ... }) export class AppModule { }
DTO
Data transfer object is an object that defines how data will be sent over the network.
Interfaces
TypeScript interfaces are used for type-checking and defining the types of data that can be passed to a controller or a Nest service.
Dependency injection
Dependency injection is a design pattern used to increase efficiency and modularity of applications. It is often used by the biggest frameworks to keep code clean and easier to use. Nest.js also makes use of it to basically create coupled components.
With this pattern, it is very easy to manage dependencies between building blocks like controllers, providers and modules. The only thing required is to define the dependency for example a UsersService() in the constructor of a controller as shown here:
... @Controller('users') export class UsersController { constructor(private readonly usersService: UsersService){} ... }
With some of these concepts briefly covered, you can now proceed to the next section, where you will put all the knowledge gained so far in this post into use as you will learn how to seamlessly build a RESTful API using Nest.js.
As stated earlier in this post, you will create a sample application that will help you get a good grasp on some of the core concepts of Nest.js.
This application will be specifically for a bookstore. At the end of the post you would have created a micro-service that will enable users to create and add a new book with few descriptions to an existing list of books. This could be from a database, but to ensure simplicity in this post, we won’t really be connecting our application to a database yet. But instead, we will make use of a mock data of books and once a new book is created, we will push and add it to the list.
In order to easily scaffold a new Nest.js application, you will need to globally installed Nest CLI. It is a command line interface tool specifically created to amongst other things, help to craft a new Nest.js app in no time and provide access to ( built in generators ) several commands to generate different files and produce a well-structured application.
Apart from using the CLI tool, you can also install a new Nest.js application by cloning the starter project from GitHub using Git, but for the purpose of this tutorial run the following command to install the Nest CLI:
npm i -g @nestjs/cli
This will give you access to the nest command for project installation and other project specific commands.
Next, run the command below to install a new project named bookstore-nest within your development folder:
nest new bookstore-nest
You will be asked few questions during the installation, just follow the prompt and respond accordingly. Next, once the installation is complete, change directory into the newly created project and start the application with:
// change directory cd bookstore-nest // start the application npm run start
or better still, run the command below in order to use Nodemon for the project:
// start the application using nodemon npm run start:dev
Navigate to http://localhost:3000 from your favorite browser, you will see the Hello World! message as shown here:
First you will start by generating a module for the bookstore. To do this, you will leverage the inbuilt file generator using Nest CLI. Run the following command to scaffold a new module for the application:
nest generate module books
The command above will create a new folder named books within the src folder. Also within the books folder you will find a books.module.ts file.
// ./src/books/books/module.ts import { Module } from '@nestjs/common'; @Module({}) export class BooksModule {}
This was generated by the command and the module has also been added to the app.module.ts which happens to be the root module of the application.
Next, you will create routes for the endpoints. As mentioned earlier, routes are in controllers, so you need to create controllers that will handle individual endpoints. Again, use Nest CLI to generate your controllers, run the following command:
nest generate controller books
This will create a controller inside the books folder. Since we won’t really be connecting to the database for now, create a sample mock data for the bookstore. Under the src folder, create a subfolder named mocks and within the newly created folder, create a new TypeScript file named books.mock.ts and paste the following code in it:
// ./src/mocks/books.mock.ts export const BOOKS = [ { id: 1, title: 'First book', description: "This is the description for the first book", author: 'Olususi Oluyemi' }, { id: 2, title: 'Second book', description: "This is the description for the second book", author: 'John Barry' }, { id: 3, title: 'Third book', description: "This is the description for the third book", author: 'Clement Wilfred' }, { id: 4, title: 'Fourth book', description: "This is the description for the fourth book", author: 'Christian nwamba' }, { id: 5, title: 'Fifth book', description: "This is the description for the fifth book", author: 'Chris anderson' }, { id: 6, title: 'Sixth book', description: "This is the description for the sixth book", author: 'Olususi Oluyemi' }, ];
Next, you will create a service to hold all the logic for the bookstore. Run the following command to generate a service:
nest generate service books
This command will create a new file named books.service.ts within ./src/books folder.
Next, open the newly created file and paste the following:
// ./src/books/books.service.ts import { Injectable, HttpException } from '@nestjs/common'; import { BOOKS } from '../mocks/books.mock'; @Injectable() export class BooksService { books = BOOKS; getBooks(): Promise<any> { return new Promise(resolve => { resolve(this.books); }); } getBook(bookID): Promise<any> { let id = Number(bookID); return new Promise(resolve => { const book = this.books.find(book => book.id === id); if (!book) { throw new HttpException('Book does not exist!', 404); } resolve(book); }); } }
First, you imported the requires modules from Nest.js and also BOOKS from the mock data you created earlier.
Next, you created two different methods named getBooks() and getBook() to retrieve the list of books from the mock data and to fetch just one book using the bookID as a parameter.
Next, add the method below to the /src/books/books.service.ts immediately after the getBook() method:
// ./src/books/books.service.ts import { Injectable, HttpException } from '@nestjs/common'; import { BOOKS } from '../mocks/books.mock'; @Injectable() export class BooksService { books = BOOKS; ... addBook(book): Promise<any> { return new Promise(resolve => { this.books.push(book); resolve(this.books); }); } }
The method above will be used to push a new book to the existing list
Finally, add the last method to delete a particular book using the bookID as a parameter:
// ./src/books/books.service.ts import { Injectable, HttpException } from '@nestjs/common'; import { BOOKS } from '../mocks/books.mock'; @Injectable() export class BooksService { books = BOOKS; ... deleteBook(bookID): Promise<any> { let id = Number(bookID); return new Promise(resolve => { let index = this.books.findIndex(book => book.id === id); if (index === -1) { throw new HttpException('Book does not exist!', 404); } this.books.splice(1, index); resolve(this.books); }); } }
Here, you will use dependency injection design pattern to pass the BooksService into the BooksController through a constructor. Open the BooksController created earlier and paste the following code in it:
// ./src/books/books.controller.ts import { Controller, Get, Param, Post, Body, Query, Delete } from '@nestjs/common'; import { BooksService } from './books.service'; import { CreateBookDTO } from './dto/create-book.dto'; @Controller('books') export class BooksController { constructor(private booksService: BooksService) { } @Get() async getBooks() { const books = await this.booksService.getBooks(); return books; } @Get(':bookID') async getBook(@Param('bookID') bookID) { const book = await this.booksService.getBook(bookID); return book; } @Post() async addBook(@Body() createBookDTO: CreateBookDTO) { const book = await this.booksService.addBook(createBookDTO); return book; } @Delete() async deleteBook(@Query() query) { const books = await this.booksService.deleteBook(query.bookID); return books; } }
Here in this controller, first, the important modules were imported from @nestjs/common and you also import both the BooksService and CreateBookDTO respectively. CreateBookDTO is a data transfer object, a TypeScript class created for type-checking and to define the structures of what an object looks like when creating a new book. We will create this DTO in a bit.
Next, you used constructor to inject the BooksService into the controller and created four different methods which are:
getBooks(): Used to fetch the list of all books. It has @Get() decorator attached to it. This helps to map any GET request sent to /books to this controller.
getBook(): Used to retrieve the details of a particular book by passing the bookID as a parameter.
addBook(): Used to create and post a new book to the existing book list. And because we are not persisting into the database, the newly added book will only be held in memory.
deleteBook(): Used to delete a book by passing the bookID as a query parameter.
Each of the methods has a special decorator attached to it, which makes it very easy to route each HTTP request to a specific method within the controller.
In the previous section, you made use of a data transfer object called CreateBookDTO. To set it up, navigate to the ./src/books folder and create a new subfolder name dto. Next, within the newly created folder, create another file and call it create-book.dto.ts and paste the following in it:
// ./src/books/dto/create-book.dto.ts export class CreateBookDTO { readonly id: number; readonly title: string; readonly description: string; readonly author: string; }
You are almost done with the application, the next line of action is to take a look at the BooksModule and update it accordingly. You will do that in the next section.
Navigate back to the BooksModule created earlier and update it with the code below:
// ./src/books/books.module.ts import { Module } from '@nestjs/common'; import { BooksController } from './books.controller'; import { BooksService } from './books.service'; @Module({ controllers: [BooksController], providers: [BooksService] }) export class BooksModule {}
Start the application again if it is not running at the moment with:
npm run start
and use postman to test the API
We have barely scratched the surface on what Nest.js has to offer the Node.js world in this post. To get more conversant with this awesome framework, first, we took a quick look at the fundamentals and basic building blocks of Nest.js and then proceeded to build a RESTful API where you also learnt about dependency injection amongst other things.
I hope this tutorial as given you enough information to try out Nest.js for your next application. Feel free to drop your thoughts in the comment section below and find the complete source code of this tutorial here on GitHub.
via Scotch.io http://bit.ly/2R5NVbh
0 notes
Text
Adding JWT Authentication to an Ionic Application with MongoDB and NestJS
Many Ionic applications will require the concept of an authenticated user who is authorised to perform certain actions – perhaps only authenticated users may access your application at all, or perhaps you want to restrict certain types of functionality in your application to certain types of users.
There are many different options that can be used to add this functionality to your application, including services like Firebase and Auth0 which do most of the heavy lifting for you and provide a simple API for authenticating users. However, you can also create your own authentication/authorisation functionality, which may be a more attractive option if you are taking a self-hosted approach to your backend.
In this tutorial, we are going to cover how to create our own authentication system for an Ionic application with MongoDB (to store users other data) and NestJS (to handle HTTP requests to the backend). The basic flow will work like this:
A user will create an account (if they do not have one already)
The account will be stored in the MongoDB database (if it has not been already)
The user will supply their email and password to sign in to the application
If the sign in is successful, the user will be supplied with a JWT that identifies them
Requests to any restricted routes will require that the JWT is sent along with the request in order to access it
I will not be covering what JSON Web Tokens (JWT) are in this tutorial. If you are not already familiar with the concept, I would recommend reading this article. In short, a JWT supplied to a user cannot be modified by the user (without breaking the signature), and so if we supply a JWT to the user that says they are Natalie, we can trust that is true since we know the user couldn’t have just edited it themselves on the client-side. If the someone were to try to modify a JWT (e.g. changing Natalie to Josh) then when the JWT is checked on the server we would be able to tell that it was tampered with (and thus reject the request). This concept means we can check a users authorisation without needing their password after they have signed in initially.
A critical point about a JWT is that they cannot be modified not that they can’t be read. A JWT is encoded and that may give the illusion that you could store sensitive data in the JWT, but you should definitely never do this as a JWT can be easily decoded by anybody. A JWT is good for storing information like a user_id, an email, or a username, but never something sensitive like a password. Another important thing to keep in mind about a JWT is that anybody who has it has the ability to be authorised as the “true” owner of the JWT (e.g. if someone managed to steal a JWT from someone, they may be able to perform actions that they should not be authorised to do). We will be taking a very simple approach in this tutorial, but keep in mind that other security measures are often used in conjunction with a JWT.
IMPORTANT: This tutorial is for learning purposes only. It has not been rigorously tested and it is not a plug-and-play solution. Authentication/authorisation and security in general, are important and complex topics. If you are creating anything where security is important, you should always engage the help of an expert with relevant knowledge.
Before We Get Started
Although this tutorial is completely standalone, it continues on from the concepts that we have covered in the previous NestJS tutorials:
An Introduction to NestJS for Ionic Developers
Using Providers and HTTP Requests in a NestJS Backend
Sending Data with POST Requests to a NestJS Backend
Using MongoDB with Ionic and NestJS
If you have not already read these, or you are not already familiar with the basic NestJS concepts, I would recommend that you read those first as I won’t be explaining those concepts in this tutorial.
In order to work with MongoDB on your machine, you will need to have it installed. If you do not already have MongoDB installed on your machine, you can find information on how to do that here. I also released a video recently that covers installing MongoDB on macOS: Installing MongoDB with Homebrew on macOS.
Once you have installed MongoDB, you will need to make sure to open a separate terminal window and run the following command:
mongod
This will start the MongoDB daemon, meaning that the database will be running in the background on your computer and you will be able to interact with it.
1. Create a New NestJS Application
We will start by creating a fresh new NestJS application, which we can do with the following command:
nest new nest-jwt-auth
We are also going to take care of installing all of the dependencies we require as well.
npm install --save @nestjs/mongoose mongoose
This will install mongoose and the associated NestJS package that we will use to interact with our MongoDB database.
npm install --save bcrypt
We will be using bcrypt to hash the user passwords that we will be storing in the database.
npm install --save passport npm install --save passport-jwt npm install --save @nestjs/jwt npm install --save @nestjs/passport
We will be using the Passport library to implement authentication “strategies” – this helps us define the process that will be used to determine whether a user is authorised to access certain routes or not. We will be implementing a JWT strategy, so we also require the JWT packages.
Before we move on, we are also going to enable CORS which will allow us to make cross-domain requests to our NestJS server.
Modify src/main.ts to reflect the following:
import { NestFactory } from '@nestjs/core'; import { AppModule } from './app.module'; async function bootstrap() { const app = await NestFactory.create(AppModule); app.enableCors(); await app.listen(3000); } bootstrap();
2. Set up the MongoDB Connection
In order to interact with our MongoDB database, we will need to set up the connection in the root module of our NestJS application.
Modify src/app.module.ts to reflect the following:
import { Module } from '@nestjs/common'; import { MongooseModule } from '@nestjs/mongoose'; import { AppController } from './app.controller'; import { AppService } from './app.service'; @Module({ imports: [ MongooseModule.forRoot('mongodb://localhost/authexample') ], controllers: [AppController], providers: [AppService], }) export class AppModule {}
In this particular example, we will be using a database called authexample but you can name this whatever you like (there is no need to “create” the database beforehand).
3. Create the Users Module
Now that we have all of the plumbing out of the way, we can move on to building our authentication functionality. We are going to start off by creating a users module that will contain all of the functionality related to creating and finding users.
Run the following command to create the users module
nest g module Users
By using the g command to generate the module for us, the NestJS CLI will automatically import the module into our root app.module.ts module for us. If you create your modules manually, you will also need to manually add the module to your root module.
We can also use the NestJS CLI to automatically create our users controller for us (which will handle the various routes available on the server) and our users service (which will handle any logic for us).
Run the following commands:
nest g controller users nest g service users
The controller and the service will also automatically be added to the users module since we have used the generate command. We will get to implementing the controller and the service soon, but there are still some additional files we need to create.
Create a file at src/users/dto/create-user.dto.ts and add the following:
export class CreateUserDto { readonly email: string; readonly password: string; }
If you recall, we use DTOs (Data Transfer Objects) to define the structure of the data that we want to be able to POST to our server (from our Ionic application or from whatever frontend we are using). This particular DTO defines the data that we will be sending when we want to create a new user. We also need to define a DTO for when a user wants to log in.
Create a file at src/users/dto/login-user.dto.ts and add the following:
export class LoginUserDto { readonly email: string; readonly password: string; }
These two DTOs are exactly the same, so technically, we don’t really need both in this case. However, it would be common that when creating a user you might also want to accept some additional information (perhaps an age, address, account type, and so on).
Create a file at src/users/user.interface.ts and add the following:
export interface User { email: string }
This file just defines a simple type that we will be able to use with our User objects in the application.
Create a file at src/users/user.schema.ts and add the following:
import * as mongoose from 'mongoose'; import * as bcrypt from 'bcrypt'; export const UserSchema = new mongoose.Schema({ email: { type: String, unique: true, required: true }, password: { type: String, required: true } }); // NOTE: Arrow functions are not used here as we do not want to use lexical scope for 'this' UserSchema.pre('save', function(next){ let user = this; // Make sure not to rehash the password if it is already hashed if(!user.isModified('password')) return next(); // Generate a salt and use it to hash the user's password bcrypt.genSalt(10, (err, salt) => { if(err) return next(err); bcrypt.hash(user.password, salt, (err, hash) => { if(err) return next(err); user.password = hash; next(); }); }); }); UserSchema.methods.checkPassword = function(attempt, callback){ let user = this; bcrypt.compare(attempt, user.password, (err, isMatch) => { if(err) return callback(err); callback(null, isMatch); }); };
Now we are getting into something a bit more substantial, and this is actually a core part of how our authentication system will work. As we have talked about in previous tutorials, a Mongoose schema allows to more easily work with data in our MongoDB database. In this case, we are creating a schema to represent a User.
The interesting part here is the save function we are adding as well as the custom method. With Mongoose, we can specify a function we want to run whenever a document is going to be saved in the database. What will happen here is that when we want to create a new User we will supply the email and the password that the user gives us, but we don’t want to just immediately save that to the database. If we did that, the password would just be stored in plain text – we want to hash the user’s password first.
Hashing is a one-way process (unlike encryption, which can be reversed) that we use to avoid storing a user’s password in plain-text in a database. Instead of checking a user’s password against the value stored in the database directly, we check the hashed version of the password they supply against the hashed version stored in the database. This way, we (as the database owner or anyone with access) won’t be able to actually see what the user’s password is, and perhaps more importantly if the database were compromised by an attacker they would not be able to retrieve the user’s passwords either. You should never store a user’s password without hashing it.
What happens with our save function above is that rather than saving the original value, it will use bcrypt to convert the password field into a hashed version of the value supplied. Before doing that, we use isModified to check if the password value is being changed (if we were just updating some other information on the user, we don’t want to re-hash the password field otherwise they would no longer be able to log in).
We define the checkPassword method on the User schema so that we have an easy way to compare a password from a login attempt to the hashed value that is stored. Before we can continue, we will need to set up our new User schema in our users module (which will allow us to use it in our users service).
Modify src/users/users.module.ts to reflect the following:
import { Module } from '@nestjs/common'; import { MongooseModule } from '@nestjs/mongoose'; import { PassportModule } from '@nestjs/passport'; import { UsersController } from './users.controller'; import { UsersService } from './users.service'; import { UserSchema } from './user.schema'; @Module({ imports: [ MongooseModule.forFeature([{name: 'User', schema: UserSchema}]), PassportModule.register({ defaultStrategy: 'jwt', session: false }) ], exports: [UsersService], controllers: [UsersController], providers: [UsersService] }) export class UsersModule {}
The important part here is the addition of forFeature which will make our User schema available to use throughout this module. We have also added JWT as the default strategy for the PassportModule here – this is something we are going to get into more in the Auth module, but we will need to add this PassportModule import into any module that contains routes we want to protect with our JWT authorisation. Now we can move on to implementing our service.
Modify src/users/user.service.ts to reflect the following:
import { Model } from 'mongoose'; import { Injectable } from '@nestjs/common'; import { InjectModel } from '@nestjs/mongoose'; import { User } from './user.interface'; import { CreateUserDto } from './dto/create-user.dto'; @Injectable() export class UsersService { constructor(@InjectModel('User') private userModel: Model<User>) {} async create(createUserDto: CreateUserDto) { let createdUser = new this.userModel(createUserDto); return await createdUser.save(); } async findOneByEmail(email): Model<User> { return await this.userModel.findOne({email: email}); } }
As you can see in the constructor we are injecting our User model, and we will be able to use all of the methods that it makes available. We create two functions in this service. The create function will accept the data for creating a new user, and it will use that data to create a new user in MongoDB. The findOneByEmail function will allow us to find a MongoDB record that matches the supplied email address (which will be useful when we are attempting authentication).
Finally, we just need to implement the controller.
Modify src/users/users.controller.ts to reflect the following:
import { Controller, Get, Post, Body } from '@nestjs/common'; import { CreateUserDto } from './dto/create-user.dto'; import { UsersService } from './users.service'; @Controller('users') export class UsersController { constructor(private usersService: UsersService) { } @Post() async create(@Body() createUserDto: CreateUserDto) { return await this.usersService.create(createUserDto); } }
For now, we just need a single route. This will allow us to make a POST request to /users containing the data required to create a new user. Later, we are going to add an additional “protected” route here that will only be able to be accessed by authorised users.
4. Create the Auth Module
Now we can move on to the Auth module which is going to handle authenticating users, creating JWTs, and checking the validity of JWTs when accessing a protected route. As I mentioned before, we are going to use Passport to create a JWT “strategy” which basically means the code/logic we want to run when attempting to authorise a user for a particular route.
First, we will need to create the module itself:
nest g module Auth
We will also create a controller and service for this module as well:
nest g controller auth nest g service auth
As we had to do in the Users module, we will also need to create some additional files for our Auth module. We will start by creating an interface for our JWTs.
Create a file at src/auth/interfaces/jwt-payload.interface.ts and add the following:
export interface JwtPayload { email: string; }
This is the type for the “payload” of our JWT (i.e. the data contained within the JWT). We are just using an email which we can then use to identify the user by matching it against an email for a user stored in our MongoDB database. You could add other information to your JWT as well, but remember, do not store sensitive information like passwords in a JWT.
Modify src/auth/auth.service.ts to reflect the following:
import { Injectable, UnauthorizedException } from '@nestjs/common'; import { JwtService } from '@nestjs/jwt'; import { LoginUserDto } from '../users/dto/login-user.dto'; import { UsersService } from '../users/users.service'; import { JwtPayload } from './interfaces/jwt-payload.interface'; @Injectable() export class AuthService { constructor(private usersService: UsersService, private jwtService: JwtService){ } async validateUserByPassword(loginAttempt: LoginUserDto) { // This will be used for the initial login let userToAttempt = await this.usersService.findOneByEmail(loginAttempt.email); return new Promise((resolve) => { // Check the supplied password against the hash stored for this email address userToAttempt.checkPassword(loginAttempt.password, (err, isMatch) => { if(err) throw new UnauthorizedException(); if(isMatch){ // If there is a successful match, generate a JWT for the user resolve(this.createJwtPayload(userToAttempt)); } else { throw new UnauthorizedException(); } }); }); } async validateUserByJwt(payload: JwtPayload) { // This will be used when the user has already logged in and has a JWT let user = await this.usersService.findOneByEmail(payload.email); if(user){ return this.createJwtPayload(user); } else { throw new UnauthorizedException(); } } createJwtPayload(user){ let data: JwtPayload = { email: user.email }; let jwt = this.jwtService.sign(data); return { expiresIn: 3600, token: jwt } } }
Our auth service provides three different methods. The first two handle the two different authentication processes available. We have a validateUserByPassword method that will be used when the user is initially logging in with their email and password. This method will find the user in the MongoDB database that matches the supplied email and then it will invoke the custom checkPassword method we added to the User schema. If the hash of the supplied password matches the hash stored in the database for that user, the authentication will succeed. In that case, the method will return a JWT by calling the createJwtPayload method.
The createJwtPayload method will add the user’s email address to the payload, and then it will sign the JWT using the sign method of the JwtService that was injected into the constructor. This is what ensures that the JWT cannot be tampered with as it is signed by a secret key known only to the server (which we will need to set up in a moment).
The validateUserByJwt method will be used when a user has already logged in and has been given a JWT. This will simply check that the email contained in the JWT represents a real user, and if it does it will return a new JWT (and the success of this method will be used to determine whether or not a user can access a particular route).
Modify src/auth/auth.controller.ts to reflect the following:
import { Controller, Post, Body } from '@nestjs/common'; import { AuthService } from './auth.service'; import { LoginUserDto } from '../users/dto/login-user.dto' @Controller('auth') export class AuthController { constructor(private authService: AuthService) { } @Post() async login(@Body() loginUserDto: LoginUserDto){ return await this.authService.validateUserByPassword(loginUserDto); } }
Our controller is quite simple, we just have a single POST route set up which will allow our frontend application to POST a users email and password to the /auth endpoint. This will then invoke the validateUserByPassword method, and if it is successful it will return the JWT for the user.
Create a file at src/auth/strategies/jwt.strategy.ts and add the following:
import { Injectable, UnauthorizedException } from '@nestjs/common'; import { ExtractJwt, Strategy } from 'passport-jwt'; import { AuthService } from '../auth.service'; import { PassportStrategy } from '@nestjs/passport'; import { JwtPayload } from '../interfaces/jwt-payload.interface'; @Injectable() export class JwtStrategy extends PassportStrategy(Strategy) { constructor(private authService: AuthService){ super({ jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(), secretOrKey: 'thisismykickasssecretthatiwilltotallychangelater' }); } async validate(payload: JwtPayload){ const user = await this.authService.validateUserByJwt(payload); if(!user){ throw new UnauthorizedException(); } return user; } }
This is the “strategy” that we will use to authorise a user when they are attempting to access a protected route – this is where the Passport package comes in. In the constructor, we supply passport with the settings we want to use. We will be extracting the JWT from the Bearer header that we will send along with any requests to the server, and the secret key that we will use to sign the JWTs is thisismykickasssecretthatiwilltotallychangelater. You need to change this to a secret value that isn’t known to anybody else – if somebody knows the secret key you are using to sign your JWTs then they can easily create their own JWTs containing whatever information they like, and your server will see those JWTs as valid.
IMPORTANT: Don’t forget to change the secretOrKey value.
The validate method handles checking that the JWT supplied is valid by invoking the validateUserByJwt method that we created earlier.
Modify src/auth/auth.module.ts to reflect the following:
import { Module } from '@nestjs/common'; import { JwtModule } from '@nestjs/jwt'; import { AuthService } from './auth.service'; import { AuthController } from './auth.controller'; import { JwtStrategy } from './strategies/jwt.strategy'; import { UsersModule } from '../users/users.module'; import { PassportModule } from '@nestjs/passport'; @Module({ imports: [ PassportModule.register({ defaultStrategy: 'jwt', session: false }), JwtModule.register({ secretOrPrivateKey: 'thisismykickasssecretthatiwilltotallychangelater', signOptions: { expiresIn: 3600 } }), UsersModule ], controllers: [AuthController], providers: [AuthService, JwtStrategy] }) export class AuthModule {}
Now we just need to make a few changes to our Auth module. Once again, we set up the PassportModule with the default strategy that will be used as we need to import this into any module where we want to add protected routes. We set up the NestJS JwtModule with the values we want to use with our JWT (make sure to use the same secret key value as before, but make sure it is different to the one I am using).
5. Create a Restricted Route
With everything above in place, we now have an API that supports:
Creating new users
Authenticating users with an email and password
Supplying users with a JWT
Authenticating users with a JWT
Restricting particular routes by enforcing that users require a valid JWT in order to access it
Although this is in place, we don’t actually have any protected routes. Let’s create a test route in our users controller.
Modify src/users/users.controller.ts to reflect the following:
import { Controller, Get, Post, Body, UseGuards } from '@nestjs/common'; import { CreateUserDto } from './dto/create-user.dto'; import { UsersService } from './users.service'; import { AuthGuard } from '@nestjs/passport'; @Controller('users') export class UsersController { constructor(private usersService: UsersService) { } @Post() async create(@Body() createUserDto: CreateUserDto) { return await this.usersService.create(createUserDto); } // This route will require successfully passing our default auth strategy (JWT) in order // to access the route @Get('test') @UseGuards(AuthGuard()) testAuthRoute(){ return { message: 'You did it!' } } }
To protect a particular route, all we need to do is add @UseGuards(@AuthGuard()) to it and it will use our default JWT strategy to protect that route. With this in place, if we were to make a GET request to /users/test it would only work if we sent the JWT along with the request in the headers.
6. Test in an Ionic Application
With everything in place, let’s test it!
Everything we have done above really doesn’t have much to do with Ionic at all, you could use this backend with many types of frontends. In the end, all we will be doing is making GET and POST HTTP requests to the NestJS backend. Although you do not have to use Ionic, I am going to show you some rough code that you can use to test the functionality.
NOTE: The following code is purely for testing the API and is in no way designed well. Your Ionic application should not look like this. Keep in mind that you will need to have the HttpClientModule set up in order for the following code to work.
Modify src/home/home.page.ts to reflect the following:
import { Component } from '@angular/core'; import { HttpClient, HttpHeaders } from '@angular/common/http'; @Component({ selector: 'app-home', templateUrl: 'home.page.html', styleUrls: ['home.page.scss'], }) export class HomePage { public createEmail: string; public createPassword: string; public signInEmail: string; public signInPassword: string; public jwt: string; constructor(private http: HttpClient){ } createAccount(){ let credentials = { email: this.createEmail, password: this.createPassword } this.http.post('http://localhost:3000/users', credentials).subscribe((res) => { console.log(res); }); } signIn(){ let credentials = { email: this.signInEmail, password: this.signInPassword } this.http.post('http://localhost:3000/auth', credentials).subscribe((res: any) => { console.log(res); // NOTE: This is just for testing, typically you would store the JWT in local storage and retrieve from there this.jwt = res.token; }); } testRoute(){ let headers = new HttpHeaders().set('Authorization', 'Bearer ' + this.jwt) this.http.get('http://localhost:3000/users/test', {headers: headers}).subscribe((res) => { console.log(res); }); } logout(){ this.jwt = null; } }
Modify src/home/home.page.html to reflect the following:
<ion-header> <ion-toolbar> <ion-title> Ionic Blank </ion-title> </ion-toolbar> </ion-header> <ion-content padding> <h2>Create Account</h2> <ion-input [(ngModel)]="createEmail" type="text" placeholder="email"></ion-input> <ion-input [(ngModel)]="createPassword" type="password" placeholder="password"></ion-input> <ion-button (click)="createAccount()" color="primary">Test Create Account</ion-button> <h2>Sign In</h2> <ion-input [(ngModel)]="signInEmail" type="text" placeholder="email"></ion-input> <ion-input [(ngModel)]="signInPassword" type="password" placeholder="password"></ion-input> <ion-button (click)="signIn()" color="primary">Test Sign In</ion-button> <ion-button (click)="testRoute()" color="light">Test Protected Route</ion-button> <ion-button (click)="logout()" color="light">Test Logout</ion-button> </ion-content>
The important part in the code above is that we are setting the Authorization header and sending our JWT as a bearer token. In order to run this example, you will need to make sure that you:
Have the MongoDB daemon running with mongod
Have your NestJS backend being served by running npm run start
Have your Ionic application served with ionic serve
If you are using the code above you should be able to go through the process of:
Creating a user
Signing in with that user
Accessing the protected route
Logging out (and you will no longer be able to access the protected route)
After creating a user or signing in, you should receive a JWT in the server response that will look something like this:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6InRlc3RAZ21haWwuY29tIiwiaWF0IjoxNTQ0NTcyNzM3LCJleHAiOjE1NDQ1NzYzMzd9.6p0XH9KkGsde9S38nDOkPudYk02dZK6xxtd3qqWFg3M
If you were to paste this JWT in the debugger at jwt.io you would be able to see that the payload of this JWT is:
{ "email": "[email protected]", "iat": 1544572737, "exp": 1544576337 }
However, you might notice that it says “Invalid Signature”. This is good, we should only get a valid signature when the secret key the JWT was signed with is supplied. If you were to first add the key thisismykickasssecretthatiwilltotallychangelater to the “Verify Signature” section under “your-256-bit-secret”, and then add the JWT to the “Encoded” section you will see that the signature is valid. Since this key is only known to our server, only our server can validate or create JWTs.
In the test code, we are just saving the JWT on this.jwt but you would typically save this in some kind of local storage.
If you wanted to test the security of the application you could even try modifying the values of the JWT manually, or supplying your own manually created JWTs to see if you can fool the authorisation process. After you have created a user, if you were to open a MongoDB shell in your terminal by running mongo you should be able to run the following commands:
use authexample users.find()
To retrieve a list of all of the users you have created. The users will look something like this:
{ "_id" : ObjectId("5c0dc18d349bc9479600c171"), "email" : "[email protected]", "password" : "$2b$10$2WLRRE/IWW.1yXcEyt0sZeFS/257w6SAaigbMNMfcqX1JNZ1KKXGO", "__v" : 0 }
You can see the password hashing in action here. I’ll let you in on a little secret – the test password I used for this was password. But, there is no way you could know that just by looking at the value stored in the database:
$2b$10$2WLRRE/IWW.1yXcEyt0sZeFS/257w6SAaigbMNMfcqX1JNZ1KKXGO
Since this value is hashed (not encrypted) it means that this value should not be able to be reversed. We can’t read what the password is, and neither could an attacker.
Summary
This tutorial wasn’t exactly a simple one but without too much work we now have a fully functional authentication/authorisation system that can remember users after their initial login. I’d like to stress again that this is primarily for educational purposes and has not been seriously tested – please make sure to do your own research and testing if you intend to use any of this code in a production environment.
What to watch next...
VIDEO
via joshmorony – Learn Ionic & Build Mobile Apps with Web Tech https://ift.tt/2C7R8CG
0 notes
Text
10 Node Frameworks to Use in 2019
Introduction
More developers have switched to using JavaScript to build more applications, especially for the web. This has brought about an exponential growth in the usage of frameworks built specifically for the JavaScript community to facilitate quick prototyping and building of awesome projects.
When Node.js was introduced to the tech community in 2009 as a tool for building scalable server-side web applications, it came with a lot of benefits which includes but not limited to the usage of event-driven non-blocking input/output model, single-threaded asynchronous programming amongst others.
The fact that, as a developer, you can easily use the same language both for the client-side and server-side scripting easily increased the quick adoption and rapid the usage of Node.
Over the years, a lot of experienced JavaScript developers have built quite a number of impressive frameworks to easily get started with Node.js when developing web applications.
As we look into 2019, I will list some of the most popular Node.js frameworks that you should consider using for building web applications irrespective of the size.
What is a Node framework?
A Node.js framework is just some abstract design, built out of Node.js, that embodies the control flow of the given framework’s design. So it is almost like the skeleton of a program whereby the customised codes you write kind of makes up as the meat that completes the program.
So for every Node.js function, there would be some generic implementation unique to the framework which would then require the user to follow the lead of the framework by adding more codes to define its use case.
Benefits of Node frameworks
Node.js frameworks are mostly used because of their productivity, scalability and speed, making them one of the first choice for building enterprise applications for companies.
Node.js allows you to write the same language for both your front-end and backend, saving you the stress of learning a new language for some simple implementation, and also helping you maintain the same coding pattern all through.
By using a framework, you can work with a set of tools, guidelines, and recommended practices that help you save time. It also can help solidify the code standards across a team of developers.
Selecting a Node Framework
Selecting a framework can be a bit tricky and subjective to its use case. This is because we choose based on a particular feature we like. Ranging from the weight of the framework on the application, speed, simplicity, learning curve, flexibility and configuration, use case or maybe even popularity in some cases, GitHub stars.
Next, lets take a deep dive into the objective of this post and go through the list of Node.js frameworks that will help boost your productivity when building JavaScript applications, especially on the server-side.
Stars aren't everything so we'll be organizing by what we've seen to be popular on Scotch.io.
1. AdonisJs [GitHub Stars: 5,053]
AdonisJsis a Node.js framework. From the official documentation, "AdonisJs is a Node.js MVC framework that runs on all major operating systems. It offers a stable ecosystem to write a server-side web application so that you can focus on business needs over finalising which package to choose or not."
Adonis is billed as the Laravel of Node. Simplicity and a focus on getting things done.
"We're big fans of Laravel's approach (Scotch is built on Laravel) so when we saw those same principles come to the Node side, we were very excited." - Chris Sevilleja
Why AdonisJS?
AdonisJs has a support for an ORM is made with SQL-databases in mind (PostgreSQL). It creates efficient SQL-queries and is based on active record idea. Its query builder is easy to learn and allows us to build simple queries quickly.
AdonisJs has good support for No-SQL database like MongoDB too. It's MVC structure is quite similar to Laravel, so if you've been using Laravel for web development, AdonisJs will be a walk in the park.
To get started easily check out this comprehensive article by Chimezie here on scotch.io.
2. Express.js [GitHub Stars: 41,036]
Express.js is a fast, non-opinionated, minimalist web framework for Node.js. It is simply a technology built on Node.js which behaves like a middleware to help manage our servers and routes. Looking at the asynchronous nature of Node.js and the fact that Express.js was built on node, the ability to build a light-weight application that can process more than a single request seamlessly actually depends on the serving capability of technologies like express.
It’s robust API allows users to configure routes to send/receive requests between the front-end and the database (acting as a HTTP server framework). A good advantage with express is how it supports a lot of other packages and other template engines such as Pug, Mustache, EJS and a lot more.
Some of the numerous advantages of Express.js includes:
Almost the standard for Node.js web middleware
Fully customisable
Low learning curve
Majorly focused on browsers, making templating and rendering an almost out of the box feature.
Express.js has shown, over time, that it’s popularity is worth the hype with its easy to use methods and functions. It is probably the most popular Node.js framework available for the JavaScript community on GitHub with over 41,000 stars [Github stars: 41,036].
Looking at this framework and all it’s exciting abilities, I do not see it going away anytime soon.
3. Meteor.js [GitHub Stars: 40,490]
The Meteor docs defines meteor as a full-stack JavaScript platform for developing modern web and mobile applications. It’s major advantage is it’s realtime update. As changes are made to the web app, it automatically updates the template with the latest changes.
The Node.js framework makes development quite very simplified by providing a platform for the entire tier of the application to be in the same language; JavaScript. Making it function just as efficient in both the server and client side.
Meteor stands the capability of serving large projects like reaction commerce( known to be one of the largest and most popular e-commerce open source projects).
The most fascinating aspect of the Meteor framework is the very rich and organised documentation/large community it has, helping users learn fast by reaching out and getting their hands dirty with projects, very fast.
With the fact that meteor is leveraging on the Facebook GraphQL datastack to come up with meteor Apollo, as far back as 2016, only indicates that they have good plans and a visionary perception of what the future holds for data, how it is managed and how it flows. If there is any list of Node.js frameworks to watch out for, I would probably be arrested if I did not add Meteor to that list.
4. Nest.js [GitHub Stars: 10,128]
NestJs is a framework built with Node.js, It is used for building efficient, scalable Node.js server-side applications. Nest uses progressive JavaScript and is written with TypeScript. Being built with TypeScript means that Nest comes with strong typing and combines elements of OOP(Object Oriented Programming), FP(Functional Programming) and FRP(Functional Reactive Programming).
Nest also makes use of Express, It provides an out of the box application architecture which allows for the effortless creation of highly testable, scalable, loosely coupled, and easily maintainable applications.
Nest CLI can be used to generate nest.js applications with a lot of features out of the box. According to the information on the website, one can contact the nest community of developers behind the nest framework to find out more about expertise consulting, on-site enterprise support, trainings, and private sessions. Isn’t that cool? Well I guess it is, and I also think this also should make it into the list of Node.js frameworks to look out for in 2019.
5. Sails.js [GitHub Stars: 19,887]
According to the official site, Sails is another Node.js framework used to build custom enterprise-grade Node.js apps. It boasts of being the most popular MVC Node.js framework with the support for modern apps requirements. The APIs are data-driven, with a scalable service oriented architecture.
Let us take a closer look at what they mean here. Sails bundles an ORM, waterlines, that makes compatibility possible with almost all databases, going as far as providing a huge number of community projects. Some of its officially supported adapters include MYSQL, Mongo, PostgreSQL, Redis, and even Local Disk.
Looking at the backend, Just by running an installation command, `sails generate api bookstore` for instance, sails blows your mind by providing you some basic blueprints, without you writing any codes at all.
This command provides you endpoints to CRUD bookstore. You think that is all right, check this out: Sails is also compatible with almost all frontend technologies ranging from React, Angular, Backbone, iOS/objective C, Android/java, windows phone and probably even some technologies yet to be created. For this one, 2019 it is! summarised features include:
Many automated generators.
Requires no additional routing
Great frontend compatibility with other frontend technologies.
Transparent support for Websockets.
Enables faster build of REST API.
Compatible with almost all database, thanks to its waterline ORM.
6. Koa.js [GitHub Stars: 23,902]
Referred to as the next generation web framework for Node.js(according to the website), Koa was created by the same team that created Express.js, making it seem like it would pick up from where express left off. Koa is unique in the fact that it uses some really cool ECMAScript(ES6) methods that have not even landed in some browsers yet, it allows you to work without callbacks, while also providing you with an immense increase in error handling. it requires a Node.js version of at least 0.11 or higher.
According to the website, Koa does not bundle any middleware within core, meaning the middlewares are more cascaded/streamlined, and every line of code is quite elegant and granular, thereby allowing you to structure the parts however you want(component-based middlewares). This makes the framework to have more control over configurations and handling.
Koa became futureproof owing to the fact that it could actually ditch the holy grail of asynchronous functionality: callbacks.
Some key features include:
Ditched callbacks hell
Component-based building blocks
Cascading middlewares
Quite modular
Efficient error handling
This is definitely a framework for the future and I am almost beginning to see that if an article for frameworks to lookout for in the year 2020 comes out, it would still probably make the list.
7. LoopBack.js [GitHub Stars: 11,985]
LoopBack is another Node.js framework with an easy-to-use CLI and a dynamic API explorer. It allows you to create your models based on your schema or dynamic models in the absence of a schema. It is compatible with a good number of REST services and a wide variety of databases including MySQL, Oracle, MongoDB, Postgres and so on.
It has the ability to allow a user build a server API that maps to another server, almost like creating an API that is a proxy for another API. It’s support for native mobile and browser SDKs for clients like Android/Java, iOS, Browser javaScript(Angular).
Key features:
Quickly create dynamic end-to-end REST APIs.
Connect devices and browsers to data and services.
Use Android, iOS, and AngularJS SDKs to easily create client apps.
Add-on components for file management, 3rd-party login, and OAuth2.
Runs on-premises or in the cloud
Most of these details were collected from their Website/documentation which I found very exciting to go through and even try to get a basic setup up, Indicating that they have a well structured documentation and a community distributed across different media( StrongLoop blog, LoopBack Google Group, LoopBack Gitter channel ). For instance, the Loopback blog provides lots of tutorials and use cases on how to leverage the use of the technology in different ways.
Amongst some of its powerful users are Go Daddy, Flight Office, Bank of America(Meryll Linch), Symantec, Intellum, ShoppinPal and so on.
8. Hapi.js [GitHub Stars: 10,371]
Just like ExpressJs, the common hapi.js(supported by Walmart Labs) is a Node.js framework that helps serve data by intermediating between the server side and client. It is quite a good substitute for Express(they both have their unique features).
Hapi is a configuration-driven pattern, traditionally modeled to control web server operations. A unique feature it has is the ability to create a server on a specific IP, with features like the ‘onPreHandler’, we can do something with a request before it is completed by intercepting it and doing some pre-processing on the request.
Considering it’s ‘handler’ function where we can call a route and still pass some configurations while making the requests, just to get the function to do something specified in the configuration. This handler, from what we see, acts like a pseudo-middleware.
Let us look at some key features that make hapiJs promising:
There is a deeper control over request handling.
Detailed API reference and a good support for document generation
Has more functions for building web servers
Configuration-based approach to some sub-middlewares(pseudo-middlewares)
Provides the availability of caching, Authentication, and input validation.
Has a plugin-based architecture for scaling.
Provides you with really good enterprise plugins like the joi, yar, catbox, boom, tv, travelogue, and so on.
HapiJs might not be as popular [github stars: 10,371] as Express but it has some good backing up and it seems to be gaining some grounds too. It does not seem like it is slowing down its mark and relevance anytime soon.
9. Derby.js [4,350]
According to the Derby.js site, it is a full stack Node.js framework for writing modern web applications. Derby has been around a little while, quite long enough to have proven itself to hop into 2019 and rock some chords. Let’s see what we have here.
DerbyJs provides you with seamless data synchronisation between your server and client with an automatic conflict resolution powered by ShareDB's operational transformation of JSON and text. It permits you the opportunity to add customised codes to build highly efficient web applications.
10. Total.js [Github stars: 3,853]
Total.js boast of being a very fast development Node.js framework, that requires little maintenance, with a good performance and a seamless scaling transition. It shows some promise by giving some insight on their website, where they ask for visitors willing to contribute to the growth of the framework. So far the Total.js team has spent some time trying to get more premium sponsors to join them. This is another indication that they have plans to expand and should be checked out for more growth in the nearest future to come.
Total.js has some really beautiful versions like the Total.js Eshop, which contains a user interface optimized for mobile devices, and downloadable by all premium members. The Eshop is one of the best Node.js e-commerce system. This is because of its many versions of unique content management system(CMS).
Conclusion
If there is anything we can pick from this article, I can bet you must have noticed before now that picking a framework is based on what you actually want to achieve with it.
The Node.js frameworks above have purely shown us that whatever framework we are going for, there is an open and welcoming community out there solving issues and ready to aid you with learning the basics of that particular framework, which a is vital factor to look out for amongst lots more other factors like GitHub contributions, stars, issues and so on. Just for the fun of it, you can find a lot more of Node.js frameworks here.
Please note that all the Node.js framework highlighted in this post were selected based on popularity in the JavaScript community, usage and personal opinion.
Do you know of any other awesome Node.js framework that you feel its worthy of being added to the list? please feel free to mention it in the comment section below.
I do hope you find this post very helpful. Happy coding.
via Scotch https://ift.tt/2Q1WcRA
0 notes
Text
Using Providers and HTTP Requests in a NestJS Backend
In the previous tutorial, we covered setting up a simple NestJS server that communicated with an Ionic application. All we have done so far is create a simple controller in NestJS that responded with some dummy message data. At the moment, it looks like this:
import { Controller, Get, Param } from '@nestjs/common'; @Controller('messages') export class MessagesController { @Get() getMessages(){ return { message: 'In a real example, I would return all of the messages' } } @Get(':id') getMessage(@Param('id') id){ return { message: `In a real example, I would return the message with an id of ${id}` } } }
The purpose of the previous tutorial was to introduce you to the basic structure of a NestJS project and get some simple communication happening between the backend and the front end.
In this tutorial, we will be aiming to cover two more concepts:
Using Providers
Making HTTP Requests
If you are coming from an Ionic/Angular background, then you could consider the Controllers in a NestJS backend to be similar in concept to the pages/views in your Ionic applications. Like pages, we should aim to keep our controllers as “light” as possible. The main role of a controller is to “direct traffic” – we should not assign too much “work” to a controller, it should just listen for the incoming requests, outsource the work that needs to be done, and then send a response to the request.
In that sense, it is a good idea to utilise “providers” in a NestJS application to do the heavy lifting for us. This way, a controller can make a request to a provider to do some work, rather than doing the work itself. This is much the same as we would have our pages in an Ionic/Angular application makes requests to a provider rather than do the work itself.
As an example, we will be modifying our existing server to fetch some data from a real API rather than just returning a string as dummy data. In the course of doing this, we will also need to learn how to make HTTP requests, as we will be launching an HTTP request from the provider that we create.
We will be using the API that quotesondesign.com provides to pull in some quotes to the application. The general process that we will be creating is:
The Ionic application makes a request to our NestJS backend
The controller that listens for that request will make a call to our provider
The provider will make a request to the API and return the data to the controller
The controller will return the data to the Ionic application
Why not just consume the API directly from the client?
Technically, we probably could just make an HTTP request from our Ionic application directly to the API for the same result. For example, in our Ionic application (or whatever kind of client-side tech you happen to be using) we could do something like this:
this.http.get('http://quotesondesign.com/wp-json/posts/2463).subscribe((response) => { console.log(response); });
Assuming that this particular API supports CORS, this would work just fine. We won’t be doing this, though. In this tutorial, we will be making a request to our NestJS server to load the data into the application instead (and the server will handle making the request to the Quote API), e.g:
this.http.get('http://localhost:3000/messages').subscribe((response) => { console.log(response); });
There can be benefits to proxying the request through our own server (e.g. if the API we wanted to use did not support CORS). However, what the service does is beside the point anyway – the point of this tutorial is to demonstrate how to use a provider in NestJS to “do work”, and I wanted a simple example to demonstrate the general idea.
In a more realistic/complex example, we might use the provider to handle requests that need to be handled on the server side. Perhaps a request to a MongoDB database, performing some authorisation logic, or handling uploading or downloading files. We will get to the more complex stuff in future, but for now, let’s just keep it basic.
Before We Get Started
Last updated for NestJS 5.0.0
This tutorial continues on from the last tutorial, which covered setting up a basic Ionic application using NestJS as the backend. You do not need to use Ionic/Angular in order to understand this tutorial, you could be using different tech on the front-end, but the tutorial is written with Ionic/Angular developers in mind. Many of the concepts in NestJS are the same as those in Angular, and this tutorial assumes a basic level of understanding of those Angular concepts.
Creating the Provider
The first thing we are going to do is add the provider to our application.
Run the following command to generate the provider:
nest g service services/quotes
By using this generate command, the provider will automatically be added to the imports in app.module.ts, which is required in order to use the provider.
After you have run the command, you will find the basic outline of the provider in src/services/quotes.service.ts.
Making an HTTP Request
The main role of our provider will be to perform an HTTP request and return that data to the controller. We are going to implement three different methods in the provider:
A method to return all of the quotes
A method to return a specific quote by id
A method to return a random quote
Before we can make any HTTP requests, we will need to set up the HttpModule in our NestJS application (just like we would need to set up the HttpClientModule in Angular).
Modify src/app.module.ts to reflect the following:
import { Module, HttpModule } from '@nestjs/common'; import { AppController } from './app.controller'; import { AppService } from './app.service'; import { MessagesController } from './messages/messages.controller'; import { QuotesService } from './services/quotes.service'; @Module({ imports: [HttpModule], controllers: [AppController, MessagesController], providers: [AppService, QuotesService], }) export class AppModule {}
We will also need to inject the HttpService into the provider.
Modify src/services/quotes.service.ts to reflect the following:
import { Injectable, HttpService } from '@nestjs/common'; import { map } from 'rxjs/operators'; @Injectable() export class QuotesService { constructor(private http: HttpService){ } }
Now we will be able to launch HTTP requests through this.http. Notice that we are also importing the map operator here. When we run our HTTP requests we don’t want to return the entire response object, we just want to return the data. We will be using the map operator to modify that response into the format we want. Now, let’s add our methods.
Modify src/services/quotes.service.ts to reflect the following:
import { Injectable, HttpService } from '@nestjs/common'; import { map } from 'rxjs/operators'; @Injectable() export class QuotesService { constructor(private http: HttpService){ } getQuotes(){ return this.http.get('http://quotesondesign.com/wp-json/posts') .pipe( map(response => response.data) ); } getQuote(id){ return this.http.get('http://quotesondesign.com/wp-json/posts/' + id) .pipe( map(response => response.data) ); } getRandomQuote(){ return this.http.get('http://quotesondesign.com/wp-json/posts?filter[orderby]=rand&filter[posts_per_page]=1') .pipe( map(response => response.data) ); } }
The way in which we launch the request is much the same as the way we would do it with Angular, except that here we are explicitly mapping the response to only return the data. Although we don’t usually map responses in Angular, both map and pipe are just a part of the RxJS library and both are available to use in Angular – this isn’t a NestJS specific thing.
Using the Provider
With our provider created, we now need to make use of it inside of our Messages controller. We can do that by importing it and injecting it through the constructor.
Modify src/messages/messages.controller.ts to reflect the following:
import { Controller, Get, Param } from '@nestjs/common'; import { QuotesService } from '../services/quotes.service'; @Controller('messages') export class MessagesController { constructor(private quotesService: QuotesService){ } @Get() getMessages(){ return this.quotesService.getQuotes(); } @Get(':id') getMessage(@Param('id') id){ return this.quotesService.getQuote(id); } }
Our controller remains mostly the same as it was before, except now we are returning a call to the quotes service. We just return the observable returned by the HTTP request directly, and that will be handled by our Ionic application. Unlike in the last tutorial, now our route that accepts the id parameter is actually doing something useful, as it will return a specific quote from the API that matches that id.
Updating the Client
The last step is to utilise these changes in our front-end. We don’t really need to make any changes as we haven’t changed the structure of how our API works, but we will need to request an id that actually exists.
Modify src/app/home/home.page.ts to reflect the following:
import { Component, OnInit } from '@angular/core'; import { MessagesService } from '../services/messages.service'; @Component({ selector: 'app-home', templateUrl: 'home.page.html', styleUrls: ['home.page.scss'], }) export class HomePage implements OnInit { constructor(private messages: MessagesService){ } ngOnInit(){ this.messages.getMessages().subscribe((res) => { console.log(res); }); this.messages.getMessage('2463').subscribe((res) => { console.log(res); }); } }
If we were to serve this application now, we would see a response in the console that looks like this:
Summary
If you are already with Angular, then what we have covered will likely feel like pretty familiar territory. Although we could have easily launched those HTTP requests from within the controller itself, it is a good idea to use providers to handle the heavy lifting in the application – especially as the application starts to become more complex.
What to watch next...
VIDEO
via joshmorony – Learn Ionic & Build Mobile Apps with Web Tech https://ift.tt/2NI8oGc
0 notes
Text
An Introduction to NestJS for Ionic Developers
Creating a backend for your application has typically required a totally different skill set to what you might use for the front end. Over time, those lines have blurred as the likes of NodeJS and server-side JavaScript have risen in popularity. Now, with NestJS, you might not even feel like you are working on a backend at all.
NestJS is a NodeJS framework for building server-side applications. The major thing that drew me towards NestJS was its similarities to standard Angular architecture. You will find a lot of the same concepts used in NestJS as you will in an Angular, including:
TypeScript
Imports/Exports
Services/Providers
Modules (e.g. app.module.ts)
Pipes
Guards
Although NestJS introduces its own unique concepts as well – including additional decorators like @Controller, @Get, and @Post – the general methodology is very much Angular inspired. It seems to be that anywhere that the framework can be like Angular, it is (and that is fantastic).
If you are familiar with Angular, or building Ionic/Angular applications, you are already going to feel comfortable with many of the key concepts for NestJS.
As much as I enjoy building servers with vanilla NodeJS and Express (NestJS uses Express behind the scenes), I feel much more at home with NestJS. NestJS brings that Angular experience to the backend – it’s super easy to get started with built-in generators in the Nest CLI and TypeScript support is included by default.
In this tutorial, we are going to focus on getting a simple project set up that uses Ionic for the frontend and NestJS for the backend. For now, we will just be focusing on a bare-bones “Hello world!” style example. We will not be focusing on exploring the theory of NestJS in-depth, and we will only be covering the key concepts required to get a simple server running. In future tutorials, we will cover other aspects of NestJS.
Before We Get Started
Last updated for Ionic 4.0.0-beta.7 and NestJS 5.0.0
This tutorial will assume a basic understanding of Ionic and Angular. It will also help to have a general sense of how integrating a backend with an Ionic applications works – if you are not already familiar, you might be interested in reading this article.
If you’re not familiar with Ionic already, I’d recommend reading my Ionic Beginners Guide or watching my beginners series first to get up and running and understand the basic concepts. If you want a much more detailed guide for learning Ionic, then take a look at Building Mobile Apps with Ionic & Angular.
1. Create a Client/Server Project Structure
When we are creating an Ionic application with a backend, we are going to require two separate projects: the Ionic project, and the NestJS project.
A structure I like to use is to use a single folder for the entire project, which contains a client folder for the Ionic project, and a server folder for the NestJS project. You don’t need to use this structure if you don’t want to, just make sure that you are not creating your NestJS project inside of your Ionic project (or vice versa).
In order to start a new NestJS project, you can install the NestJS CLI:
npm i -g @nestjs/cli
and then you will just need to run:
nest new server
I used server as the project name here because, as I mentioned, I want the NestJS project to be contained inside of a folder called server – you can supply a different name for the project if you wish.
Once you have generated the NestJS project, you should have a quick browse around the files and folders that were created. As I mentioned, we are going to cover more of the theory stuff in future tutorials, but just from looking around you will likely notice a few similarities between the NestJS project and an Angular (or Ionic/Angular) project.
2. Create a Simple NestJS API
Unlike a frontend client-side application built with Ionic/Angular, a backend/server application primarily performs the function of listening for requests and responding to those requests.
The way in which we would integrate out front-end Ionic application with our backend NestJS server is by making HTTP requests from our Ionic application to the URL of the server where our NestJS backend is hosted. If our NestJS server was running on http://localhost:3000 then perhaps we would make an HTTP request from our Ionic application to http://localhost:3000/messages. Our NestJS application would then receive that request and then it can send a response back to the Ionic application (what that response is will depend on what it is you code the server to do).
In order to set up a simple API that responds appropriately to that request, we are going to need to set up a @Controller in NestJS. A @Controller is a NestJS concept that allows us to set up routes for the application, and those routes can handle responding to requests.
Run the following command to generate a messages controller:
nest g controller messages
This will create a basic controller template at src/messages/messages.controller.ts that looks like this:
import { Controller } from '@nestjs/common'; @Controller('messages') export class MessagesController { }
As is typical in Angular applications, we just have an exported class topped with a particular decorator – in this case, we are just using the NestJS @Controller decorator to identify this class as a controller.
Also note that this controller is automatically added to app.module.ts if you use the generator:
import { Module } from '@nestjs/common'; import { AppController } from './app.controller'; import { AppService } from './app.service'; import { MessagesController } from './messages/messages.controller'; @Module({ imports: [], controllers: [AppController, MessagesController], providers: [AppService], }) export class AppModule {}
Again, this is all rather Angular-esque – instead of using @NgModule NestJS is just using @Module but the general concept remains the same. Modules bundle chunks of functionality together, and in our root module, we are including the various dependencies that will be used throughout the application.
Our controller is going to allow us to listen to and respond to requests on the messages route. In order to allow for GET requests, we will also need to import the @Get decorator and use it to decorate a method that will return a response.
Modify src/messages/messages.controller.ts to reflect the following:
import { Controller, Get } from '@nestjs/common'; @Controller('messages') export class MessagesController { @Get() getMessages(){ return { message: 'In a real example, I would return all of the messages' } } }
By adding the @Get decorator above getMessages, this method will now be triggered when we activate the messages route by making a request to http://localhost:3000/messages. Whatever this method returns is what will be supplied in response to that request. We are just supplying a simple message in return, but in a real application, you might fetch some actual messages from a database before returning a response to the requester.
If we wanted to set up an additional route that would allow us to grab a specific message from the backend, we might do something like this:
import { Controller, Get, Param } from '@nestjs/common'; @Controller('messages') export class MessagesController { @Get() getMessages(){ return { message: 'In a real example, I would return all of the messages' } } @Get(':id') getMessage(@Param('id') id){ return { message: `In a real example, I would return the message with an id of ${id}` } } }
Now we are importing and using the @Param decorator, which will allow us to grab parameters from our routes. Once again, the way in which you supply parameters through routes is very similar to Angular routes – we just prefix the desired parameter with a :. With this additional route defined, we would now be able to make a request to http://localhost:3000/messages/123 and the response we receive will be able to make use of the id that was supplied.
3. Run the NestJS Server
If we now start our NestJS server by running:
npm run start
inside of our NestJS project, and then navigate to:
http://localhost:3000/
We will first see the Hello world! message that the default project generates by default (this code is contained in the app.controller.ts file). However, if we then navigate to:
http://localhost:3000/messages
We will see the message we are returning from our getMessages method:
In a real example, I would return all of the messages
If we then navigate to:
http://localhost:3000/messages/14
we would see the following result:
In a real example, I would return the message with an id of 14
We can see that the server has been able to grab the id we supplied and use it in its response. In a real-world scenario, we would probably use that id to look up a specific record in a database.
Interacting with our server through by navigating to URLs through our browser is all well and good, but this isn’t how we would interact with the server generally. We would be making HTTP requests from our client-side application, which in this case is our Ionic application.
Let’s investigate how to do that.
4. Enable CORS (Cross-Origin Resource Sharing)
Before we can make requests to our server (in development at least), we will need to enable CORS (Cross-Origin Resource Sharing). By default, requests from one domain to another are blocked unless the server specifically allows it. Since our Ionic application will be running on localhost:8100 and the server will be running on localhost:3000 our requests from Ionic to NestJS will be blocked.
If you want to know more about what CORS is exactly, I would recommend reading Dealing with CORS (Cross-Origin Resource Sharing) in Ionic Applications.
Enabling CORS in a NestJS server is simple enough, we just need to add app.enableCors() to the main.ts file in our NestJS project:
import { NestFactory } from '@nestjs/core'; import { AppModule } from './app.module'; async function bootstrap() { const app = await NestFactory.create(AppModule); app.enableCors(); await app.listen(3000); } bootstrap();
Make sure to stop and re-run your server after making these changes:
Ctrl + C
npm run start
5. Integrating a NestJS API with an Ionic Application
All we have left to do now is to make the request from our Ionic application to the NestJS server we have running (you do need to make sure that you keep it running, otherwise the request won’t work).
Create the following service to interact with the NestJS API:
ionic g service services/Messages
We will also be making use of the HttpClient library, so make sure that you have the HttpClientModule set up the root module file for your Ionic project.
Modify src/app/services/messages.service.ts to reflect the following:
import { Injectable } from '@angular/core'; import { HttpClient } from '@angular/common/http'; import { Observable } from 'rxjs' @Injectable({ providedIn: 'root' }) export class MessagesService { constructor(private http: HttpClient) { } getMessages(): Observable<Object> { return this.http.get('http://localhost:3000/messages'); } getMessage(id: string): Observable<Object> { return this.http.get(`http://localhost:3000/messages/${id}`); } }
We’ve just created two simple methods that will make our HTTP requests to the server for us. Now, all we need to do is make use of these somewhere – as an example, we are just going to add it to the ngOnInit hook for the home page.
Modify src/app/home/home.page.ts to reflect the following:
import { Component, OnInit } from '@angular/core'; import { MessagesService } from '../services/messages.service'; @Component({ selector: 'app-home', templateUrl: 'home.page.html', styleUrls: ['home.page.scss'], }) export class HomePage implements OnInit { constructor(private messages: MessagesService){ } ngOnInit(){ this.messages.getMessages().subscribe((res) => { console.log(res); }); this.messages.getMessage('12').subscribe((res) => { console.log(res); }); } }
If we were to serve our Ionic application now (whilst the NestJS server remains running) we would see the following values output to the console:
As you can see, both requests have received a successful response from our NestJS server.
Summary
We have just scratched the surface of NestJS, so there will be plenty more tutorials to come in the future that will cover all sorts of concepts and examples. The good news is that if you already know Angular, then you already know a lot about NestJS. In the meantime, it is always a good idea to have a read through the official documentation.
What to watch next...
VIDEO
via joshmorony – Learn Ionic & Build Mobile Apps with Web Tech https://ift.tt/2Chq71U
0 notes