Resources
Resources are at the heart of $PLACEHOLDER_NAME$. To put it frankly, everything that isn't the platform itself is a resource; a user, your database, your auth provider, even your application itself.
To create a new resource, you must define one declaratively. Declarative programming is often contrasted with imperative programming; instead of specifying the steps how to create a certain resource, you specify the end result that you want, and $PLACEHOLDER_NAME$ will get you there. For example:
This declaration roughly translates into the following steps (simplified):
- If an application with id
myApplication
already exists in the platform:- Make sure the declaration in the code is the same or a higher version than the one in the backend.
- If the code version is higher, upgrade the backend to the code version. (See Versioning)
- Return the existing application.
- If no such application exists yet:
- Create a new application with the given id and version.
- Return the new application.
In some cases, you may prefer creating, getting, and upgrading resources manually. For this, $PLACEHOLDER_NAME$ also provides the
app.createTable
, app.getTable
, and app.updateTable
functions.File organization
$PLACEHOLDER_NAME$ wants to make it as easy as possible to use resources anywhere. We strive to make the interface for
defineTable
as simple as the interface for ES6 new Map()
, but as capable as any other database table.So, just like with ES6
new Map()
, you can either put your resource declarations into a separate file, or keep them where you need them. For example, if you have a file where you want to load & save data about flowers from your database, you could define the table inside that file:Now the table definition is only accessible from the file, and part of the internal implementation details of
flowers.ts
. This guarantees that future modifications to the table scheme don't break any other code.While you can define tables anywhere (inside a conditional, loop, function, or class constructor, for example), for code clarity reasons it is recommended to only define them at the top-level of each file. For more information on the trade-offs and how to use parametric resources, see the section below.
We encourage you to give this style of file organization a try, even if it is very different from what you've seen in other frameworks. Because all of $PLACEHOLDER_NAME$ was built around it, the issues that other frameworks have with file-local configuration don't exist here.
Deleting resources
Deleting resources is special compared to creating and upgrading. To avoid accidental data loss, deletion is always an imperative two-step process:
- Update the codebase by either:
- Removing the resource definition from the codebase (implicit deletion), or
- Marking the resource for deletion (explicit deletion).
- Then, explicitly deleting the resource on the Dashboard or the CLI, eg.
pn tables delete flowers
(see why)
Implicit deletion
When you refer to a resource in your codebase, we call this a resource reference. Most typically, you refer to resources by the
defineXYZ
functions seen above.As long as a running application references a resource, you will not be able to delete them. So, your first step is to remove all references from your codebase and redeploying your application. If you have a
flowers.ts
file like above, you can just delete the file (or make sure the defineTable
call is not executed anymore).Until you complete the deletion process on the Dashboard or the CLI (see above), you can always restore the table again by adding the resource reference back to your codebase.
Explicit deletion
You can explicitly mark a resource as deleted, like this:
It will now be inaccessible from your codebase. However, all data will remain in the database, and to actually delete that you have to delete it from the Dashboard or using the CLI:
Until you complete the deletion process on the Dashboard or the CLI (see above), you can always restore the table again by bumping the version number:
Parametric resources
Sometimes you may want to create resources dynamically. A common example is organizations. We can create a parametric resource using
defineParametricXYZ
:The
id
, version
, and description
properties are the same for all instances of the parametric resource, while anything else may vary.Why parametric resources?
...
Anatomy of a resource
All resources have a few common properties:
type
: The type of the resource, for exampletable
orgroup
.parent
: The parent resource. For example, a table's parent is the application it belongs to. Only the application resource has no parent.id
: A string identifier for the resource. It must be unique among all resources of the same type and parent, with the exception of parametric resources, where two resources with different parameters can have the same ID. It is recommended to use human-readable IDs, but some teams may choose to suffix them with a random string to avoid collisions.uri
: An automatically generated uniform resource identifier that points to the resource. It is globally unique, meaning that it is even unique across different projects. It is technically also a URL, but we refer to them as URIs to avoid confusion.version
: The version of the resource. See Versioning for more information.description
: A human-readable description of the resource. This is optional, but recommended.