CRUD de pila completa, simplificada, con entidades de typeScript SSOT
La remulgación utiliza entidades TypeScript como una sola fuente de verdad para: ✅ API RUD + en tiempo real, ✅ Cliente API seguro de tipo frontend y ✅ Backend ORM.
La remulgación admite todas las bases de datos principales , que incluyen: PostgreSQL, MySQL, SQLite, MongoDB, MSSQL y Oracle.
La remulgación es el marco de retroceso y el backend agnóstico y viene con adaptadores para Express, Fastify, Next.js, Nuxt, Sveltekit, SolidStart, Nest, Koa, Hapi y Hono.
¿Quieres experimentar la remulgación de primera mano? Pruebe nuestro tutorial interactivo en línea.
La remulgación promueve una sintaxis de consulta consistente para el código frontend y de backend :
// Frontend - GET: /api/products?_limit=10&unitPrice.gt=5,_sort=name
// Backend - 'select name, unitPrice from products where unitPrice > 5 order by name limit 10'
await repo ( Product ) . find ( {
limit : 10 ,
orderBy : {
name : 'asc' ,
} ,
where : {
unitPrice : { $gt : 5 } ,
} ,
} )
// Frontend - PUT: '/api/products/product7' (body: { "unitPrice" : 7 })
// Backend - 'update products set unitPrice = 7 where id = product7'
await repo ( Product ) . update ( 'product7' , { unitPrice : 7 } ) // shared/product.ts
import { Entity , Fields } from 'remult'
@ Entity ( 'products' , {
allowApiCrud : true ,
} )
export class Product {
@ Fields . cuid ( )
id = ''
@ Fields . string ( )
name = ''
@ Fields . number ( )
unitPrice = 0
}¿No te gustan los decoradores? Tenemos apoyo completo para trabajar sin decoradores
Ejemplo:
// backend/index.ts
import express from 'express'
import { remultExpress } from 'remult/remult-express' // adapters for: Fastify,Next.js, Nuxt, SvelteKit, SolidStart, Nest, more...
import { createPostgresDataProvider } from 'remult/postgres' // supported: PostgreSQL, MySQL, SQLite, MongoDB, MSSQL and Oracle
import { Product } from '../shared/product'
const app = express ( )
app . use (
remultExpress ( {
entities : [ Product ] ,
dataProvider : createPostgresDataProvider ( {
connectionString : 'postgres://user:password@host:5432/database"' ,
} ) ,
} ) ,
)
app . listen ( )La remulgación agrega manejadores de ruta para una API REST totalmente funcional y puntos finales de Quera en vivo en tiempo real, opcionalmente que incluye una especificación de API abierta y un punto final GRAPHQL
const [ products , setProducts ] = useState < Product [ ] > ( [ ] )
useEffect ( ( ) => {
repo ( Product )
. find ( {
limit : 10 ,
orderBy : {
name : 'asc' ,
} ,
where : {
unitPrice : { $gt : 5 } ,
} ,
} )
. then ( setProducts )
} , [ ] ) useEffect ( ( ) => {
return repo ( Product )
. liveQuery ( {
limit : 10 ,
orderBy : {
name : 'asc' ,
} ,
where : {
unitPrice : { $gt : 5 } ,
} ,
} )
. subscribe ( ( info ) => {
setProducts ( info . applyChanges )
} )
} , [ ] ) import { Entity , Fields , Validators } from 'remult'
@ Entity ( 'products' , {
allowApiCrud : true ,
} )
export class Product {
@ Fields . cuid ( )
id = ''
@ Fields . string ( {
validate : Validators . required ,
} )
name = ''
@ Fields . number < Product > ( {
validate : ( product ) => product . unitPrice > 0 || 'must be greater than 0' ,
} )
unitPrice = 0
} try {
await repo ( Product ) . insert ( { name : '' , unitPrice : - 1 } )
} catch ( e : any ) {
console . error ( e )
/* Detailed error object ->
{
"modelState": {
"name": "Should not be empty",
"unitPrice": "must be greater than 0"
},
"message": "Name: Should not be empty"
}
*/
} // POST '/api/products' BODY: { "name":"", "unitPrice":-1 }
// Response: status 400, body:
{
"modelState" : {
"name" : "Should not be empty" ,
"unitPrice" : "must be greater than 0"
} ,
"message" : "Name: Should not be empty"
}@ Entity < Article > ( 'Articles' , {
allowApiRead : true ,
allowApiInsert : Allow . authenticated ,
allowApiUpdate : ( article ) => article . author == remult . user . id ,
apiPrefilter : ( ) => {
if ( remult . isAllowed ( 'admin' ) ) return { }
return {
author : remult . user . id ,
}
} ,
} )
export class Article {
@ Fields . string ( { allowApiUpdate : false } )
slug = ''
@ Fields . string ( { allowApiUpdate : false } )
authorId = remult . user ! . id
@ Fields . string ( )
content = ''
} await repo ( Categories ) . find ( {
orderBy : {
name : 'asc ' ,
} ,
include : {
products : {
where : {
unitPrice : { $gt : 5 } ,
} ,
} ,
} ,
} )
// Entity Definitions
export class Product {
//...
@ Relations . toOne ( Category )
category ?: Category
}
export class Category {
//...
@ Relations . toMany < Category , Product > ( ( ) => Product , `category` )
products ?: Product [ ]
}
Si bien CRUD simple no debería requerir ninguna codificación de backend, usar la reminación significa tener la capacidad de manejar cualquier escenario complejo controlando el backend de numerosas maneras:
El paquete de remultos es uno y el mismo tanto para el paquete frontend como para el backend. Instálelo una vez para un proyecto de monolito o per-repetición en un monorepo.
npm i remultLa mejor manera de aprender la remulgación es siguiendo un tutorial de una aplicación web simple con un backend expreso node.js.

Mira la demostración del código en YouTube aquí (14 minutos)
La documentación cubre las características principales de la remulgación. Sin embargo, sigue siendo un trabajo en progreso.
FullStack ToDomVC Ejemplo con React y Express. (Código fuente | Codesandbox)
CRM demostración con una base de datos React + MUI front-end y Postgres.
La remulgación está lista para la producción y, de hecho, se usa en aplicaciones de producción desde 2018. Sin embargo, mantenemos la versión principal en cero para que podamos usar los comentarios de la comunidad para finalizar la API V1.
El desarrollo web completo es (aún) demasiado complicado. Simple Crud, un requisito común de cualquier aplicación comercial, debe ser simple de construir, mantener y extender cuándo surge la necesidad.
Los resumen de los resúmenes de un código repetitivo, repetitivo, propenso a errores y mal diseñado, por un lado, y habilita la flexibilidad y el control total por el otro. La remulgación ayuda a construir aplicaciones FullStack utilizando solo un código TypeScript que puede seguir y refactorizar fácilmente , y se ajusta muy bien a cualquier proyecto existente o nuevo al ser minimalista y completamente sin opinuar con respecto a la elección del desarrollador de otros marcos y herramientas.
Otros marcos tienden a caer en demasiada abstracción (sin código, código bajo, BAA) o abstracción parcial (marcos MVC, GraphQL, ORMS, generadores API, generadores de código), y tienden a ser obstinados con respecto a la cadena de herramientas de desarrollo, el entorno de implementación, la configuración/convenciones o los dSL. La remulgación intenta lograr un mejor equilibrio.
Las contribuciones son bienvenidas. Ver contribuyente. MD.
La remulgación tiene licencia MIT.