User Model
To build out the User model for the application, we need to consider the following:
- A user should have a name and an email
- A user can be part of a team or not
- A user can create a document
To start we can describe the data for the User model with the following fields:
model User {
fields {
identity Identity @unique
name Text
email Text
teams TeamMembership[]
documents Document[]
}
}
The above defines the identity
field as Identity
which carries the user identity (opens in a new tab) and act as a mechanism for authentication (opens in a new tab) We have also made the Identity unique with the @unique rule which makes sure that every user is unique.
The name and email of the user with a type of Text
which is mandatory by default. We can make a field optional by using the ?
symbol.
At field level the ?
sets a field to be nullable
In Keel, you can indicate a relationship between multiple models by referencing them as fields, in our case we are referencing the TeamMembership
and Document
model as a part of the User model since a user can belong to a team and also create a document.
Now that we’ve defined the data that belongs to the User model, we need to specify what actions (opens in a new tab) can be done on the User model and its respective permissions. In our Keel schema we can specify this using actions
like so.
model User {
fields {
identity Identity @unique
name Text
email Text
teams TeamMembership[]
documents Document[]
}
actions {
get me() {
@where(user.identity == ctx.identity)
}
list listUsers() {
@where(user.identity == ctx.identity)
}
delete deleteUser(id)
create createUser() with (name, email) {
@set(user.identity = ctx.identity)
@permission(expression: ctx.isAuthenticated)
}
update updateUser(id) with (name?, email?)
}
}
Just below the model fields, we have defined the following actions that allow us perform CRUD (opens in a new tab) operations to the User model. All Keel models come with a built-in id
property by default to serve as a means of reference to the model, hence why we are specifying it in some of the operations. Keel models also come with built-in createdAt
and UpdateAt
properties by default, so you can reference these in your actions without needing to manually specify them in your fields.
In the createUser()
action, we have specified that a name and email needs to be provided before a user can be created. We have also set the owner of the newly created record to be the identity of the logged in user and finally, we have provided a permission (opens in a new tab) that this action can only be performed by an authenticated user. Permissions allow you define an authorization condition for an action to be carried out.
The get me()
action will help us return the user’s identity in context just incase we need to pull the correct user details on the client-side.
The name of an action does not denote any functional significance, what matters is the action type you use. You can name your actions whatever you want.
The delete deleteUser()
action will delete a user account
The update updateUser()
actions will update a user name or email.
Next, we need to set permissions for all the other actions in the model. We can do that by using @permisson (opens in a new tab) attribute to define this in the keel schema.
model User {
fields {
identity Identity @unique
name Text
email Text
teams TeamMembership[]
documents Document[]
}
actions {
get me() {
@where(user.identity == ctx.identity)
}
list listUsers() {
@where(user.identity == ctx.identity)
}
delete deleteUser(id)
create createUser() with (name, email) {
@set(user.identity = ctx.identity)
@permission(expression: ctx.isAuthenticated)
}
update updateUser(id) with (name?, email?)
}
@permission(
actions: [get, update, delete],
expression: user.identity == ctx.identity
)
}
In Keel, permissions are assigned to different action types by the action parameter of @permissions
. How the permissions are implemented is defined by the expression parameter. If the specificied expression returns true
then it passes.
Additional action permissions can be included by adding an @permission
within the action definition, as demonstrated in createUser
So we’ve built our User model which is based on the application requirements we specified above.