Skip to content
EN FR

Tutorial: publish a user-management API

Documentation status: tutorial — see Maturity and evidence.

Goal

Build a small UserManagement module, validate the model, and then publish HTTP routes over Runtime capabilities.

The sequence is deliberate: model first, service second. A route should never be used to hide a model that does not load correctly.

Target structure

UserManagement/
├── packages/
│   └── UserManagement.package.yaml
├── meta/
│   └── models/
│       └── UserManagement/
│           ├── ClassItems.manifest.yaml
│           └── User.model.yaml
└── services/
    └── UserManagement.service.yaml

1. Declare the package

package:
  name: UserManagement
  enabled: true

2. Declare the manifest

Use a project-owned application prefix. usr# is illustrative.

classes:
  - class:
      classId: usr#user
      name: User
      type: entity

Do not borrow a platform prefix for an application-owned concept.

3. Declare the User model

class:
  classId: usr#user
  name: User
  type: entity
  concepts:
    - concept:
        name: Entity
        facets:
          - facet:
              type: hypergraph
              name: main
              fields:
                - Name: String
                - Age: Integer
                - Email: String
                - Company:
                    type: String
                    nullable: true

Add a persistence facet only when the scenario requires durable storage.

4. Validate before publishing

Start the application with the package enabled and verify:

  1. ClassItems.manifest.yaml loads;
  2. usr#user is unique;
  3. User resolves in the Runtime;
  4. fields have the expected types;
  5. constraints are valid.

If this fails, do not add the HTTP service yet.

5. Add a service group

The package should make the service loadable using the publication mechanism supported by the release.

Conceptual example:

services:
  - name: UserManagementApi
    source: ../../services/UserManagement.service.yaml
    enabled: true

The exact service descriptor is versioned. Use the reference for your release when producing a deployable file.

6. Define the HTTP service

The service publishes model capabilities, not a second copy of the domain.

service:
  name: UserManagementApi
  basePath: /api/users
  routes:
    - method: GET
      path: /
      action: ListUsers
    - method: GET
      path: /{id}
      action: GetUser
    - method: POST
      path: /
      action: CreateUser
    - method: PUT
      path: /{id}
      action: UpdateUser
    - method: DELETE
      path: /{id}
      action: DeleteUser

This snippet describes the publication pattern. Effective action names must match actions actually published by the model and the service grammar of the Runtime version in use.

7. Publish CRUD operations

HTTP Business capability Note
GET /api/users User collection filtering/paging according to service contract
GET /api/users/{id} resolve one User return not-found when absent
POST /api/users create validate before commit
PUT /api/users/{id} update preserve identity and constraints
DELETE /api/users/{id} delete apply authorization and business rules

8. Security

HTTP publication creates a separate security boundary. At minimum:

  • authenticate callers when required;
  • authorize at the business-capability boundary;
  • never place secrets in object references;
  • propagate audit context;
  • treat local and remote execution as explicit trust boundaries.

9. Diagnostics

When a request fails, diagnose in this order:

  1. application and package;
  2. manifest;
  3. User model;
  4. published actions/collections;
  5. service;
  6. route;
  7. transport;
  8. authentication/authorization.

Keep a correlation identifier for remote calls so client and Runtime diagnostics can be joined.

10. What this tutorial demonstrates

  • a business model exists independently from its HTTP projection;
  • publication comes after model validation;
  • services expose published capabilities;
  • the same Runtime model can sit behind local or remote execution;
  • transport details should not leak into domain types.