ALPS Tutorial for REST Applications
Introduction
Modern web applications (online shopping, social networks, video streaming services, business systems, etc.) are mostly built based on the REST architecture. In this tutorial, we will explain how to design applications using ALPS, considering the basic concepts of REST.
Essence of REST Applications
A REST application is essentially a “state transition system.” For example:
- Search for a product, add it to the cart, and confirm the order (online shopping)
- Read posts, react, and leave comments (social network)
All of these actions can be viewed as “transitions” from one “state” to another, and a REST application manages these transitions.
What is State Transition?
State transition refers to a change from one state to another within a system. In web applications:
- Users are always “somewhere” (current state).
- They can move “somewhere else” (possible state transition).
- “How” to move is defined (transition method).
These three elements are the basics of a state transition system.
Two States in REST
In addition to the states used in state transitions, REST has two important types of states:
- Application State
- Represents the client (browser) location, expressed as URLs
- Resource State
- Represents the state of data managed on the server
The client accesses resource states by changing its application state, and the server responds with both resource states and network affordances that describe possible state transitions.
Basic Flow of State Transitions in REST Applications
State transitions in REST applications proceed as follows:
- Recognize the Current State
- The client understands the current state and the available information.
- Choose a Transition
- The client checks the provided links and actions, then chooses the next transition.
- Execute the Transition
- The client performs the chosen action, moving to a new state.
This flow repeats continuously throughout the use of the application.
Information Architecture and ALPS
To properly design a REST application, the state transition system needs to be systematically documented. Dan Klyn has proposed three important aspects needed for this documentation:
- Ontology
- Defines “what something means.”
- Example: The meaning of terms such as “blog post” or “creation date.”
- Shares the same meaning of terms.
- Taxonomy
- Organizes “how things relate.”
- Example: A “blog post” has a “creation date” and “body.”
- Defines the structure of information.
- Choreography
- Describes “how things work.”
- Example: Viewing, creating, updating, and deleting posts.
- Shows the flow of actions.
ALPS is a means to practically express these concepts. In the following sections of this tutorial:
- Ontology: Define the basic terms.
- Taxonomy (1): Define the information structure.
- Choreography: Define state transitions.
- Taxonomy (2): Integrate states and transitions.
We will learn the specific implementation methods.
Ontology: Defining Terms
Ontology defines the meaning of terms used in the application. Clearly defining these terms at this stage helps create a shared understanding among the team and ensures consistent API design.
Setting Up the Editor
- Open https://editor.app-state-diagram.com/ in your browser.
- Delete all the demo code displayed in the left editor pane.
Defining the First Term
Below is an example definition for the term “creation date.”
In XML:
<?xml version="1.0" encoding="UTF-8"?>
<alps
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="https://alps-io.github.io/schemas/alps.xsd">
<descriptor id="dateCreated" title="Creation Date">
<doc format="text">Represents the date the post was created, in ISO8601 format</doc>
</descriptor>
</alps>
In JSON:
{
"$schema": "https://alps-io.github.io/schemas/alps.json",
"alps": {
"version": "1.0",
"descriptor": [
{"id": "dateCreated", "title": "Creation Date", "doc": {"format": "text", "value": "Represents the date the post was created, in ISO8601 format"}}
]
}
}
Explanation of each element in this definition:
id
Attribute- The identifier for the term.
title
Attribute- A short, human-readable description used for display in UI or documentation.
doc
Element- Describes the precise meaning and usage of the term.
- Specifies the format attribute (e.g., text).
Defining the Article Body
Next, we add a term that represents the body of a blog post.
In XML:
<?xml version="1.0" encoding="UTF-8"?>
<alps
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="https://alps-io.github.io/schemas/alps.xsd">
<descriptor id="dateCreated" title="Creation Date">
<doc format="text">Represents the date the post was created, in ISO8601 format</doc>
</descriptor>
<descriptor id="articleBody" title="Article Body">
<doc format="text">The body of the blog post</doc>
</descriptor>
</alps>
In JSON:
{
"$schema": "https://alps-io.github.io/schemas/alps.json",
"alps": {
"version": "1.0",
"descriptor": [
{"id": "dateCreated", "title": "Creation Date", "doc": {"format": "text", "value": "Represents the date the post was created, in ISO8601 format"}},
{"id": "articleBody", "title": "Article Body", "doc": {"format": "text", "value": "The body of the blog post"}}
]
}
}
Key Points of Ontology Definition
- Naming Conventions
- Prioritize semantic terms.
- Use consistent naming patterns.
- CamelCase is recommended (e.g., dateCreated, articleBody).
- Writing Descriptions
- Aim for concise and clear descriptions.
- Include examples if necessary.
- Specify formats or constraints if applicable.
Taxonomy: Structuring Information
Taxonomy defines “how to organize and classify information.” By combining the terms we defined earlier, we can represent larger concepts.
A blog post (BlogPosting) can be defined as a collection of information with a creation date and body.
In XML:
<?xml version="1.0" encoding="UTF-8"?>
<alps
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="https://alps-io.github.io/schemas/alps.xsd">
<descriptor id="dateCreated" title="Creation Date">
<doc format="text">Represents the date the post was created, in ISO8601 format</doc>
</descriptor>
<descriptor id="articleBody" title="Article Body">
<doc format="text">The body of the blog post</doc>
</descriptor>
<descriptor id="BlogPosting" title="Blog Post">
<descriptor href="#dateCreated"/>
<descriptor href="#articleBody"/>
</descriptor>
</alps>
In JSON:
{
"$schema": "https://alps-io.github.io/schemas/alps.json",
"alps": {
"version": "1.0",
"descriptor": [
{"id": "dateCreated", "title": "Creation Date", "doc": {"format": "text", "value": "Represents the date the post was created, in ISO8601 format"}},
{"id": "articleBody", "title": "Article Body", "doc": {"format": "text", "value": "The body of the blog post"}},
{"id": "BlogPosting", "title": "Blog Post", "descriptor": [
{"href": "#dateCreated"},
{"href": "#articleBody"}
]}
]
}
}
Key Points of Structuring
- Reference by
href
- Use
#
to refer to existing terms. - Allows reuse of the same definitions multiple times.
- Ensures consistency of terms.
- Use
- Representation of Hierarchical Structure
BlogPosting
includesdateCreated
andarticleBody
.- The included elements are represented using the
descriptor
tag. - Represented as a parent-child relationship.
Preview in Editor
- Vocabulary List
- Defined terms are displayed hierarchically.
- Elements contained within
BlogPosting
are displayed.
- State Diagram
BlogPosting
is displayed as a single state.- No transitions are defined at this stage.
Why Structuring is Important
- Clarification of Relationships
- Which information belongs to which concept.
- Visualization of dependencies between pieces of information.
- Consistent API
- The same structure is always represented in the same way.
- Makes implementation on the client side easier.
- Role as Documentation
- Understanding the system as a whole.
- Establishing a common understanding of the information structure.
Choreography: Defining State Transitions
Choreography defines state transitions according to the types of operations. In ALPS, operations are categorized as follows:
Operation | Type | HTTP Method Description |
---|---|---|
safe | GET | Changes only application state |
unsafe | POST | Creates new resource state |
idempotent | PUT/DELETE | Updates/deletes resource state |
safe
- Changes only the application state (e.g., GET).
- Resource state is not altered.
unsafe
- Creates a new resource state.
- May have different outcomes each time it is executed.
idempotent
- Updates or deletes the resource state.
- Produces the same outcome no matter how many times it is executed.
ALPS operations distinguish between resource changes that have a different result each time they are performed, i.e., non-idempotent operations, such as add operations, and those that have a different result each time they are performed, i.e., idempotent operations, such as change or delete operations, which do not change the result no matter how many times they are repeated.
Defining the Transition to View an Article
First, let’s define a safe
operation to view a blog post:
In XML:
<?xml version="1.0" encoding="UTF-8"?>
<alps
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="https://alps-io.github.io/schemas/alps.xsd">
<descriptor id="dateCreated" title="Creation Date">
<doc format="text">Represents the date the post was created, in ISO8601 format</doc>
</descriptor>
<descriptor id="articleBody" title="Article Body">
<doc format="text">The body of the blog post</doc>
</descriptor>
<descriptor id="BlogPosting" title="Blog Post">
<descriptor href="#dateCreated"/>
<descriptor href="#articleBody"/>
</descriptor>
<descriptor id="goBlogPosting" type="safe" rt="#BlogPosting" title="View Blog Post">
<descriptor href="#dateCreated"/>
</descriptor>
</alps>
In JSON:
{
"$schema": "https://alps-io.github.io/schemas/alps.json",
"alps": {
"version": "1.0",
"descriptor": [
{"id": "dateCreated", "title": "Creation Date", "doc": {"format": "text", "value": "Represents the date the post was created, in ISO8601 format"}},
{"id": "articleBody", "title": "Article Body", "doc": {"format": "text", "value": "The body of the blog post"}},
{"id": "BlogPosting", "title": "Blog Post", "descriptor": [
{"href": "#dateCreated"},
{"href": "#articleBody"}
]},
{"id": "goBlogPosting", "type": "safe", "rt": "#BlogPosting", "title": "View Blog Post", "descriptor": [
{"href": "#dateCreated"}
]}
]
}
}
Important elements of this definition:
- Prefix Naming Convention
- Use
go
forsafe
transitions. - Use
do
forunsafe
andidempotent
transitions.
- Use
type
Attribute- Specifies the type of operation.
- In this case, it is
safe
(a safe transition).
rt
(return type) Attribute- Specifies the destination state.
- Indicates a transition to
#BlogPosting
.
- Information Needed for the Transition
- Specified by
descriptor href="#dateCreated"
. - Represents the information needed to identify the post.
- Specified by
In the preview screen:
- The state diagram shows the state (
BlogPosting
) and an arrow representing the transition. - The vocabulary list displays information about the transition (
goBlogPosting
).
Defining the Transition to Create an Article
Next, let’s define an unsafe
operation to create a new blog post:
In XML:
<descriptor id="doCreateBlogPosting" type="unsafe" rt="#BlogPosting" title="Create Blog Post">
<descriptor href="#articleBody"/>
</descriptor>
In JSON:
{"id": "doCreateBlogPosting", "type": "unsafe", "rt": "#BlogPosting", "title": "Create Blog Post", "descriptor": [
{"href": "#articleBody"}
]}
Important elements of this definition:
- Prefix Naming Convention
- Use
do
forunsafe
transitions.
- Use
type
Attribute- Specifies the type of operation.
- In this case, it is
unsafe
(a state-changing operation).
rt
(return type) Attribute- Specifies the destination state.
- Indicates a transition to
#BlogPosting
.
- Information Needed for the Transition
- Specified by
descriptor href="#articleBody"
. - Represents the information needed to create the post.
- Specified by
In the preview screen:
- The state diagram shows the state (
BlogPosting
) and an arrow representing the transition (doCreateBlogPosting
). - The vocabulary list displays information about the transition (
doCreateBlogPosting
).
Defining the Transition to Update an Article
Now, let’s define an idempotent
operation to update a blog post:
In XML:
<descriptor id="doUpdateBlogPosting" type="idempotent" rt="#BlogPosting" title="Update Blog Post">
<descriptor href="#articleBody"/>
</descriptor>
In JSON:
{"id": "doUpdateBlogPosting", "type": "idempotent", "rt": "#BlogPosting", "title": "Update Blog Post", "descriptor": [
{"href": "#articleBody"}
]}
Important elements of this definition:
- Prefix Naming Convention
- Use
do
foridempotent
transitions.
- Use
type
Attribute- Specifies the type of operation.
- In this case, it is
idempotent
(an operation that can be repeated without changing the result).
rt
(return type) Attribute- Specifies the destination state.
- Indicates a transition to
#BlogPosting
.
- Information Needed for the Transition
- Specified by
descriptor href="#articleBody"
. - Represents the information needed to update the post.
- Specified by
In the preview screen:
- The state diagram shows the state (
BlogPosting
) and an arrow representing the transition (doUpdateBlogPosting
). - The vocabulary list displays information about the transition (
doUpdateBlogPosting
).
Taxonomy (2): Integrating States and Transitions
So far, we have defined the terms (ontology), the information structure (taxonomy), and the state transitions (choreography). Now, let’s integrate these elements to represent the complete blog system.
In XML:
<descriptor id="Blog" title="Blog">
<descriptor href="#BlogPosting"/>
<descriptor href="#goBlogPosting"/>
<descriptor href="#doCreateBlogPosting"/>
<descriptor href="#doUpdateBlogPosting"/>
</descriptor>
In JSON:
{"id": "Blog", "title": "Blog", "descriptor": [
{"href": "#BlogPosting"},
{"href": "#goBlogPosting"},
{"href": "#doCreateBlogPosting"},
{"href": "#doUpdateBlogPosting"}
]}
This final structure represents the complete blog system, integrating all defined states and transitions.
Summary of Blog Structure
- Information Structure
- BlogPosting: Represents the structure of a blog post (with
dateCreated
andarticleBody
).
- BlogPosting: Represents the structure of a blog post (with
- State Transitions
- goBlogPosting: A
safe
operation to view a blog post. - doCreateBlogPosting: An
unsafe
operation to create a new blog post. - doUpdateBlogPosting: An
idempotent
operation to update an existing blog post.
- goBlogPosting: A
- Complete Blog System
- Blog: Integrates all states (
BlogPosting
) and transitions (goBlogPosting
,doCreateBlogPosting
,doUpdateBlogPosting
).
- Blog: Integrates all states (
In the preview screen:
- The state diagram shows the complete structure of the blog system.
- The vocabulary list displays all defined elements and their relationships.
Conclusion: ALPS as a Design Methodology
In this tutorial, we learned how to use ALPS to design a blog system:
- Ontology: Defining terms and their meanings.
- Taxonomy: Structuring information.
- Choreography: Defining state transitions.
- Integration: Combining states and transitions to represent the complete system.
Using ALPS allows for clear and consistent API design, shared understanding among team members, and effective documentation.
The ALPS approach may initially seem like extra work, but as the project grows, its value becomes evident. Consistent design, clear documentation, and effective communication are key contributors to the long-term success of a project.