Raising the Performance with Node.JS for backend development
by Seven Peaks on Nov 12, 2021 11:05:00 AM
On November 10, 2022, at the Seven Peaks office, there was a Seven Peaks Speaks: Raising the Performance for Your Node.JS Backends meetup. Our backend developers organized the event to present what you should know about backend programming and how to use Node.JS for backend development effectively in your upcoming project.
This time we have Sijan Shrestha – our senior full-stack developer as our first speaker.
Then our second speaker is Denis Pshenov – our Tech Lead for Node.JS.
What is Serverless?
When starting out as a backend developer, understanding Serverless is essential.
Serverless is a cloud-native development model that allows developers to create and launch applications without being concerned about managing servers.
Previously, functions in Amazon Web Services (AWS) were the core objective for it but currently it is a database, messages (SQS and SNS), and storage.
The benefits that make Serverless a convenient model are that developers can only pay for the services they use to reduce cost.
Also, it is highly available because it is not stored on an origin server. So, the application’s code can be deployed from any place.
Last but not least, serverless infrastructure-based applications will scale automatically as their user bases or levels of consumption develop.
Then, what is Lambda?
Lambda is a virtual function service that allows you to create applications that respond swiftly to events and new information.
It is a completely managed service that manages all of your infrastructure needs. Therefore, it not only can save you time on operational tasks but is also affordable.
Basically, when the function is invoked, it creates a particular space to run the code and scan it automatically.
How do you deploy your code?
One of the simplest ways to deploy a piece of code is to directly go to the AWS console and use the integrated IDE (integrated development environment). However, this is not a recommended approach.
There are plenty of better approaches to deploying code; for example, by using IaC (infrastructure as a code). Additionally, one of the most popular and widely used IaC tools is Terraform.
Another IaC tool is the Serverless Application Model (SAM) that is provided by AWS. SAM is a framework that is freely available for developing serverless applications.
It includes a shorthand syntax for expressing functions, databases, APIs, and mappings of event sources.
The tool helps you build serverless applications more swiftly since SAM expands and transforms the SAM syntax into AWS CloudFormation syntax during deployment.
However, it is not considered developer-friendly and is difficult to work with. Therefore, the Serverless Framework is a better option, as Sijan suggested.
Serverless Framework is a Node.js-based web framework that is not only open-source but also free. It is the first framework that was built for developing applications on AWS Lambda.
Furthermore, the serverless framework is an IaC-specific tool for AWS Lambda.
CloudFormation is a tool that helps in modeling and setting up AWS resources into Cloud Formation templates.
Therefore, you can spend more time focusing on your AWS-running apps and less time managing those resources.
Also, AWS understands CloudFormation natively, which creates the infrastructure from a file. Explaining that, serverless framework uses a simple readable yaml file, and converts or transforms it into a cloudformation template that AWS understands.framework
The examples of CloudFormation and serverless include the following:
Suggestions to Node.JS for backend development
When adopting Node.js for a backend development project, Middy is a fairly simple middleware engine that helps you to simplify your AWS Lambda code.
Whether you have experience with web frameworks like Express, you will be familiar with the concepts within Middy and be ready to start shortly.
A middleware engine helps you focus on the key business logic of your Lambda and then add additional parts like authentication, validation, authorization, serialization, etc. by decorating the key business logic in a modular and reusable approach.
Within bigger teams, the approach of deploying various services in a single repository is very typical.
The objective of Serverless Framework Compose is to simplify the deployment and management of a variety of services, such as:
- Deploy many services concurrently
- Provide services in a specified order
- Run commands across various services
- Share outcomes from one service to another
Developers normally recommend using Serverless Compose. The reason is to avoid issues while waiting for deployment.
As a developer himself, Sijan also proposes a few often used plugins, including serverless-webpack, serverless-offline, and serverless-api-gateway-caching.
- Serverless-webpack is to transpile the code.
- Serverless-offline is to run the code locally.
- Serverless-api-gateway-caching is to enable code caching.
The examples are attempting to add a number to a string and anticipating a numeric result.
Therefore, to ensure that type assertions made in the code are followed and to detect bugs, some type of compiler or checker is used.
Defining the ends in the pursuit of end-to-end type safety is starting with a client. A client could be on any platform, including a web browser, an application, or a mobile application.
The client is calling APIs, which are basically a running server returning some response. So, you have both a request and a response.
This means that you now have a database somewhere and a request response.
“Any organization that designs a system will produce a design whose structure is a copy of the organization’s communication structure.”
This is a structure that you will have on a bigger project. There will be a backend team that builds APIs and databases. The web team is responsible for the website, and the android team is doing the application. Also, the service team will be responsible for a microservice.
All of the mentioned teams have to communicate with each other, so the question is how are they going to communicate the funds? How are they going to describe each other? What are request and response structures? Here are some pain points that you may face:
- Inefficient communication between teams
- Bugs and bad developer experience due to lack of types
- Difference between client and server type
- Duplication of effort spent on manually typing each client
Design First Approach
The traditional solution to solve the problems is the “design first” approach. Explaining that you have to design and document your API by writing and categorizing documentation, followed by implementing the server and client based on it.
The typical tool is an OpenAPI such as Swagger. It allows you to write your API documentation and API design specs in YAML files.
Then you will have a website where you can share this documentation to send to your teams.
This will help your teams implement it on the client and the server based on this documentation. Therefore, we are able to solve our first pain point, which is inefficient communication between teams.
However, the bugs still exist and do not have types. Hence, you need to write manual types based on the documentation you created.
The reason you have to do it is for the serene deployment and to get cookie requests, cookie responses, etc.
Typed Client is typically a type of plan that helps you with cookie functionality, including request and response. Then you will be able to fetch something from your cookie API.
This will help you solve the second problem, which is bugs and a bad developer experience due to a lack of types.
Keeping Types Aligned
However, one thing to consider is keeping the types aligned between server and client. Here are some ideas from our second speaker, Denis:
- Expose types via npm package
- Use monorepo
- Generate types from OpenAPI
Inspect the First Approach
For the workflow, the first thing is to inspect the first approach by following these steps:
- Write OpenAPI specs
- Generate types, clients, and server
- Use types to implement server
Code First Approach
Another option for the first approach is to write code or run a server by following these steps:
- Implement or stub server
- Generate OpenAPI specs
- Generate client from OpenAPI
These will allow you to solve the remaining pain points, which are the differences between client and server types and the duplication of effort spent on manually typing each client.
GraphQL is a query language and server-side runtime for APIs. Its priority is providing clients with only the data they want and nothing more.
gRPC is a reliable RPC (Remote Procedure Call) framework used to create scalable and swift APIs. It allows for the development of networked systems and transparent communication between server applications and clients.
tRPC is a light library that helps you develop fully typesafe APIs without the use of schemas or code generation.
It offers type sharing between the server and client and only imports the types, not the actual server code. Hence, the frontend is not accessible to any of the server codes.
You can detect issues between your frontend and backend at compilation and build time with end-to-end type-safety.
CodeDeploy is a tool that automates code deployments to any instance and on-premises servers. This lets you control everything from one place and reduces the amount of downtime.
Zodios is a REST API toolbox with end-to-end type safety. With a simple, understandable, and declarative syntax, you can use it to develop a REST API.
Here are some other benefits of using Zod:
What about database?
In terms of end-to-end type safety, the database is considered the other end. From Denis’s point of view, there are two highly recommended databases.
The first one is Prisma, Prisma is a kind of functionality that gives excellent developer experience with a super typesafe.
Another one is MikroORM. MrikroORM might be more complicated to use, but it has good safety features.