eicrud

An opinionated backend framework based on NestJS. Get your CRUD app up and running in no time! ⚙️🔒

741
20
TypeScript

@eicrud/eicrud logo

Static Badge npm package Static Badge X (formerly Twitter) Follow

Eicrud is an opinionated backend framework extending NestJS.
It's a tool for building scalable, secure Node.js server applications in record time.

[!IMPORTANT]
Eicrud is still in beta; expect minor breaking changes with new versions until v1.0.0. However, you can still use it as it is, and the API will not change much. Check out the release notes for migration guides. If you’re interested in the project, please leave a star on the repository; it helps a lot 🌟🙏

Philosophy

Most of the time, a web app has some CRUD functionality as its base. Eicrud abstracts this into a simple and easy-to-use API, so you don’t have to re-write boilerplate code (controllers, validations, db queries…) whenever you need a new service. By centering everything around CRUD entities, Eicrud provides a framework for writing complex applications that are easy to read, test, and maintain. Eicrud also emphasizes “default security” for its components, where everything is forbidden until allowed.

Features

How it works

Under the hood, Eicrud uses MikroOrm entities guarded with CASL and class-validator.

Here’s a quick example

You first define your entity with validations and transforms (what the data can be).

@Entity()
export class Profile {
  @PrimaryKey()
  @IsString()
  @IsOptional()
  id: string;

  @OneToOne(() => MyUser, (user) => user.profile)
  @IsString()
  owner: MyUser | string;

  @Property()
  @$Transform((val) => val.toLowerCase())
  @MaxLength(30)
  userName: string;
}

Then define your security (who can access the data).

const security: CrudSecurity = {
  user: {
    async defineCRUDAbility(can, cannot, ctx) {
      const id = ctx.userId;
      // users can crud their own profile
      can('crud', 'profile', { owner: id });
    },
  },
  guest: {
    async defineCRUDAbility(can, cannot, ctx) {
      // guests can read all profiles
      can('read', 'profile');
    },
  },
};

And finally, register your service.

@Injectable()
export class ProfileService extends CrudService<Profile> {
  constructor(protected moduleRef: ModuleRef) {
    super(moduleRef, Profile, security);
  }
}

That’s it, profile is now a fully operational CRUD service that you can query with the client.

const client = new CrudClient({ serviceName: 'profile' });

const res = await client.findOne({ userName: 'jon doe' });

You can extend it using commands (for non-CRUD operations).

Monolithic/Microservices duality

Eicrud lets you group your CRUD services into “microservices” with a simple configuration. You can start developing a monolith and easily switch to microservices later on.

msOptions.microServices = {
  "entry": {
    services: [],
    openMsLink: false, openController: true,
    url: "http://localhost:3004",
  },
  "users": {
    services: [User, Profile],
    openMsLink: true, openController: false,
    url: "http://localhost:3005",
  },
  "orders": {
    services: [Order],
    openMsLink: true, openController: false,
    url: "http://localhost:3006",
  },
}

Powerful typed client (remote procedure call)

Eicrud lets you generate a powerful super-client that holds all your DTOs and commands. Allowing auto-completion and type safety directly in your front-end.

// in your profile service
async $say_hello(dto: SayHelloDto, ctx: CrudContext) {
    return `Hello ${dto.myArg}!`
}

// in your frontend
const sp = new SuperClient({url: 'http://localhost:3004'});
sp.profile.say_hello({myArg: 'world'}).then(console.log);

Start building

Eicrud is made for code simplicity, you can build your applications in record time using the CLI that will do the heavy work for you.

Check out the documentation to get started.

Support

Eicrud is in active development and issues are taken seriously. Don’t hesitate to create a ticket or join the Discord if you need help.