DEV Community

Cover image for Why Mandarine is by far the best server-side framework in Deno
andreespirela
andreespirela

Posted on

Why Mandarine is by far the best server-side framework in Deno

Mandarine is an open-source typescript framework that runs on Deno. Mandarine is used to develop any type of server-side application (Mostly MVC) with the use of strong design patterns such as Dependency Injection, or the SOLID principles.

From Mandarine's website:

A minimalist, decorator-driven, MVC framework for Deno.

On this post, we will cover why Mandarine is perhaps, the best server-side framework in the Deno community. I admit, it's a hot take to describe Mandarine as such, but I will defend these points throughout the post.

Deno, not NodeJS.

We have to start from this point. NodeJS as you may already know is meant to work with Javascript and yes, you can make it compatible with Typescript as well, but NodeJS itself was not created under a Typescript paradigm. Unlike Deno, Deno was fully created to support typescript out of the box, most Deno applications are written in Typescript and this will continue to be this way. As Ryan Dahl (Creator of both NodeJS & Deno) stated:

Alt Text

The reason I address this is because I keep seeing packages in Deno that are written in Typescript but they have the same kind of code a Javascript code could have & this is really an issue because people are just trying to think in a "Javascript way" inside a Typescript environment which definitely stops the development of more powerful features & stops the limits of our imagination in a Typescript environment. I keep seeing people coding the "equivalent" of a NodeJS package in Deno and while this may be good at some extend, I can't stand the fact that the "Javascript way" is being kept in many Deno packages.

Mandarine changes this. Mandarine takes advantage of every single feature Typescript has to offer, from generic classes inside Mandarine's core, to the use of Decorators & Metadata reflection for the creation of Mandarine-powered applications.
Mandarine tries to get as far away as possible from a Javascript thinking in a Typescript runtime. Typescript really are not just Types, Typescript has an extensive core of solutions for design-patterns and functionalities that many developers are not taking advantage of which is something Mandarine is looking forward to changing.

A simple quickstart for Mandarine
(A simple quickstart in Mandarine)

Strong Design Patterns

Mandarine believes in the strong use of Design Patterns as well as the benefits of Object-Oriented programming. Mandarine makes use of two important design patterns: Dependency Injection & MVC in order to provide the most SOLID development.

Mandarine is well-known because of its dependency injection system. Among only 3 frameworks that support Dependency Injection in Deno, Mandarine has perhaps the most stable approach. It allows dependency injection by both construction-based & property-based with the benefit of property-based injection not having to specify what type we are trying to inject like in Angular or NestJS where property injection needs to receive a token (type). Also, another +1 for Mandarine's dependency injection system is the fact there is no such thing as a "Module": If you come from Angular or NestJS for back-end, you will know dependencies usually go under the concept of "Module" and through Modules is the way your application communicates with other components. In Mandarine such concept does not exist since everything in Mandarine is either a Mandarine-powered component or not and so by the time you use the dependency declarator-decorators such as @Controller, @Service, @Component, @Configuration or others that component is immediately available for injection at other Mandarine-powered components. If you come from a Java environment, you probably know about Spring Boot, most likely, you have used. Mandarine uses the same concept of dependency injection that Spring Boot has.

Built-in Tools

Mandarine has a set of built-in tools that allow back-end development to be easier, not only in terms of design patterns as we mentioned before, but in terms of common features that are highly used.

  • Template Engine: Mandarine supports EJS & Handlebars out of the box. More about Mandarine's template engine here
  • Session Middleware: Mandarine has full support for session middleware (including a default in-memory implementation & the possibility to re-write this implementation). See more here
  • CORS Middleware: Mandarine has a CORS middleware out of the box that is not only available for endpoints but also for resources. See more here
  • Static Content: Mandarine has full support for static-content serving, fully customizable. See more here
  • Resource Handlers: Mandarine has full support for adding, overriding and creating Resource Handlers. Resource Handlers are the logic behind serving static content. The possibility to customize the behavior of this allow different interpretation and outcomes for different types of URL, for exmaple, with Resource Handlers you could add a logic to process all the .xml files and convert them to .json by the time of the request. See more here
  • ORM: Mandarine has a built-in ORM which takes away the complexity of writing SQL queries or the complexity of having chain-like ORM's. Mandarine brings the concept of MQL (Mandarine Query Language) to write complex queries.

Built-in ORM

Mandarine's built-in ORM is perhaps my favorite feature. It allows you to write SQL queries in the same way you would in frameworks like Spring Boot. With the concept of MQL, much of the functional (or SQL) boilerplate code is taken away.

Where

findByAirlineAndPassengerName(airline: string, passengerName: string)

is transformed into

SELECT .... WHERE airline = $1 AND passengerName = $2

# $1 = airline parameter
# $2 = passengerName parameter

Here is a clear implementation of how this works:
Alt Text

For more information about Mandarine's built-in ORM Click here
For more information about Mandarine's MQL Click here

Native Components

Mandarine brings the concept of Native Components to Typescript. Native components are classes that Mandarine uses as default to boost the framework. These classes usually have some sort of information related to the different behaviors of the framework. For example, in Mandarine, there is the native component WebMvcConfigurer which has the behavior of how the session container (for the session middleware) will behave, it also has information about the default resource handlers (used for serving static content). With the concept of Native Components, Mandarine allows the developer to override (through @Override) and establish custom behaviors in a OOP way, making it not only straightforward but readable in terms of lines of code to execute such thing.

See more about native components here

Alt Text


Decorator-driven

Many of you may know the express syntax, which is something like

new Router().get('/route', (context) => {});

This syntax is widely used in the NodeJS community as well as the Deno community. In Deno, we have several frameworks that take use this approach such as Oak or Pogo. While this approach may be found straightforward, it really sticks to the way we write javascript & as I mentioned before, I believe a Typescript ecosystem should make use of all its Typescript features, otherwise, what's the point behind using typescript really?. Mandarine takes a different view and creates your routes through the use of decorators such as @GET, @POST and so on, similar to NestJS or Spring Boot.


2.0.0

Just to make the last remark about why Mandarine is perhaps the best server-side framework by far in Deno, Mandarine has announced the list of features that will be available in version 2.0.0 (expected to land during last week of August 2020, or first two weeks of September 2020). These features include:

  • Native support for built-in authentication & user handling.
  • Custom Decorators
  • Exception Filters
  • Pipes
  • Guards
  • CRON Jobs

You can read more about these features and what they mean in this blog

Conclusion

We have deeply analyzed some of the most important features that divide Mandarine from the rest of server-side frameworks in Deno. The opinions behind whether Mandarine is really the best server-side framework in Deno will be different for every person, although we can state the fact that Mandarine accomplishes a better interaction between a modular application through enforcing principles such as SOLID or MVC. On the other hand, a opinion-driven thought is whether enforcing OOP programming and making use of all typescript features is really a good thing. Some would argue that Javascript is the way it is and it should be written that way, my take really goes to: If Javascript is what it is, why did we even invent Typescript?, and what I'm saying with this is that in a Typescript environment, you should think in a Typescript way: interpreting Typescript as only types is fundamentally wrong.

This post is not meant to cause any controversy on the different contributions people have made to Deno rather than presenting both facts & views to how Mandarine can get to solve different issues in a enterprise-like way, not only technically speaking but also theoretically speaking.

The different comparisons made to different frameworks such as Angular, NestJS, Pogo or Oak do not refer to facts rather than opinions on what a better approach looks like. While it is true that these frameworks do things the way they do it for a specific reason which has been thought by knowledgeable developers, it is also true that every approach can have a better approach which is exactly what I am dressing in the different comparisons and their final objective.

It is clear that every developer has a preference towards a coding style, some will prefer decorators, others would prefer functional-like declaration. Every opinion on the matter is of course appreciated by this post.

Want to know more about Mandarine?: Try Mandarine's quickstart example.

Thoughts? I'd like to know them, comment below.
Questions? I'd like to answer them, ask below in the comments section.

Latest comments (7)

Collapse
 
lalitkale profile image
Lalit Kale

This looks similar to nestjs just on deno side.

Collapse
 
mgrabov profile image
Iliya Grabovetskiy

nice stuff!

Collapse
 
andreespirela profile image
andreespirela • Edited

Had a good mentor! I'll hit u up on LinkedIn one of these days! Appreciate this comment

Collapse
 
khrome83 profile image
Zane Milakovic

@andreespirela , great write up, thank you.

I am still not clear on the benefits of a @GET('/route') vs .get('/route')

This seems overly verbose. More lines of code mean its harder to maintain. While I do think enterprises will benefit from the rigid structure, I don't think this works as well for smaller projects.

I can totally see the benefit of being familiar with SpringBoot developers. But coming from python and node, I am having trouble drawing out the benefits from the extra syntax. Yep, it for sure uses Typescript. But classes are really not that great and are less performant that functions last I checked.

Is the benefit just the organization and rigid structure, outside of personal preference?

Purly asking about the syntax, and choice of class with decorators. I am all in on Deno myself. =)

Collapse
 
borsemayur2 profile image
Mayur Borse

I feel the same way

Collapse
 
andreespirela profile image
andreespirela

Well, it really depends on how you feel about decorators as mentioned before. For me, and for many people (I personally come from a Java environment) decorators make the code more readable, when you have functional references like router.get(), the boilerplate can get real big in terms of expansion and nested routes, the use of router.get() forces you to have all your routes (or main routes) in a single file. With Decorators such as @Controller and @GET you can divide your business logic and controller logic into multiple files which at the end will be processed by Mandarine. Also, the use of decorators is not only about routes but injection (strong design patterns), Mandarine uses decorators at all levels, if you look at this table among with the examples on the link, you can see how Mandarine injects values through the use of you calling it per se, making your code more automatic, and your business logic will be reduced to many lines of codes at the end, the idea behind this is that decorators can process variables so when the variable reaches the business logic is already processed with that said, while decorators can seem to have boilerplate, the benefits in the long-term are really related to pre-processing and having a great reduction of common logic and common code in the business logic.

While it is true that classes are less performant than functions, it really depends on how you load & call classes, the performance of a class and a function is really slight (in Mandarine). In the case of Mandarine, every component in the dependency injection container (including controllers) is a singleton, which means, Mandarine does not have to create a new object rather than just call it as if it was a regular function so in terms of performance, classes do not really affect the outcome, in fact, they can offer a better coding environment inside a OOP related-style (Of course, if you are more of a functional programming person, you will totally prefer functional programming).

The benefits from a enterprise perspective is really what plays a role here, having your application divided into multiple classes and controllers without having to have the main logic (let's say the main controllers) in a single file plays a huge role on how you organize your application which is one of the points Mandarine tries to cover.

In a nutshell, while it is true that there are no "facts" when it comes to the benefits of one or the other, organization & the extend & benefits of using decorators in the long term will save you a lot of code and business requirements, the very fact that through decorators you can know the metadata of a parameter, function or class at compile time makes your code have so much less boilerplate and more pre-processing (as described), the effects of these will not be of course visible in very small projects, but the benefits of these will be required in long-term or large projects.

Long answer, hopefully it's worth the read.

Collapse
 
khrome83 profile image
Zane Milakovic

I really appreciate the write up. Thank you!