Appearance
Components and applications
This page explains how to model components and applications in the canonical model and how they relate to APIs and generation.
We focus on:
- component definitions and provided endpoints
- optional pseudo-code for documenting behaviour
- applications as compositions of components
- what generators typically do with this information
It builds on the concepts from:
1. Components
A component represents a deployable building block in your system. It groups API endpoints and (optionally) behaviour that belongs together.
Typical examples:
- a backend service
- a microservice or bounded context
- a web API with a set of controllers
In the canonical model, a component:
- provides resources/endpoints from your API model,
- can be linked to implementation artefacts (e.g. Java controllers) via attributes like
basePackageandcontroller, - can optionally contain pseudo-code to document the internal flow of a call for documentation and diagrams.
1.1 Basic component definition
A minimal component definition for the quickstart example looks like this:
text
package com.example.joindeworkz.quickstart.backend
import com.example.joindeworkz.quickstart
platform Base
component QuickstartBackend basePackage='com.example.joindeworkz.quickstart.webapp' {
provide /hello subPackage='greeting.v1' controller="GreetingV1Controller" { }
}Key points:
- The package
com.example.joindeworkz.quickstart.backenddefines the namespace of the component. - The component is named
QuickstartBackend. - The attribute
basePackageindicates where the platform should place generated implementation artefacts (for example Java controllers) for this component. - The
import com.example.joindeworkz.quickstartmakes the API model (resource/hello) available so it can be provided by the component. - The
platform Baseselects theBaseplatform, which among other things includes the OpenAPI and diagram cartridges.
1.2 Provided endpoints
Inside a component you declare which API endpoints it provides. In the example:
text
provide /hello subPackage='greeting.v1' controller="GreetingV1Controller" { }This means:
- The component
QuickstartBackendimplements the resource/hellodefined in the imported API model. - The implementation is grouped under the
subPackagegreeting.v1below the component'sbasePackage(platforms use this to compute final package names). - The implementation class (e.g. a controller in a Spring Boot platform) is called
GreetingV1Controller.
Different platforms may use this information in different ways. For example:
- A Spring Boot platform could generate a
GreetingV1Controllerclass in a package derived frombasePackageandsubPackage. - The OpenAPI cartridge of the
Baseplatform can use thecontrollername as a tag in the generated OpenAPI documents. - Diagram cartridges can show which endpoints belong to which component.
2. Optional pseudo-code for behaviour
Components can optionally contain pseudo-code that documents the behaviour of individual endpoints. This pseudo-code is not executable business logic – it is used for diagrams and documentation.
Extending the previous example:
text
component QuickstartBackend basePackage='com.example.joindeworkz.quickstart.webapp' {
provide /hello subPackage='greeting.v1' controller="GreetingV1Controller" {
read {
if 'is morning' {
[[ return 'Good Morning' ]]
} else 'is evening' {
[[ return 'Good Evening' ]]
}
}
}
}Here:
- The
readblock corresponds to thereadendpoint on/hello. - Inside the block you describe the flow as pseudo-code:
- conditions (
if 'is morning',else 'is evening'), - actions (
[[ return 'Good Morning' ]],[[ return 'Good Evening' ]]).
- conditions (
The diagram cartridge of the Base platform can turn this into a sequence-like diagram that visualises the flow of the endpoint. This is useful for:
- documentation,
- discussions with other developers or stakeholders,
- understanding complex flows without reading implementation code.
Important:
- Pseudo-code is optional. Components are still useful without it (for assigning endpoints to components and driving generation).
- The exact pseudo-code syntax is intentionally lightweight and focused on readability. Details belong in the DSL reference and the documentation of the diagram cartridge.
3. Applications
An application is a top-level model element that represents a runnable system composed of components.
Applications are used to:
- get an overview of which components belong to a specific app,
- visualise dependencies between own and external components,
- generate a combined OpenAPI document for all endpoints of the application,
- generate an HTML page with an embedded OpenAPI viewer for that document.
3.1 Basic application definition
Continuing the quickstart example:
text
application QuickstartApp {
consists of {
QuickstartBackend
}
use {
// referenced components
}
}Meaning:
- The application is called
QuickstartApp. - It consists of the component
QuickstartBackend. These are the components that are part of the application itself. - The optional
usesection can list external components that this application depends on (for example shared or third-party components).
Platforms and cartridges can use this information to:
- draw a component diagram showing the application and its components,
- highlight dependencies between internal and external components,
- determine which endpoints belong to a given application when generating aggregated artefacts.
3.2 Aggregated OpenAPI and viewer
Using the information from components and applications, the OpenAPI cartridge in the Base platform can:
- generate an OpenAPI YAML that contains all endpoints of the application,
- group operations under tags derived from controller names (such as
GreetingV1Controller), - generate an HTML file that embeds an OpenAPI viewer for this document.
This gives you a convenient, application-centric view of your API:
- one document per application,
- grouped by controllers/tags,
- directly derived from the canonical model.
4. How components and applications fit in
Putting it all together:
- APIs (
resource/service) define what is exposed. - Components define who provides which part of the API and how this maps to implementation artefacts (controllers, packages, etc.).
- Optional pseudo-code inside components documents how calls are handled and enables generation of behavioural diagrams.
- Applications assemble components into runnable systems and define the scope for application-wide artefacts such as combined OpenAPI documents and component diagrams.
Because components and applications live in the canonical model, you can:
- reuse the same component/application structure across different platforms,
- generate diagrams, OpenAPI and implementation artefacts from a single source of truth,
- evolve your technical stack while keeping the logical architecture stable.
5. Next steps
From here you can:
- read about Profiles & platforms (.profil) to see how platforms configure cartridges (including diagram and API generators) and interpret component/application models;
- explore Modeling with JoinedWorkz Studio for details on how components and applications are visualised and edited in the Studio;
- consult the CMN reference for the exact syntax of component and application definitions and pseudo-code blocks.
