In the world of OutSystems development, you will hear a lot of talk about “CRUD wrappers”(“CRUD” means “Create, Read, Update, and Delete”) and they seem to be connected to the “Four Layer Canvas” architecture, but it is not clear what exactly people mean by a CRUD wrapper, why they are needed, or how to build one. So let’s take a look!
What is a CRUD wrapper?
A CRUD wrapper is an action that “wraps” one or more of the default Entity Actions (GetXYZ, GetXYZForUpdate, CreateXYZ, CreateOrUpdateXYZ, UpdateXYZ, and DeleteXYZ)in a fashion that allows you to build logic that always runs before and after the record is accessed or changed. Even though the “R” in “CRUD” stands for “Read” and it is quite possible that someone can write a wrapper to stand-in for GetXYZ and GetXYZForUpdate, it is much less likely to see the R Entity Actions get wrapped than the C, U, and D Entity Actions.
Why have a CRUD wrapper?
When you first start to use OutSystems, the nifty “build an app in 5 minute” demos show you how to rapidly build out a data model and quickly drag/drop screens together to achieve rapid success. All good stuff! But once you start to build apps at a bigger scale, you discover that you often have multiple places that change a record’s value, and each place has to be maintained for things like validation logic before the record is saved. Or perhaps your application needs to support multiple locales, and you discover just how hard it is to do the translations when your messages like “saved!” are scattered all over the place. Even worse is when you need to start performing more advanced logic into your Entity access, like setting default values, integrating with outside services to push or pull data, and so on. If you follow a soft delete pattern, it becomes a disaster when any developer who isn’t paying attention adds a call to DeleteXYZ to their screen because they did not notice that the Entity has an IsActive Attribute. The CRUD wrappers give you a place to put all of the logic related to the Entity in a way that forces the rest of the application to use it.
Traits of a good CRUD wrapper
A good set of CRUD wrappers fulfills these “missions”:
- Acts as a centralized, predictable location for error and success messages
- Performs validation
- Sets standard fields such as “CreatedOn” and “UpdatedByUserId”
- Handle soft deletes transparently and correctly
- Validates and cascade deletes as-needed
- Provide both highly granular messaging and coarse messaging in a consistent and standardized fashion
- Sets default values on create/update
- Perform any needed cleanup work after create/update/delete
- Allows you to force all changes through them so that you are guaranteed consistent usage
- Be performant and efficient, but not sacrifice correctness for performance (use separate actions for exceptions to this rule)
- Be offered in multi-tenant versions as-needed
- Enables developers who are not familiar with the application’s business logic to write code that performs CRUD operations without error simply by using the CRUD wrappers
This is just the beginning. We will be learning a lot more in the next few weeks about CRUD wrappers, how to write them, and how to use them!