Crud complet, simplifié, avec des entités SSOT dactylographiées
Remult utilise des entités TypeScript comme une seule source de vérité pour: ✅ CRUD + API en temps réel, ✅ Client API de type frontal et ✅ Orm backend.
Remult prend en charge toutes les principales bases de données , notamment: PostgreSQL, MySQL, SQLite, MongoDB, MSSQL et Oracle.
Remult est le frontend et le framework backend agnostic et est livré avec des adaptateurs pour express, stabiliser, next.js, nuxt, sveltekit, solidstart, nid, koa, hapi et hono.
Vous voulez faire l'expérience de Remult de première main? Essayez notre tutoriel interactif en ligne.
Remult promeut une syntaxe de requête cohérente pour le code frontal et le 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
}Vous n'aimez pas les décorateurs? Nous avons un soutien complet pour travailler sans décorateurs
Exemple:
// 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 ( )Remult ajoute des gestionnaires d'itinéraire pour une API de repos entièrement fonctionnelle et des points de terminaison en direct en temps réel, incluant éventuellement une spécification API ouverte et un point de terminaison 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 [ ]
}
Bien que le simple crud ne nécessite aucun codage backend, utiliser Remult signifie avoir la possibilité de gérer n'importe quel scénario complexe en contrôlant le backend de nombreuses manières:
Le package Remult est une seule et même chose pour le bundle Frontend et le backend. Installez-le une fois pour un projet monolithe ou par repo dans un monorepo.
npm i remultLa meilleure façon d'apprendre Remult est de suivre un tutoriel d'une application Web TODO simple avec un backend Node.js Express.

Regardez la démo de code sur YouTube ici (14 minutes)
La documentation couvre les principales caractéristiques de Remult. Cependant, c'est toujours un travail en cours.
Exemple Fullstack TODOMVC avec React et Express. (Code source | codes et boîte)
Demo CRM avec une base de données REACT + MUI frontal et Postgres.
Remult est prêt pour la production et, en fait, utilisé dans les applications de production depuis 2018. Cependant, nous gardons la version majeure à zéro afin que nous puissions utiliser les commentaires de la communauté pour finaliser l'API V1.
Le développement Web complet est (toujours) trop compliqué. Simple Crud, une exigence commune de toute application commerciale, devrait être simple à construire, à maintenir et à étendre en cas de besoin.
Remult résume le code répétitif, passe-partout, sujet aux erreurs et mal conçu d'une part, et permet une flexibilité et un contrôle totaux d'autre part. Remult aide à créer des applications FullStack en utilisant uniquement du code TypeScript que vous pouvez facilement suivre et refacter en toute sécurité , et s'adapte bien à tout projet existant ou nouveau en étant minimaliste et complètement sans opinion concernant le choix du développeur d'autres cadres et outils.
D'autres cadres ont tendance à tomber dans trop d'abstraction (sans code, faible code, baaS) ou abstraction partielle (frameworks MVC, GraphQL, ORMS, générateurs d'API, générateurs de code) et ont tendance à être opinionnés sur la chaîne d'outils de développement, l'environnement de déploiement, la configuration / les conventions ou le DSL. Remult tente de trouver un meilleur équilibre.
Les contributions sont les bienvenues. Voir contribution.md.
Remult est sous licence MIT.