All Projects → FawzyMokhtar → TypeScript-in-Nodejs-Starter

FawzyMokhtar / TypeScript-in-Nodejs-Starter

Licence: MIT license
A starter kit for Node.js project written with TypeScript.

Programming Languages

typescript
32286 projects

Projects that are alternatives of or similar to TypeScript-in-Nodejs-Starter

nest-boilerplate
Nest.js boilerplate with CircleCI, Commitizen, Commitlint, Docker-Compose, ESLint, GitHub Actions, Husky, Lint-staged, OpenAPI, Prettier, PostGreSQL, Travis CI, TypeORM
Stars: ✭ 16 (-58.97%)
Mutual labels:  prettier, husky, lint-staged
vital
Starter template for Vite with React (TypeScript). Supports Tailwind with CSS-Modules. Jest and @react/testing-library configured and ready to go. Also ESLint, Prettier, Husky, Commit-lint and Atomic Design for components.
Stars: ✭ 151 (+287.18%)
Mutual labels:  prettier, husky
todo-list
A practical web application built with Node.js, Express, and MySQL for you to readily record, view, and manage your tasks with an account: Create, view, edit, delete, filter, and sort expenses are as easy as pie 🥧
Stars: ✭ 18 (-53.85%)
Mutual labels:  sequelize, express-validator
zero
📦 A zero config scripts library
Stars: ✭ 17 (-56.41%)
Mutual labels:  prettier, lint-staged
vite-vue3-starter
⭐ A Vite 2.x + Vue 3.x + TypeScript template starter
Stars: ✭ 384 (+884.62%)
Mutual labels:  husky, lint-staged
gbkel-portfolio
💎 My personal website that's mainly powered by Next.js, my own style guide and a lot of other technologies.
Stars: ✭ 12 (-69.23%)
Mutual labels:  husky, lint-staged
typescript-react-starter
React & TypeScript Starter with webpack, ts-jest and runtime environment variables. It comes with fp-ts ecosystem and pre-configured prettier, eslint, vscode, husky hooks and Dockerfile to build a deployable image of your app
Stars: ✭ 17 (-56.41%)
Mutual labels:  prettier, husky
uno-game
🎴 An UNO Game made in Javascript
Stars: ✭ 93 (+138.46%)
Mutual labels:  husky, lint-staged
node-boilerplate
Node Typescript Boilerplate for Microservices. Skeleton for Node.js Apps written in TypeScript (with Setup Instructions for ESLint, Prettier, and Husky)
Stars: ✭ 92 (+135.9%)
Mutual labels:  prettier, husky
react-native-template-basic
A simple React Native template with ESlint, Enzyme, Flow, Prettier and custom scripts
Stars: ✭ 14 (-64.1%)
Mutual labels:  prettier, lint-staged
Husky.Net
Git hooks made easy with Husky.Net internal task runner! 🐶 It brings the dev-dependency concept to the .NET world!
Stars: ✭ 394 (+910.26%)
Mutual labels:  husky, lint-staged
rest-api-node-typescript
This is a simple REST API with node and express with typescript
Stars: ✭ 154 (+294.87%)
Mutual labels:  winston, sequelize
nextjs-with-chakra-ui-boilerplate
Next.js with Chakra UI boilerplate. PWA ready with storybook and tests configured.
Stars: ✭ 48 (+23.08%)
Mutual labels:  prettier, husky
website
Personal website and blog built with Next.js, Preact, MDX, Tailwind CSS and hosted on Vercel.
Stars: ✭ 17 (-56.41%)
Mutual labels:  prettier, husky
Typescript Express Starter
🚀 TypeScript Express Starter
Stars: ✭ 238 (+510.26%)
Mutual labels:  prettier, sequelize
typescript-api-starter
🔰 Starter for Node.js express API in Typescript 🚀
Stars: ✭ 72 (+84.62%)
Mutual labels:  winston, prettier
Jsonapi Utils
Build JSON API-compliant APIs on Rails with no (or less) learning curve.
Stars: ✭ 191 (+389.74%)
Mutual labels:  json-api
Datoji
A tiny JSON storage service. Create, Read, Update, Delete and Search JSON data.
Stars: ✭ 222 (+469.23%)
Mutual labels:  json-api
Jsonapi Datastore
JavaScript client-side JSON API data handling made easy.
Stars: ✭ 190 (+387.18%)
Mutual labels:  json-api
Json Api
Implementation of JSON API in PHP 7
Stars: ✭ 171 (+338.46%)
Mutual labels:  json-api

Typescript in Nodejs Starter Kit

A starter kit for Node.js project written with TypeScript.

This project is well organized, scalable and maintainable boilerplate as your application's business grows.

Prerequisites

It's is recommended before start to have a basic knowledge about the following

Table of contents

Problem definition

As we know JavaScript doesn't enforce type checking by itself, this may not be a problem when developing small Node.js apps, but it will be a BIG problem when building a multi-module or scaled apps.

How to solve the problem

Since TypeScript is a super set of JavaScript, we can have Node.js apps to be written using TyeScript.

TypeScript is transpiled using TypeScript Compiler - also known as tsc - which can be adjusted to output the desired version of ECMAScript.

Getting Started

Setup project dependencies

  • If you have yarn installed on your machine:

    Open your terminal on the project's root folder & run the following command

    yarn
  • If you don't have yarn installed on your machine:

    Open your terminal on the project's root folder & run the following command

    npm i -g yarn

    then

     yarn

To run this project in development environment run the command

yarn run dev

To build this project in run the command

yarn run build

To run this project from the built output run the command

yarn run start

Project structure

Overview

We are building a simple electronics store with to basic entities

  1. Category.
  2. Product.

Each Category will have the properties

  • id: number (🔑 primary key).
  • name: string.

Each Product will have the properties

  • id: number (🔑 primary key).
  • name: string.
  • price: number.
  • categoryId: number (🗝 foreign key from category).

Folder structure

./src
└── app
    ├── app.ts
    ├── categories
    │   ├── data
    │   ├── models
    │   └── validation
    ├── controllers
    ├── products
    │   ├── data
    │   ├── models
    │   └── validation
    ├── shared
    │   ├── db
    │   │   └── db.json
    │   ├── middleware
    │   ├── models
    │   └── utils
    └── startup
        └── server.ts
  • app.ts is the entry point of the application.

  • startup/server.ts file is where Node.js server options getting set.

  • Each folder on the app folder represents an application module.

  • shared module contains utilities and shared models which will be used by other application modules.

  • controllers module is where all application modules' routes are being defined.

  • Each module may contains

    • data folder to define its data-access functionalities.
    • models folder in which the module models are defined.
    • validation folder in which all models validations are defined, e.g. validating a model for creating a category.
    • Each folder must has a index.ts by a convention to export each (class, interface, function & etc..) defined in this folder.

Database

Until now this boilerplate supports five types of databases:

  1. In-memory Database (current branch].
  2. PostgreSQL Database (branch postgresql-integration).
  3. MySQL Database (branch mysql-integration).
  4. MSSQL Database ((branch mssql-integration).
  5. MongoDB Database ((branch mongodb-integration).

We are using a json file as virtual database.

The database file could be found in the location ./src/app/shared/db/db.json .

Important note

When we load the db.json file we create an in-memory database which means are changes such as (create, update & delete) category or product will be available until the application is restarted.

We use a class called Database defined in the file ./src/app/shared/models/database.model.ts to load and query the data from the db.json file.

/**
 * Represents a virtual database with two tables `categories` and `products`.
 */
export class Database {
  /**
   * Gets or sets the set of categories available in the database.
   */
  public categories: Category[] = [];

  /**
   * Gets or sets the set of products available in the database.
   */
  public products: Product[] = [];

  /**
   * Creates a new instance of @see Database and loads the database data.
   */
  public static async connect(): Promise<Database> {
    return ((await import('../db/db.json')) as unknown) as Database;
  }
}

API

Since we follow the Json API standards, our web api should always return a response with this structure

/**
 * Represents an application http-response's body in case of success or even failure.
 */
export interface AppHttpResponse {
  /**
   * Gets or sets the data that requested or created by the user.
   *
   * This property will has a value only if the request was succeeded.
   */
  data?: unknown;

  /**
   * Gets or sets the metadata for the http response.
   */
  meta?: AppHttpResponseMeta;

  /**
   * Gets or sets a set of errors that occurs during request processing.
   *
   * @summary e.g. validation errors, security errors or even internal server errors.
   */
  errors?: AppHttpResponseError[];
}

Where the meta has the structure

/**
 * Represents an application http-response metadata.
 */
export interface AppHttpResponseMeta {
  /**
   * Gets or sets the current pagination page.
   */
  page?: number;

  /**
   * Gets or sets the maximum allowed items per-page.
   */
  pageSize?: number;

  /**
   * Gets or sets the count of the actual items in the current page.
   */
  count?: number;

  /**
   * Gets or sets the total count of items available in the database those match the query criteria.
   */
  total?: number;

  /**
   * Gets or sets the number of the previous pagination page.
   */
  previousPage?: number | undefined;

  /**
   * Gets or sets the number of the next pagination page.
   */
  nextPage?: number | undefined;

  /**
   * Gets or sets the total available pagination pages those match the query criteria.
   */
  totalPages?: number;
}

And each error in the errors property has to be

/**
 * Represents an app http error that should be sent within a failed request's response.
 *
 * @summary All error members are optional but the more details the server sends back to the client the more easy it becomes to fix the error.
 */
export interface AppHttpResponseError {
  /**
   * Gets or sets the application-specific code for this error.
   */
  code?: AppErrorCode;

  /**
   * Gets or sets the name of the source that causes this error.
   *
   * Usually it's the name of the property that causes the error.
   *
   * The property maybe a nested property,
   * in this case use e.g. if we are validating a `Person` object use `address.postalCode` instead of `postalCode`.
   */
  source?: string;

  /**
   * Gets or sets a generic title of the problem.
   */
  title?: string;

  /**
   * Gets or sets a more descriptive details for the problem, unlike the generic @field title.
   */
  detail?: string;
}

App specific error codes

The code member of an error object contains an application-specific code representing the type of problem encountered. code is similar to title in that both identify a general type of problem (unlike detail, which is specific to the particular instance of the problem), but dealing with code is easier programmatically, because the “same” title may appear in different forms due to localization as described here.

Our application-specific codes are defined in an Enum called AppErrorCode with the following definition

/**
 * The application-specific error codes.
 */
export enum AppErrorCode {
  /** Un-authenticated code. */
  UnAuthenticated = 1,

  /** Access denied or forbidden code. */
  Forbidden = 2,

  /** Internal server code. */
  InternalServerError = 3,

  /** The field is required code. */
  IsRequired = 4,

  /** The field type is invalid. */
  InvalidType = 5,

  /** The field type is String and its length is invalid. */
  InvalidLength = 6,

  /** The entity field value already exists in another entity. */
  ValueExists = 7,

  /** The entity can't be deleted due to its existing relations with other entities. */
  CantBeDeleted = 8,

  /**
   * The related entity isn't found,
   * @summary e.g. you are trying to create a new product in a category which is not exists in the database.
   */
  RelatedEntityNotFound = 9
}

API examples

  • A success response

    Searching for a list of products those matching some criteria

    [GET] http://localhost:3000/api/products?name=Samsung&categories=1,2,3&page=1&pageSize=3

    Should return a response like the following

    {
      "data": [
        {
          "id": 1,
          "name": "Samsung Galaxy S5",
          "price": 5000,
          "categoryId": 1,
          "category": {
            "id": 1,
            "name": "Mobiles"
          }
        },
        {
          "id": 2,
          "name": "Samsung Galaxy S6",
          "price": 4500,
          "categoryId": 1,
          "category": {
            "id": 1,
            "name": "Mobiles"
          }
        },
        {
          "id": 15,
          "name": "Samsung 32 Inch HD LED Standard TV - UA32K4000",
          "price": 3550,
          "categoryId": 3,
          "category": {
            "id": 3,
            "name": "TVs"
          }
        }
      ],
      "meta": {
        "page": 1,
        "pageSize": 3,
        "count": 3,
        "total": 3,
        "totalPages": 1
      }
    }
  • A bad-request response

    Try to create a new product with a name that is already exists in the database

    [POST] http://localhost:3000/api/products

    {
      "name": "Samsung Galaxy S5",
      "price": 12300.0,
      "categoryId": 1
    }

    Should return a response like the following

    {
      "errors": [
        {
          "code": 7,
          "source": "name",
          "title": "Field value already exists",
          "detail": "Product name already exists"
        }
      ]
    }
  • The internal server error, un-authenticated and forbidden responses should follow the same convention.

Static code analysis

We are using the following plugins to statically analysis our code

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].