The only API stack (and workflow) you should be using.
Tags: node, javascript, webdev, devops
Published: 2020-09-13 01:09:11

Over the years, I've tried multiple Node.js back-end technology stacks, and I can finally say I've found a suitable one that will help you rapidly develop your projects (and kickstart your startups!).

### **The REST framework**
**Why?** I've extensively used both REST and GraphQL back-ends and I believe GraphQL is an overkill in most cases. While it's great for scalability, it is not the fastest way to develop an API for your project.

My REST framework of choice is **koa.js**.
**Why?** I believe it's one of the best frameworks when it comes to quick development of your API, since it makes it extremely easy to go from the idea to the implementation.

The middleware stack is also very intuitive and relies on async/await.

I also feel it's a lot better than Express and generally more lightweight.

### **TypeScript**
**Why?** It is an extremely good and easy way to make your API type safe and develop more rapidly in the long run. It has saved  me a lot of headaches and I could not live without its IntelliSense suggestions.

You'll also see that using TypeScript enables us to easily integrate `TypeORM` into our project.

### **ESLint**
**Why?** Consistency goes a long way. ESLint makes sure you and your co-workers don't yell at each other over code that - in their opinion - is not properly formatted. It can also track things like unused variables/imports and usages of `let` instead of `const`.

### **The Database**
This depends on your use case. However, there are only two database types you should care about - relational and document-based databases.

If you're not sure,
I'd say for smaller projects you'd want to go with a document-based database, like MongoDB.
However, when your project grows, you'll probably have certain relations between your entities. And thus, you should use a relational database, like MySQL or PostgreSQL (which is my database of choice).

### **TypeORM**
*For MongoDB, Mongoose may be more suitable.*
**Why?** TypeORM is an Object-Relational Mapping library for typescript (and babel), which basically means you don't have to deal with raw SQL and you can use certain utilities, like automatic relation joining.

The reason why TypeORM is so interesting is the fact that it uses decorators for entity synchronization. What that means is you won't have to use migrations in your development environment.

Instead, you define a class and decorate it:

```ts
@Entity()
class User {
  @PrimaryGeneratedColumn('uuid')
  id: string;

  // automatic type detection thanks to reflection!
  @Column()
  name: string;

  // automatic date columns!
  @CreateDateColumn()
  createdAt: Date;
}
```

TypeORM then uses that class to migrate the database and to make IntelliSense suggestions based on the fields.

**Why not?** Frankly, TypeORM is not beginner friendly, largely due to the docs being quite horrible. However, when you get a hang of it and use IntelliSense to your advantage, it becomes an incredibly powerful tool.

### **Git Flow**
**Why?** This is a certain philosophy/workflow/strategy that works particularly well when working with git in teams (not particularly needed if you're not in a team). 
It defines what branches should be used for certain things, like features, releases, hotfixes.

### **.env**
**Why?** Using `.env` files for defining your environmental variables is pretty much a standard now. It lets you define different variables for your local machine and for the machine you're hosting your project on.

Do not forget to add `.env` to `.gitignore`!.

### **File structure**
I came up with a file structure that works well with this particular technology stack:
```
src
├── entities
│   └── User.ts
├── modules
│   └── module-name
│       ├── module-name.router.ts
│       ├── module-name.service.ts
│       └── module-name.spec.ts
├── mw
├── utils
└── app.ts

e2e
└── test-name.e2e.ts
```

Going from the top:
- The `entities` folder is where you should store your TypeORM entities
- The `modules` folder holds the different modules of your application (inspired by NestJS). For instance, an `auth` module may have a router that has a `/auth/facebook` route which in turn calls the `authorizeWithFacebook()` function in the service file. It's important the router handles the HTTP stuff, and the service deals with pure data. This way, your unit tests (`.spec.ts`) can call the service directly. Additionally, your routes should - most of the time - be prefixed with the module name.
- The `mw` folder is where you should store your custom middleware. You could also use the `utils` folder for this.
- The `utils` folder is pretty much every other function that doesn't fit anywhere else.
- The `e2e` folder stores the end-to-end tests.

---

This workflow has proven most successful for my projects and is great for rapid development.

Don't agree with me? Start a discussion in the comments!

Happy coding! 🎉