Base profile & modeling
This page describes how to model applications using the Base platform.
It focuses on:
- simple types
- REST modeling
- method types
- pseudocode for sequence diagrams
- layers
- how the model maps to OpenAPI + diagram artifacts
Exact generated output paths are described in the Base example.
The OpenAPI and diagram artifacts described here are replaceable output. The ownership and regeneration reference explains safe editing, cleanup and version-control policies.
1. Simple types
Provided by the common-base model Base.cmn:
String,Integer,Long,BooleanDate,Time,Timestamp- semantic helper types like
Id
Used across all higher‑level platforms.
1.1 OpenAPI wire representation
The Base OpenAPI cartridge derives one coherent wire contract from the effective CMN type definition:
| Base type | OpenAPI schema |
|---|---|
String, Name, Text | string |
Id | string with format uuid |
Integer | integer with format int32 |
Long | integer with format int64 |
Decimal | number |
Date | string with format date |
Time, Timestamp | string with format date-time |
Boolean | boolean |
Binary | string with format binary |
CMN enumerations are represented as OpenAPI string schemas whose allowed values are the CMN enumeration names. This also applies to enum<integer>: its numeric codes are not exposed as OpenAPI values. For example, the public values of SetupType remain NONE, NP, and JP, while its numeric codes can be used by a persistence facility.
The Base Timestamp is declared as type<time> Timestamp. Its default wire representation is therefore an ISO-8601 timestamp in an OpenAPI string/date-time schema. A project or another facility can define a numeric timestamp by specializing Long; that type uses integer/int64. The numeric value's time unit remains part of that project-specific contract.
The target-language javaType property does not select the OpenAPI wire representation. For example, assigning java.time.Instant or java.lang.Long does not turn a temporal CMN type into a numeric wire value, and it does not turn a Long-based CMN type into a temporal string.
Modeled documentation and examples remain authoritative. Their supported OpenAPI positions and exact precedence are defined under OpenAPI documentation and examples.
1.2 Dictionary schemas
For a CMN dictionary ValueType[KeyType], the Base OpenAPI cartridge emits an object whose additionalProperties schema describes the value type. For example, String[String] becomes:
type: object
additionalProperties:
type: stringThis mapping is used for dictionary fields and for JSON request and response bodies. JSON object member names are strings, and OpenAPI 3.0 additionalProperties describes their values. The current generated schema therefore does not encode the CMN dictionary key type as a separate schema. The public REST dictionary contract accepts a CMN string-based key type only when its effective Java type is Java String. This includes string specializations without a different javaType; for example, an Id specialization mapped to java.util.UUID is not a supported REST dictionary key. The Base REST validation rejects other key types. A facility with a different wire contract must provide and verify its own mapping.
Direct dictionary path and query parameters are rejected by the Base REST validation. Model such data as a JSON body or as explicit scalar parameters supported by the target facility. See the generic CMN dictionary syntax and the SpringBoot REST mapping.
2. REST modeling with resources
Example:
resource /hello as Greeting {
read sayHello()
}2.1 Method types
Base provides:
Raw method types:
get→ GETpost→ POSTput→ PUTpatch→ PATCHdelete→ DELETE
Opinionated (CRUD):
create→ POSTread→ GETupdate→ PUTdeleteInstance→ DELETE for one resource instancequery→ GET with optional pagination
Example:
resource /customers as Customer[] by id {
create()
read readCustomer()
update()
query()
}2.2 Named request headers in OpenAPI
Use the Base resource-method property consumeHeaders to declare named request headers that belong to an endpoint's OpenAPI contract. Its value is one quoted header name or a comma-separated list of quoted names:
package com.example.customer.api
import org.joinedworkz.facilities.common.profiles.base
platform Base
methodtype tracedRead GET
consumeHeaders='x-request-id','x-tenant-id'
success=200
resource /customers {
tracedRead()
}Declare consumeHeaders on a reusable method type or directly on a resource method. A local declaration replaces the complete inherited list. It does not append names to that list. Use lowercase dash-separated HTTP names in public models so the modeled and generated wire names are identical. Camel-case values are converted to lowercase dash-separated OpenAPI names; for example, xRequestId becomes x-request-id.
The Base OpenAPI generator emits one optional string header parameter per name. Names are normalized before they are compared, so declarations such as xRequestId and x-request-id identify the same wire header and are emitted once, in first-declaration order. An operation whose only parameters are request headers still receives a valid parameters section:
parameters:
- name: x-request-id
in: header
schema:
type: stringBase describes this static HTTP contract. It does not read incoming requests or pass header values to application code; runtime binding is defined by the selected target-platform Facility. SpringBoot's binding is documented under Request headers and handler signatures.
Use consumeHeaders even for a single header. consumeHeader is a deprecated compatibility alias. It still supplies the canonical property and reports a deprecation diagnostic, but it should not be used in new or updated models. The general alias conflict behavior and migration table are in the upgrade guide.
2.3 OpenAPI documentation and examples
The Base OpenAPI cartridge reads normalized CMN documentation. Authors use the platform-independent syntax described under Documentation, descriptions and examples; Base defines where that metadata appears in its generated OpenAPI document.
| CMN metadata | Generated OpenAPI position |
|---|---|
| operation description | operation description |
operation @summary | operation summary |
operation @request description | requestBody.description, including multipart file requests |
examples inside @request | non-multipart request media type examples |
operation @response description | primary CMN result's concrete OpenAPI response description |
examples inside @response | primary CMN result's response media type examples |
| documentation on an explicitly modeled status response | that status response's description |
| examples on an explicitly modeled status response | that status response's media type examples |
| complex-type documentation | component schema description |
| field documentation, otherwise simple-type documentation | property schema description |
| examples on types and fields | generated request/response media examples |
For a response description, Base selects the first available value in this order:
- documentation attached directly to the explicitly modeled status response;
@responseon the operation for its primary CMN result;- the short quoted result description;
- the standard HTTP-status text.
For a non-multipart request media example, an example inside @request takes precedence over examples derived from the request representation. A multipart file request uses the modeled @request description but does not attach modeled examples to its generated file schema. For a response, Base selects an example attached directly to the modeled status response first, then an example inside @response for the primary CMN result, and then an example derived from the response representation. A direct example on the representation type takes precedence over a synthesized object. When Base synthesizes an object, each field value is selected in this order:
- an example on the effective field;
- an example reached through its source-field chain;
- an example on its simple type;
- the primitive generator fallback.
Valid JSON objects, arrays and scalar values in an application/json example are emitted as structured OpenAPI values. A historical value that is not valid JSON remains a string for compatibility; one-line strings are safely quoted. A standalone multiline string is emitted as a YAML block scalar. If the response uses a query or context wrapper, the example value is embedded in the structured wrapper JSON instead. Use valid JSON for object and array contracts so the example has the same value kind as its schema.
For operations merged into one path and verb, Base uses the first non-blank modeled operation description, summary and request description. Request and response examples remain scoped to their media type. If merged operations contribute the same named example to one request media type, or to one response status and media type, Base emits that name once and keeps the first modeled value. Choose unique, stable names when the examples represent different cases.
The primary CMN result normally becomes a concrete success response such as 200 or 201. It is distinct from OpenAPI's default: response key; Base uses that key separately for the configured generic error fallback.
The neutral Java REST example contains named request, primary-result and status-specific examples and asserts their generated locations. The static Base document is independent of SpringDoc's runtime processing of Java annotations; the SpringBoot metadata boundary documents that separate output path.
3. Types
Basic:
type Greeting {
message*: String
}Complex types show up in datatype diagrams (hierarchy, references).
4. Pseudocode (optional)
CMN includes pseudocode syntax inside provided component resources. Diagram generation uses this model content to create sequence diagrams:
This is an independent Greeting follow-on, not part of the minimal one-model Quickstart.
component GreetingBackend {
provide /hello namespaceSuffix='greeting.v1' controller="GreetingV1Controller" {
read {
if 'is morning' {
[[ return 'Good Morning' ]]
} else 'is evening' {
[[ return 'Good Evening' ]]
} else {
[[ return 'Hello']]
}
}
}
}5. Layers
Layers can be defined:
core package com.example.demo
platform Baseapi package com.example.demo.api
platform BaseThe declared CMN layer normally becomes the effective layer for generated output. Base does not attach additional semantics to particular layer names, but exact layer-specific mappings can route its OpenAPI and diagram outlets. A specialized generator can assign another effective layer to its own output. See the multi-module outlet guide.
6. Summary
The Base facility allows you to:
- define types
- define REST resources
- use method types
- model processes
- generate OpenAPI and diagrams
