Giter VIP home page Giter VIP logo

node-typescript-boilerplate's Introduction

NodeJs/Typescript API Boilerplate

Open Source Love GitHub issues GitHub stars GitHub forks GitHub license

To Contribute

Please feel free to contribute to this project. To contribute, please follow this instructions

Running the app

NOTE: These instructions require MongoDB and Node.js to be installed on your environment.

Clone the Repository

git clone https://github.com/ofuochi/node-typescript-boilerplate.git
cd node-typescript-boilerplate

Install Dependencies

npm install

Copy Files

Sample env File into a .env File

Copy the sample environment file to a new environment file that holds the sensitive settings of your application.

cp env.sample .env

Run the App

npm run start

Or run in development watch mode. This uses nodemon to watch for file changes.

npm run dev

DB Seeding

The first time the application runs, MongoDB is seeded with default Tenant and default Admin User.

  1. Default tenant name is Default (obvioulsy)
  2. Default admin login detail;
    • Username: admin
    • Password: 123qwe

Swagger API Documentation

Open the URL http://localhost:3000/api-docs to view the the swagger documentation of the endpoints.

This will contain all the endpoints you expose to the client. Once you add a new endpoint, this endpoint will automatically be added! How cool is that?๐Ÿ˜Ž. Concentrate on building the functionality and business logic of your application. Swagger will do the documentation for you!.

Since this is a multi-tenant application, to authenticate (sign-in or sign-up), you need to pass a tenant ID in the header so that the application will know which tenant you are referencing during authentication.

To get the tenant details call the "get tenants" endpoint. For example, to get the details of the Default tenant, I'll call the endpoint http://localhost:3000/api/v1/tenants/default. Good thing is, you can do this directly on Swagger!

Run Tests

Run test once

npm run test

Or re-run test on every file change (watch mode)

npm run test-watch

REST Services

The application exposes a few REST endpoints which require you to pass x-tenant-id header. First, call the tenant endpoint /api/v1/tenant to get all the available tenants. Use any of the tenant IDs as the value for x-tenant-id

  • HTTP GET /api/v1/tenants
  • HTTP GET /api/v1/tenants/:query
  • HTTP GET /api/v1/secured (Requires a valid x-auth-token header)

You can use the following code snippet to call the secured endpoint:

fetch("http://localhost:3000/api/v1/secure", {
	method: "GET",
	headers: {
		"Content-Type": "application/json",
		"x-tenant-id": "TENANT_ID",
		"x-auth-token": "SOME_VALID_CREDENTIAL"
	}
})
	.then(r => {
		if (r.status === 200) {
			r.json().then(j => console.log(j));
		} else {
			console.log("ERROR", r.status);
		}
	})
	.catch(e => console.log(e));

You can use the following code snippet to call the secured endpoint with an invalid x-auth-token header:

fetch("http://localhost:3000/api/v1/secure", {
	method: "GET",
	headers: {
		"Content-Type": "application/json",
		"x-tenant-id": "TENANT_ID",
		"x-auth-token": "SOME_WRONG_CREDENTIAL"
	}
})
	.then(r => {
		if (r.status === 200) {
			r.json().then(j => console.log(j));
		} else {
			console.log("ERROR", r.status);
		}
	})
	.catch(e => console.log(e));

node-typescript-boilerplate's People

Contributors

artfuldev avatar dependabot[bot] avatar ezesunrise avatar fabianopb avatar irmerk avatar ofuochi avatar rugglcon avatar tayormi avatar tingwei99 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

node-typescript-boilerplate's Issues

Standardize response returned to client.

Return a standard response to client in all controllers. All response could inherit from a BaseResponse class that have useful properties which will be used as a standard for returning responses to client.

Create Issue Workflow

Description

There currently isn't a standard for creating issues.

Why do we need this?

Bug Reports ๐Ÿ›

To help maintainers resolve issues as quickly as possible it is important that we communicate effectively

Feature Requests ๐Ÿ“ฆ

To communicate clearly the feature details and reduce the debt of rework/refactoring

Community Questions ๐Ÿค”

In an open-source community, everyone's voice should be heard clearly

Enforce named exports (eslint)

Named exports are a better idea than default exports because they enforce consistent naming while importing - especially in TypeScript.

Enforce named exports in the linting (eslint) rules.

Add tenant service.

Add tenant service class/methods to make the tenant controller cleaner. Take a cue from the AuthService class here.

Implement role based permissons

Add a Permission entity that should have a list of role IDs.
The idea is, a Role can have one or more Permission that restricts what a User with that role can or cannot do.

Consider using "tsoa" instead of "inversify-express-utils"

Question

I was wondering if we could consider using tsoa package for routing instead of inversify-express-utils for two reasons.

  1. tsoa comes out of the box with swagger documentation feature
  2. tsoa is actively supported.

As this application is purely an API application, it will be very useful if API documentation can be easily integrated and maintained without too much overhead and writing too much decorators and customization.

Readme Typos

Bug ๐Ÿ›

There are a couple of spelling mistakes in the readme.
Screenshot 2019-10-09 at 19 46 54

Add helper entity to DTO mapper methods

It will be very useful and convenient to have mapper methods that automatically map entities to DTOs which will be returned to the client.
One example is here .

const tenants = await this._tenantRepository.findManyByQuery({ name: tenantName });
const tenantDtoList = tenants.map(t => {
   let tenantDto: TenantDto = {
        name: t.name,
        description: t.description,
        isActive: t.isActive,
        id: t.id
    };
    return tenantDto;
});

return tenantDtoList

This can quickly get messy if the DTO has many properties that need to be manually mapped to it. It will be helpful to have an auto mapper method or package that can do this.

[Automapper] Breaking change in next version

Question

Hi, I am the author of automapper-nartc. Due to allowing consumers creating different instances of AutoMapper (and making sure profiles/mappings still work with each instance), breaking changes have emerged. Specifically the MappingProfileBase.configure() method has changed.

Now whenever you call addProfile() on the AutoMapper instance, that instance will be pass in the configure() method. profile.configure(this).

const SomeProfile extends MappingProfileBase {
      constructor() {
         super();
      }

      configure(mapper: AutoMapper) {
         // use mapper.createMap() instead of this.createMap()
         mapper.createMap(...)
      }
}

Thanks for trying out the library.

Return empty array for incorrect get query

I have an endpoint that is used to get a list of tenants by a query like so .../api/v1/tenants?name=default here. I want the user to get an empty list if they queried for a nonexisting tenant name.
Also if a client has passed in an unexpected get query, an empty array should be returned. .../api/v1/tenants?name="blahblah" should return an empty array.

Return typescript class as repository response.

Return typescript class as the response gotten from repositories instead of a JavaScript object representation of the class.
After making calls to the DB using the injected repositories, the response (even after being cast to a typescript class) is always a JavaScript object instead of a typescript class.

const user:User = await new userRepository.findById(userId); // findById is defined to return Promise<User>

console.log(user instanceOf User) //strangely returns false
console.log(user typeof) // is a JavaScript object instead of a User

Because of this weird behavior, I can't call methods of user instance. Hence doing something like this user.activate(); (where activate() is a method in the User class) throws an annoying runtime error that says activate is not a method in user because of course user is not actually an instance of User
Is there a way to fix this? I won't be able to use packages like class-transform to simply convert the JavaScript object to its corresponding typescript class because User has a private constructor which will make class-transform methods (like plainToClass) to complain

Take a look here

const userInstance = User.createInstance({...dto, password: hashedPassword });
userRecord = await this._userRepository.save(userInstance);

even though userRecord seem like an instance of User, it actually isn't.

Setup CI

Setup continues integration with Travis CI

Add useful methods to entities

Currently, in the User and Tenant entities, which are children of the BaseEntity there are a few methods for setting certain properties such as setRole() (in the User entity), deactive() (in the BaseEntity).
It will be useful to have more of these methods that directly modifies the entity

Update CONTRIBUTING Document

The CONTRIBUTING document needs to be updated in order to assist existing and potential contributors on the process of contribution.

Code documentation

Proper documentation is need for existing and subsequently created public classes, properties and methods.

Implement pagination

Implement pagination in all get all endpoints and return a standard pagination response

Make Tenant ID globally accessible

A Tenant ID is passed by the client through the X-Tenant-Id header. This ID should be accessible everywhere without necessarily importing it.

I currently use a global variable to achieve (which I think isn't the right thing to do). Take a look here.

Seed DB with default Tenant.

This boilerplate implements a multi-tenancy architecture. It will be convenient to seed mongo DB with the default tenant for the first time the application starts. This is because to call other endpoints in the application, X-Tenant-Id must be passed in the header. As shown here

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.