Skip to content

Read models' before hooks

Compare
Choose a tag to compare
@juanjoman juanjoman released this 01 Jul 13:21
· 1057 commits to main since this release

With this new version, we can now add before hooks to our @ReadModel annotations. This can become really handy to either:

  • Validate parameters
  • Change read model filters on the fly with programmatic logic
  • Deny access to specific users

For example, we could deny user's access when he/she's not the Cart's owner:

@ReadModel({
  authorize: [User],
  before: [validateUser],
})
export class CartReadModel {
  public constructor(
    readonly id: UUID,
    readonly userId: UUID
  ) {}
  // Your projections go here
}

function validateUser(filter: FilterFor<CartReadModel>, currentUser?: UserEnvelope): FilterFor<CartReadModel> {
  if (filter?.userId !== currentUser.id) throw NotAuthorizedError("...")
  return filter
}

You can also chain these before functions to split your logic:

import { changeFilters } from '../../filters-helper' // You can also use external functions!

@ReadModel({
  authorize: [User],
  before: [validateUser, validateEmail, changeFilters],
})
export class CartReadModel {
  public constructor(
    readonly id: UUID,
    readonly userId: UUID
  ) {}

  // Your projections go here
}

function validateUser(filter: FilterFor<CartReadModel>, currentUser?: UserEnvelope): FilterFor<CartReadModel> {
  if (filter.userId !== currentUser.id) throw NotAuthorizedError("...")
  return filter // This filter will be passed as a parameter to the validateEmail function
}

function validateEmail(filter: FilterFor<CartReadModel>, currentUser?: UserEnvelope): FilterFor<CartReadModel> {
  if (!filter.email.includes('myCompanyDomain.com')) throw NotAuthorizedError("...")
  return filter
}

As a side note, remember that the order in which filters are specified matters.