DEV Community

Cover image for The only API stack (and workflow) you should be using.
judehunter
judehunter

Posted on • Edited on • Originally published at judehunter.dev

The only API stack (and workflow) you should be using.

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:

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

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

  // automatic date columns!
  @CreateDateColumn()
  createdAt: Date;
}
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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! 🎉

Top comments (9)

Collapse
 
madza profile image
Madza

I feel like TypeScript is most appealing to two kinds of devs - those coming from statically typed languages like C, C++, Java, Rust, Go, Scala or those developing projects in JS (or other dynamically typed languages like Ruby, Python, PHP) to the degree that static typing becomes a necessity to debug and manage codebase more easily.

Collapse
 
judehunter profile image
judehunter

Don't forget C#, since C# and TypeScript were both created by the same guy!
I love to look at the similarities in these languages.

Collapse
 
cwraytech profile image
Christopher Wray

So, you are only talking about NodeJs backends, right?

Collapse
 
judehunter profile image
judehunter

Sure, the article focuses on Node. However, I feel like Node (+JS) has dominated the web industry and it's a go-to language at this point.

Collapse
 
cwraytech profile image
Christopher Wray

I know it has dominated the blog industry, but is it really dominating actual backends being developed?

I think if you look you will find a good majority of great companies are using Ruby on Rails, Spring, DotNet, or Laravel and are completely happy with that choice.

Collapse
 
netlancer profile image
Ellie

Why not resort to higher abstraction frameworks then, like nest.js with its ready made toolings, app architecture in place, typescript coding and i'm sure there's an orm thing in a package ..?

Collapse
 
judehunter profile image
judehunter

So, funnily, I came up with this toolset and workflow after tinkering with Nest.
I tried building an API in it and it was so overly complicated, because it is meant for extreme scalability, with dependency injection and modules to separate different parts of the api.

My toolset is more of a devops one, and is meant for rapid development and fairly small APIs.

Collapse
 
dylanesque profile image
Michael Caveney

I do agree with you about GraphQL being overkill in a lot of cases, but you can move pretty fast with Hasura as a back-end once you're familiar with the basics of it.

Collapse
 
judehunter profile image
judehunter

I'm waiting on Prisma 2 to be out of the beta!
That may be just enough for me to try a GraphQL api again!