SSOT TypeScript 엔티티를 사용하여 단순화 된 풀 스택 크루드
Remult는 다음을위한 단일 진실의 소스로 TypeScript 엔티티를 사용합니다.
Remult는 PostgreSQL, MySQL, SQLite, MongoDB, MSSQL 및 Oracle을 포함한 모든 주요 데이터베이스를 지원합니다 .
Remult는 Frontend and Backend Framework Agnostic 이며 Express, Fastify, Next.js, Nuxt, Sveltekit, Solidstart, Nest, Koa, Hapi 및 Hono를위한 어댑터가 제공됩니다.
remult를 직접 경험하고 싶습니까? 대화식 온라인 튜토리얼을 사용해보십시오.
Remult는 Frontend 및 백엔드 코드 모두에 대한 일관된 쿼리 구문을 홍보합니다.
// 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
}데코레이터를 좋아하지 않습니까? 우리는 데코레이터없이 일을 전적으로 지원합니다
예:
// 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는 Open API 사양 및 GraphQL 엔드 포인트를 포함하여 완전히 기능적인 REST API 및 실시간 라이브 쿼리 엔드 포인트를위한 경로 처리기를 추가합니다.
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 [ ]
}
Simple Crud는 백엔드 코딩이 필요하지 않아야하지만 Remult를 사용하는 것은 백엔드를 여러 가지 방법으로 제어하여 복잡한 시나리오를 처리 할 수있는 능력을 갖는 것을 의미합니다.
Remult 패키지는 Frontend 번들과 백엔드 모두에 대해 하나이며 동일합니다. Monorepo에서 Monolith Project 또는 REPO Per-Repo를 위해 한 번 설치하십시오.
npm i remultRemult를 배우는 가장 좋은 방법은 Node.js Express 백엔드가 장착 된 간단한 Todo 웹 앱의 자습서를 따르는 것입니다.

YouTube에서 코드 데모 시청 (14 분)
문서는 Remult의 주요 기능을 다룹니다. 그러나 여전히 진행중인 작업입니다.
React and Express의 Fullstack Todomvc 예제. (소스 코드 | Codesandbox)
React + MUI 프론트 엔드 및 Postgres 데이터베이스가있는 CRM 데모.
Remult는 생산 준비가되었으며 실제로 2018 년부터 제작 앱에 사용됩니다. 그러나 주요 버전을 0으로 유지하여 커뮤니티 피드백을 사용하여 V1 API를 마무리 할 수 있습니다.
풀 스택 웹 개발은 (여전히) 너무 복잡합니다. 모든 비즈니스 응용 프로그램의 일반적인 요구 사항 인 Simple Crud는 필요가 발생할 때 구축, 유지 및 확장하기가 간단해야합니다 .
Remult는 반복적, 보일러 플레이트, 오류가 발생하며 제대로 설계되지 않은 코드를 추상화하고 다른 한편으로는 전체 유연성과 제어를 가능하게합니다. Remult는 쉽게 팔로우하고 안전하게 리팩터링 할 수있는 TypeScript 코드 만 사용하여 FullStack 앱을 구축하는 데 도움이되며 개발자가 선택한 다른 프레임 워크 및 도구의 선택에 대해 최소한의 최소한의 새로운 프로젝트에 적합합니다.
다른 프레임 워크는 너무 많은 추상화 (코드, 저 코드, BAA) 또는 부분 추상화 (MVC 프레임 워크, GraphQL, ORM, API 생성기, 코드 생성기)에 속하며 개발 도구 사슬, 배포 환경, 구성/규칙 또는 DSL에 대한 의견을 제시하는 경향이 있습니다. Remult는 더 나은 균형을 맞추려고 시도합니다.
기부금을 환영합니다. Contributing.md를 참조하십시오.
Remult는 MIT 라이센스가 부여되었습니다.