remult 0.13.21 → 0.13.22
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +2 -2
- package/readme.md +32 -19
- package/server/expressBridge.d.ts +4 -4
- package/src/remult3/remult3.d.ts +2 -2
package/package.json
CHANGED
package/readme.md
CHANGED
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
|
|
28
28
|
## What is Remult?
|
|
29
29
|
|
|
30
|
-
**Remult** is a
|
|
30
|
+
**Remult** is a full-stack CRUD framework that uses your TypeScript model types to provide:
|
|
31
31
|
|
|
32
32
|
* Secure REST API (highly configurable)
|
|
33
33
|
* Type-safe frontend API client
|
|
@@ -38,13 +38,18 @@
|
|
|
38
38
|
Using a `monorepo` approach, with model types shared between frontend and backend code, Remult can enforce data validation and constraints, defined once, on both frontend and REST API levels.
|
|
39
39
|
|
|
40
40
|
## Getting started
|
|
41
|
-
The best way to learn Remult is by following a tutorial of a simple Todo app with a Node.js Express backend.
|
|
41
|
+
The best way to learn Remult is by following a tutorial of a simple Todo web app with a Node.js Express backend.
|
|
42
|
+
|
|
43
|
+
* [Tutorial with React](https://remult.dev/tutorials/react/)
|
|
44
|
+
* [Tutorial with Angular](https://remult.dev/tutorials/tutorial-angular.html)
|
|
42
45
|
|
|
43
46
|
## Installation
|
|
44
47
|
```sh
|
|
45
48
|
npm i remult
|
|
46
49
|
```
|
|
47
50
|
|
|
51
|
+
## Usage
|
|
52
|
+
|
|
48
53
|
### Setup API backend using a Node.js Express middleware
|
|
49
54
|
```ts
|
|
50
55
|
import express from 'express';
|
|
@@ -60,14 +65,14 @@ app.listen(port, () => {
|
|
|
60
65
|
});
|
|
61
66
|
```
|
|
62
67
|
|
|
63
|
-
|
|
68
|
+
### Define model classes
|
|
64
69
|
```ts
|
|
65
|
-
import { Entity,
|
|
70
|
+
import { Entity, Fields } from 'remult';
|
|
66
71
|
|
|
67
72
|
@Entity('products', {
|
|
68
73
|
allowApiCrud: true
|
|
69
74
|
})
|
|
70
|
-
export class Product
|
|
75
|
+
export class Product {
|
|
71
76
|
@Fields.string()
|
|
72
77
|
name = '';
|
|
73
78
|
|
|
@@ -83,13 +88,14 @@ export class Product extends EntityBase {
|
|
|
83
88
|
[{"name":"Tofu","unitPrice":5}]
|
|
84
89
|
```
|
|
85
90
|
|
|
86
|
-
|
|
91
|
+
### Find and manipulate data in type-safe frontend code
|
|
87
92
|
```ts
|
|
88
93
|
async function increasePriceOfTofu(priceIncrease: number) {
|
|
89
|
-
const
|
|
94
|
+
const productsRepo = remult.repo(Product);
|
|
90
95
|
|
|
96
|
+
const product = await productsRepo.findFirst({ name: 'Tofu' });
|
|
91
97
|
product.unitPrice += priceIncrease;
|
|
92
|
-
|
|
98
|
+
productsRepo.save(product);
|
|
93
99
|
}
|
|
94
100
|
```
|
|
95
101
|
|
|
@@ -97,22 +103,23 @@ async function increasePriceOfTofu(priceIncrease: number) {
|
|
|
97
103
|
```ts
|
|
98
104
|
@BackendMethod({ allowed: Allow.authenticated })
|
|
99
105
|
static async increasePriceOfTofu(priceIncrease: number, remult?: Remult) {
|
|
100
|
-
const
|
|
106
|
+
const productsRepo = remult!.repo(Product);
|
|
101
107
|
|
|
108
|
+
const product = await productsRepo.findFirst({ name: 'Tofu' });
|
|
102
109
|
product.unitPrice += priceIncrease;
|
|
103
|
-
|
|
110
|
+
productsRepo.save(product);
|
|
104
111
|
}
|
|
105
112
|
```
|
|
106
113
|
|
|
107
|
-
|
|
114
|
+
### :ballot_box_with_check: Data validation and constraints - defined once
|
|
108
115
|
|
|
109
116
|
```ts
|
|
110
|
-
import { Entity,
|
|
117
|
+
import { Entity, Fields } from 'remult';
|
|
111
118
|
|
|
112
119
|
@Entity('products', {
|
|
113
120
|
allowApiCrud: true
|
|
114
121
|
})
|
|
115
|
-
export class Product
|
|
122
|
+
export class Product {
|
|
116
123
|
@Fields.string<Product>({
|
|
117
124
|
validate: product => {
|
|
118
125
|
if (product.name.trim().length == 0)
|
|
@@ -133,13 +140,13 @@ export class Product extends EntityBase {
|
|
|
133
140
|
|
|
134
141
|
### Enforced in frontend:
|
|
135
142
|
```ts
|
|
136
|
-
const product =
|
|
143
|
+
const product = productsRepo.create();
|
|
137
144
|
|
|
138
145
|
try {
|
|
139
|
-
await
|
|
146
|
+
await productsRepo.save(product);
|
|
140
147
|
}
|
|
141
|
-
catch {
|
|
142
|
-
console.error(
|
|
148
|
+
catch (e: ErrorInfo<Product>) {
|
|
149
|
+
console.error(e.message); // Browser console will display - "Name: required"
|
|
143
150
|
}
|
|
144
151
|
```
|
|
145
152
|
|
|
@@ -150,14 +157,14 @@ catch {
|
|
|
150
157
|
{"modelState":{"unitPrice":"must not be less than 0","name":"required"},"message":"Name: required"}
|
|
151
158
|
```
|
|
152
159
|
|
|
153
|
-
|
|
160
|
+
### :lock: Secure the API with fine-grained authorization
|
|
154
161
|
```ts
|
|
155
162
|
@Entity<Article>('Articles', {
|
|
156
163
|
allowApiRead: true,
|
|
157
164
|
allowApiInsert: remult => remult.authenticated(),
|
|
158
165
|
allowApiUpdate: (remult, article) => article.author.id == remult.user.id
|
|
159
166
|
})
|
|
160
|
-
export class Article
|
|
167
|
+
export class Article {
|
|
161
168
|
@Fields.string({ allowApiUpdate: false })
|
|
162
169
|
slug = '';
|
|
163
170
|
|
|
@@ -168,3 +175,9 @@ export class Article extends EntityBase {
|
|
|
168
175
|
content = '';
|
|
169
176
|
}
|
|
170
177
|
```
|
|
178
|
+
|
|
179
|
+
## Contributing
|
|
180
|
+
Contributions are welcome. See [CONTRIBUTING](CONTRIBUTING.md).
|
|
181
|
+
|
|
182
|
+
## License
|
|
183
|
+
Remult is [MIT Licensed](LICENSE).
|
|
@@ -6,10 +6,10 @@ import { DataApi, DataApiRequest, DataApiResponse } from '../src/data-api';
|
|
|
6
6
|
import { AllowedForInstance } from '../src/context';
|
|
7
7
|
import { ClassType } from '../classType';
|
|
8
8
|
export declare function remultExpress(options?: {
|
|
9
|
-
/**
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
9
|
+
/** Sets a database connection for Remult.
|
|
10
|
+
*
|
|
11
|
+
* @see [Connecting to a Database](https://remult.dev/docs/databases.html).
|
|
12
|
+
*/
|
|
13
13
|
dataProvider?: DataProvider | Promise<DataProvider> | (() => Promise<DataProvider | undefined>);
|
|
14
14
|
bodySizeLimit?: string;
|
|
15
15
|
disableAutoApi?: boolean;
|
package/src/remult3/remult3.d.ts
CHANGED
|
@@ -82,7 +82,7 @@ export interface FieldRef<entityType = any, valueType = any> extends Subscribabl
|
|
|
82
82
|
valueChanged(): boolean;
|
|
83
83
|
entityRef: EntityRef<entityType>;
|
|
84
84
|
container: entityType;
|
|
85
|
-
metadata: FieldMetadata<
|
|
85
|
+
metadata: FieldMetadata<valueType>;
|
|
86
86
|
load(): Promise<valueType>;
|
|
87
87
|
valueIsNull(): boolean;
|
|
88
88
|
originalValueIsNull(): boolean;
|
|
@@ -245,7 +245,7 @@ export interface FindOptionsBase<entityType> extends LoadOptions<entityType> {
|
|
|
245
245
|
/** filters the data
|
|
246
246
|
* @example
|
|
247
247
|
* await taskRepo.find({where: { completed:false }})
|
|
248
|
-
* @see For more usage examples see [EntityFilter](https://remult.
|
|
248
|
+
* @see For more usage examples see [EntityFilter](https://remult.dev/docs/entityFilter.html)
|
|
249
249
|
*/
|
|
250
250
|
where?: EntityFilter<entityType>;
|
|
251
251
|
/** Determines the order of items returned .
|