typeorm-entitysharer
TypeScript icon, indicating that this package has built-in type declarations

1.0.1 • Public • Published

TypeORM Shared models creator

This tool can be used to create client/server classes based on the same TypeORM entities, allowing you to share them.

This is a work in progress.

Shared interface for client - server architecture

We use typescript to ensure data models integrity in all our programs.

On a client - server architecture, we share data models between both client & server. Doing this way, every update in data models will be automatically visible to both client & server.

The generic architecture we use :

                   shared interfaces repo
                  /                      \
      server repo                          client repo

Data model integrity on server side

We use typeorm as it allows us to perform database request while keeping these strong typings. Typescript works well with typeorm entities, which are js classes, so there is no special needs on this side.

We also use class-validator as it allows us to check if a data coming into the api respects the corresponding class structure.

There is also a swagger on the api.

A basic entity :

import { Entity, Column, PrimaryGeneratedColumn, BaseEntity, OneToMany } from 'typeorm';
import { Project } from './entities';
import { MinLength, MaxLength, IsEmail } from 'class-validator';
import { ApiModelProperty } from '@nestjs/swagger';
 
@Entity()
export class User extends BaseEntity {
    @ApiModelProperty()
    @PrimaryGeneratedColumn('uuid')
    public id: string;
 
    @ApiModelProperty()
    @MinLength(2, { message: 'ERRORS.USERS.FIRSTNAME_TOO_SHORT' })
    @MaxLength(50, { message: 'ERRORS.USERS.FIRSTNAME_TOO_LONG' })
    @Column()
    public firstName: string;
 
    @ApiModelProperty()
    @MinLength(2, { message: 'ERRORS.USERS.LASTNAME_TOO_SHORT' })
    @MaxLength(50, { message: 'ERRORS.USERS.LASTNAME_TOO_LONG' })
    @Column()
    public lastName: string;
 
    @ApiModelProperty()
    @IsEmail({}, { message: 'ERRORS.USERS.EMAIL' })
    @Column({ unique: true })
    public email: string;
 
    @ApiModelProperty()
    @MinLength(12, { message: 'ERRORS.USERS.PASSWORD_TOO_SHORT' })
    @Column()
    public password?: string;
 
    @ApiModelProperty()
    @Column({ default: false })
    public admin: boolean;
 
    @ApiModelProperty({ isArray: true })
    @OneToMany(type => Project, project => project.user, {
        cascade: true,
    })
    public projects: Project[];
}

How do we use this :

import { User } from 'shared-entities'
 
const User = new User()

Client side validation

On client side, we wants to make sure that data coming from the api will respects our model structure, so we will use class-validator too.

However, typeorm can not be used on client-side, furthermore it would load a useless amount of code. swagger is also useless on client side.

What we need on client side is :

  • class structure
  • class-validator decorators

The expected file would looks like this:

import { Project } from './entities';
import { MinLength, MaxLength, IsEmail } from 'class-validator';
 
export class User {
    public id: string;
 
    @MinLength(2, { message: 'ERRORS.USERS.FIRSTNAME_TOO_SHORT' })
    @MaxLength(50, { message: 'ERRORS.USERS.FIRSTNAME_TOO_LONG' })
    public firstName: string;
 
    @MinLength(2, { message: 'ERRORS.USERS.LASTNAME_TOO_SHORT' })
    @MaxLength(50, { message: 'ERRORS.USERS.LASTNAME_TOO_LONG' })
    public lastName: string;
 
    @IsEmail({}, { message: 'ERRORS.USERS.EMAIL' })
    public email: string;
 
    @MinLength(12, { message: 'ERRORS.USERS.PASSWORD_TOO_SHORT' })
    public password?: string;
 
    public admin: boolean;
 
    public projects: Project[];
}

What has been removed :

  • typeorm & swagger imports
  • extends BaseEntity keywords
  • Typeorm decorators

How do we use this :

import { User } from 'shared-entities'
 
const User = new User()

Build process

Our goal : transform a js class based on typeorm & swagger in a standalone-typescript class.

Perform it client side ?

As the problem remains mainly client side, we could transform our structure when bundling our angular app with webpack. As described here https://github.com/typeorm/typeorm/issues/62#issuecomment-264490738, we could use a shim in webpack so all typeorm decorators would return an empty function. We would have to do the same for swagger decorators. Using typescript mixin, we could also transform BasicEntity class in an empty class, so our User class would not have any additionnal attributes & methods coming from parent class.

We chose not to do this way for 2 reasons :

  • it leads to poor code understanding (all those decorators in a typescript class, which are useless which are not?)
  • We think it's the shared interface package reponsability to ensure it's compatibily with both client & server

Build for both client & server

We expects this structure in our shared gitlab repository:

/dist
  /client
    ... client entities : ts + js
  /server
   ... server entities : ts + js

We use gulp as the task runner for the build process.

Build for server :

  • take all entities (.ts)
  • copy them in dist/server (.ts)
  • transpile them to .js in dist/server

Build for client

  • take all entities (.ts)
  • remove useless decorators, imports & extends
  • copy result in dist/client (.ts)
  • transpile result in dist/client (.js)

See gulpfile.js for detailed process

Deploy as distinct npm repositories

It is possible to create two npm packages from the same gitlab repository.

Client side :

  • install with npm install shared-entities-client
  • use with import { User } from 'shared-entities-client

Server side :

  • install with npm install shared-entities-server
  • use with import { User } from 'shared-entities-server

Why we should do this :

  • only code that we need is imported as dependency (no server entities en client side)

Why we do not do this :

  • we would have to pay : )

Deploy this as a single npm repository

It should be possible (i'm on it) to import distinct classes from the same npm package :

Client side :

  • install with npm install shared-entities/client
  • use with import { User } from 'shared-entities/client

Server side :

  • install with npm install shared-entities/server
  • use with import { User } from 'shared-entities/server

Why we do this :

  • it's free : )

Why we should not do this :

  • useless code imported

Configuration file

You need to create a configuration file called typeorm-entitysharer.json at your project root, containing the following data:

{
    "decoratorsWhitelist": [
        "TranslationMinLength",
        "TranslationMaxLength"
    ],
    "importsWhitelist": [
        "./index",
        "../index",
        "../errors",
        "class-validator",
        "./validators"
    ],
    "tsconfigPath": "tsconfig.json",
    "entitiesPath": "src/**/*.ts",
    "errorsPath": "src/errors/*.ts"
}
  • decoratorsWhitelist: the decorators not to be removed
  • importsWhitelist: the imports not to be removed
  • tsconfigPath: typescript config path (from project root)
  • entitiesPath: your entities path (from project root, regex)
  • errorsPath: this project also allows to share translations. This is WIP.

Readme

Keywords

none

Package Sidebar

Install

npm i typeorm-entitysharer

Weekly Downloads

0

Version

1.0.1

License

Apache

Unpacked Size

12.1 kB

Total Files

5

Last publish

Collaborators

  • godefroy
  • totomakers
  • lonestone-team