Entities
Let's start coding the app by defining the Task
entity class.
The Task
entity class will be used:
- As a model class for client-side code
- As a model class for server-side code
- By
remult
to generate API endpoints, API queries, and database commands
The Task
entity class we're creating will have an auto-generated id
field, a title
field, a completed
field and an auto-generated createdAt
field. The entity's API route ("tasks") will include endpoints for all CRUD
operations.
Define the Model
Create a
shared
folder under thesrc
folder. This folder will contain code shared between frontend and backend.Create a file
Task.ts
in thesrc/shared/
folder, with the following code:
// src/shared/Task.ts
import { Entity, Fields } from 'remult'
@Entity('tasks', {
allowApiCrud: true,
})
export class Task {
@Fields.cuid()
id = ''
@Fields.string()
title = ''
@Fields.boolean()
completed = false
@Fields.createdAt()
createdAt?: Date
}
- In the server's
api
module, register theTask
entity with Remult by addingentities: [Task]
to anoptions
object you pass to theremultExpress()
middleware:
// src/server/api.ts
import { remultExpress } from "remult/remult-express"
import { Task } from "../shared/Task"
export const api = remultExpress({
entities: [Task]
})
The @Entity decorator tells Remult this class is an entity class. The decorator accepts a key
argument (used to name the API route and as a default database collection/table name), and an options
argument used to define entity-related properties and operations, discussed in the next sections of this tutorial.
To initially allow all CRUD operations for tasks, we set the option allowApiCrud to true
.
The @Fields.cuid decorator tells Remult to automatically generate a short random id using the cuid library. This value can't be changed after the entity is created.
The @Fields.string decorator tells Remult the title
property is an entity data field of type String
. This decorator is also used to define field-related properties and operations, discussed in the next sections of this tutorial and the same goes for @Fields.boolean
and the completed
property.
The @Fields.createdAt decorator tells Remult to automatically generate a createdAt
field with the current date and time.
TIP
For a complete list of supported field types, see the Field Types section in the Remult documentation.
Test the API
Now that the Task
entity is defined, we can start using the REST API to query and add a tasks.
Open a browser with the url: http://localhost:3002/api/tasks, and you'll see that you get an empty array.
Use
curl
toPOST
a new task - Clean car.
curl http://localhost:3002/api/tasks -d "{\"title\": \"Clean car\"}" -H "Content-Type: application/json"
Refresh the browser for the url: http://localhost:3002/api/tasks and see that the array now contains one item.
Use
curl
toPOST
a few more tasks:
curl http://localhost:3002/api/tasks -d "[{\"title\": \"Read a book\"},{\"title\": \"Take a nap\", \"completed\":true },{\"title\": \"Pay bills\"},{\"title\": \"Do laundry\"}]" -H "Content-Type: application/json"
- Note that the
POST
endpoint can accept a singleTask
or an array ofTask
s.
- Refresh the browser again, to see that the tasks were stored in the db.
Wait, where is the backend database?
While remult supports many relational and non-relational databases, in this tutorial we start by storing entity data in a backend JSON file. Notice that a db
folder has been created under the root folder, with a tasks.json
file containing the created tasks.
Admin UI
Enabling the Admin UI
Add the Admin UI to your Angular application by setting the admin
option to true
in the remultExpress()
import { remultExpress } from 'remult/remult-express'
import { Task } from '../shared/Task.js'
export const api = remultExpress({
entities: [Task],
admin: true, // Enable the Admin UI
})
Accessing and Using the Admin UI
Navigate to http://localhost:3002/api/admin
to access the Admin UI. Here, you can perform CRUD operations on your entities, view their relationships via the Diagram entry, and ensure secure management with the same validations and authorizations as your application.
Features
- CRUD Operations: Directly create, update, and delete tasks through the Admin UI.
- Entity Diagram: Visualize relationships between entities for better data structure understanding.
- Security: Operations are secure, adhering to application-defined rules.
Display the Task List
Let's start developing the web app by displaying the list of existing tasks in an Angular component.
Create a
Todo
component using Angular's clishng g c todo
Import the new component in the
app.component.ts
ts//src/app/app.component.ts import { Component } from '@angular/core'; import { CommonModule } from '@angular/common'; import { RouterOutlet } from '@angular/router'; import { HttpClientModule } from '@angular/common/http'; import { FormsModule } from '@angular/forms'; import { TodoComponent } from './todo/todo.component'; @Component({ selector: 'app-root', standalone: true, imports: [ CommonModule, RouterOutlet, HttpClientModule, FormsModule, TodoComponent, ], templateUrl: './app.component.html', styleUrl: './app.component.css', }) export class AppComponent { title = 'remult-angular-todo'; }
Replace the
app.components.html
to use thetodo
component.html<!-- src/app/app.component.html --> <app-todo></app-todo>
Add the highlighted code lines to the
TodoComponent
class file:ts// src/app/todo/todo.component.ts import { Component } from '@angular/core'; import { CommonModule } from '@angular/common'; import { FormsModule } from '@angular/forms'; import { remult } from 'remult'; import { Task } from '../../shared/Task'; @Component({ selector: 'app-todo', standalone: true, imports: [CommonModule, FormsModule], templateUrl: './todo.component.html', styleUrl: './todo.component.css', }) export class TodoComponent { taskRepo = remult.repo(Task); tasks: Task[] = []; ngOnInit() { this.taskRepo.find().then((items) => (this.tasks = items)); } }
Here's a quick overview of the different parts of the code snippet:
- We've imported the
FormsModule
for angular's forms support taskRepo
is a Remult Repository object used to fetch and create Task entity objects.tasks
is a Task array.- The
ngOnInit
method calls theRemult repository's find method to fetch tasks from the server, once when the component is loaded.
- We've imported the
Replace the contents of
todo.component.html
with the following HTML:html<!-- src/app/todo/todo.component.html --> <h1>todos</h1> <main> <div *ngFor="let task of tasks"> <input type="checkbox" [(ngModel)]="task.completed" /> {{task.title}} </div> </main>
After the browser refreshes, the list of tasks appears.