A Nest crash course for Rails people

Zoe Friedman
6 min readNov 24, 2021

--

The Nonprofit Exchange Hub (NEH) is working to build a full stack application to facilitate the exchange of resources between nonprofits, charities, etc. We’re a team of volunteers, but a recent influx of us came from the Flatiron School, where we specialized in Ruby on Rails to develop our backend APIs.

Our NEH backend, however, is built with Nest.js, a JavaScript framework. More specifically:

Nest (NestJS) is a framework for building efficient, scalable Node.js server-side applications. It uses progressive JavaScript, is built with and fully supports TypeScript (yet still enables developers to code in pure JavaScript) and combines elements of OOP (Object Oriented Programming), FP (Functional Programming), and FRP (Functional Reactive Programming)…While plenty of superb libraries, helpers, and tools exist for Node (and server-side JavaScript), none of them effectively solve the main problem of — Architecture.

Nest provides an out-of-the-box application architecture which allows developers and teams to create highly testable, scalable, loosely coupled, and easily maintainable applications. — Node docs

I wrote my first line of code, perhaps a year ago, and Rails is all I’ve ever known when it comes to backend architecture. And there’s a good portion of us on the dev team in a similar boat. So I thought I could make a resource for people like me, new to the dev team, new to Nest, and coming from a background in Rails. This should give you a brief overview of the parallels!

JavaScript & TypeScript : Nest :: Ruby : Rails

Nest allows us to incorporate TypeScript into our backend. So we’re going to see a lot of TypeScript here that will require some explanation. So if TypeScript is totally new to you, I’ve written an introduction on it: “What is TypeScript & Why Bother?.” But briefly explained, TypeScript is an additional layer we add to our JavaScript that adds type gatekeeping to our functions, arguments, and return values. It also allows us to create our own type objects that we can use throughout our application called “interfaces.” It’s worth noting that files that were once .js files will now be .ts files. And within these files you’ll be able to see type errors straight away, which is extremely helpful. (note: If you’re having a look in our frontend (i.e. React & TypeScript), the files will be .tsx)

TypeORM : Nest :: ActiveRecord : Rails

There is an important piece to our backend puzzle I’d like to note as well out of the gate. Nest works fine with any Object Relational Mapping framework (ORM), but it works especially well with TypeORM out of the box, and that’s what we’re using at the NEH. The rails equivalent here is ActiveRecord. It’s not a direct A/B comparison, but they are both ORMs, and TypeORM is the library that we’re going to be using here. It allows us to interface with Sqlite, Postgres, etc. Eventually once everything is wired up, by setting “typeORM synchronize” to TRUE in our TypeOrmOptions during development, the tables will be created automatically in our database, without having to create manual migrations. Once we go to production, we will switch to manual migrations, but it is a very cool feature of Nest/TypeORM that this can happen automatically.

Module : Nest :: XX : Rails

The structure of Nest apps are organized by modules. And the base of your Nest app is your root module. Typically this is called the “Application Module.” Within your module you will specify imports to other modules you’ll want access to, define the controllers you will be using, and in child modules, you may also be connecting your service . Rails doesn’t really have an equivalent for this. Hence why Nest is so braggy about their architecture (among other things).

Entity, Repository, & Service : Nest :: Model : Rails

It takes a few components to get the “model” equivalent in Nest up and running.

Entities: An entity defines a single kind of resource. It’s a lot like a model in Rails. However, unlike in Rails, it explicitly defines all the properties. So let’s say we’re creating an entity class for “Organizations.” We define the properties and types we want to see for each organization in our entity file.

organization.entity.ts

“Wait, what are decorators?” you might be asking.

“Nest is built around a language feature called decorators. Decorators are a well-known concept in a lot of commonly used programming languages, but in the JavaScript world, they’re still relatively new. In order to better understand how decorators work, we recommend reading this article…You apply it by prefixing the decorator with an @ character and placing this at the very top of what you are trying to decorate. Decorators can be defined for either a class, a method or a property.”Nest docs

We then connect the Organization entity to the corresponding Organizations module. When we connect THAT to the App module, Nest and TypeORM will behind the scenes, create an Organizations repository for us that we won’t even see. (note: there is more than one way to create a repository!)

Repositories: The Organizations repository will have built in methods to save, create, update, find, delete, etc. instances of organizations in our database. You can see all of the functionality repositories give us here!

Entities, however, don’t have class or instance methods, and you will remember, our models in Rails housed helpful methods we could call on our classes or instances. So where does this type of logic live in Nest? How can we use the save, create, update, find, and delete methods in my newly created repository? How can we create new custom methods? By adding a service.

Services: We use dependency injection to hook up our repository to our service. This ensures that our service has a copy of the repository. The syntax in the constructor is a bit confusing, but ultimately we’re creating a repository variable that points to a type annotation of our organization. The InjectRepository decorator says that we need an instance of the Organization repository in this class at run time. Then we will have access to our create, findAll, findOne, update, and remove functions:

A lot of additional TypeScript annotation here! And another concept we haven’t addressed yet: Dto’s! We’ll get there.

Controller : Nest :: Controller : Rails

Here’s a relief! Controllers in Rails and Controllers in Nest serve extremely similar purposes. Controllers are going to be receiving requests, routing us to to our CRUD actions:

Here we’ve used decorators to route to our specific HTTP requests in a pretty readable way. The argument passed in, being the endpoint for the request. So for example, in our Get(‘:id’) path we have a function called findOne that will pass in an id that will be of type string and it will return the resolution of a promise that will be an organization entity. The logic inside of the function calls upon the organizationsService to findOne with that id passed down as an argument.

So now it may seem a little redundant, but suffice to say that the controller is handling the routing and the service is handling the actual execution. Eventually, our controller and service will be a bit more fleshed out distinctively—and the Nest “controller” will seem more like a Rails “controller” and the Nest “service” will seem a bit more like a Rails “model.”

Next up I will be addressing DTOs (Data Transfer Objects), so stay tuned!

--

--