I've been really enjoying seeing how Mermaid.js lets you generate technical diagrams from simple markdown. Previously I've shown how Mermaid.js allows you to create entity relationship diagrams and class diagrams, but in this article we'll cover a far more complex diagram: the sequence diagram.
I distinctly remember working on sequence diagrams in my undergraduate computer science education and having so many issues trying to get the various boxes and arrows to look standard, rearrange shapes as I needed to expand the diagram, and generally focusing on anything but the logic the diagrams intended to create.
Mermaid.js is the solution I needed 20 years ago.
With Mermaid.js you can write a few lines of text and use its JavaScript library to generate a professional sequence diagram like the one below:
This means your time is focused on actually writing the interaction logic instead of generating a visual. It also means that the diagram source is easily version-controlled and anyone on your team can modify it without special tooling or licenses.
Mermaid.js is available in a variety of tools, but I most frequently use it in GitHub markdown files and in Polyglot Notebooks.
What are Sequence Diagrams?
For those of you who haven't been exposed, sequence diagrams describe a series of messages in a sequence between different objects.
Sequence diagrams represent systems and individuals as vertical columns and messages between these parts as horizontal lines that move across the various lanes to show how data flows between different pieces of the system.
This can help explain complex logic and interactions with a technical diagram and identify areas of confusion or misunderstanding.
If you're curious about sequence diagrams in general, a good starting point might be Visual Paradigm's Guide to Sequence Diagrams.
Over the course of this article, we'll create and expand a sequence diagram to explain JSON Web Token (JWT) authentication. However, the focus of the article's text will be on the diagrams themselves, not the process of JWT authentication. If you're curious about this, however, I do have an article and video on understanding JWT authentication.
Basic Sequence Diagrams
Let's start with a simple sequence diagram representing a message from the client to the server and the server's response back.
sequenceDiagram
Client->>Server: Login (Username, Password)
Server-->>Client: 200 OK & JWT
Here we start by specifying that the Mermaid diagram we want to use is a sequence diagram.
Next, we declare a message from a Client to the Server. The ->>
arrow indicates that the message is intended to be synchronous. The value after the :
describes the contents of the message.
Note: for asynchronous messages you would indicate them with -)
. This will not appear in the examples in this article
The -->>
arrow (note the two dashes instead of one) indicates a dotted line return value
Now that we've seen a simple message between two systems, let's show the database's role in fulfilling the request:
sequenceDiagram
Client->>Server: Login (Username, Password)
Server->>Database: Select User Info
Database-->>Server: Salt & Hash
Server-->>Client: 200 OK & JWT
Here by adding the Database
node and illustrating the message was sent from the server to the database, our diagram automatically expands.
Also note that systems appear in the order in which they're first mentioned, with the first system on the left and the last being at the right.
Aliases and Actors
Because typing Client
and Server
can get tedious, Mermaid.js gives us a way of creating aliases for our systems by declaring them at the top of the sequenceDiagram
block.
This also gives us an opportunity to tweak the order of the systems shown, if we wanted to swap the order of the Database and Server, for example:
sequenceDiagram
participant C as Client
participant DB as Database
participant S as Server
C->>S: Login (Username, Password)
S->>DB: Select User Info
DB-->>S: Salt & Hash
S-->>C: 200 OK & JWT
Here C
, S
, and DB
are all aliases used in the actual message lines while their full names still show up in the generated diagram.
If you wanted to indicate that a system is actually an actor (typically something involving a human user), you can use the word actor
instead of participant
and the diagram will update.
sequenceDiagram
actor C as Client
participant S as Server
participant DB as Database
C->>S: Login (Username, Password)
S->>DB: Select User Info
DB-->>S: Salt & Hash
S-->>C: 200 OK & JWT
Notes and Sequence Numbers
Often you'll want to annotate your diagrams with notes.
Notes allow you to show the reader helpful text and can be placed over a single system or over two different systems using the note
syntax:
sequenceDiagram
actor C as Client
participant S as Server
participant DB as Database
C->>S: Login (Username, Password)
S->>DB: Select User Info
note over DB: Password is not stored in database
DB-->>S: Salt & Hash
S-->>C: 200 OK & JWT
note over C, S: Subsequent requests include JWT
The placement of notes does matter and trying a few different approaches when using notes may be necessary to get the effect you're looking for.
It can be helpful to include sequence numbers in your diagram. This aids in verbal communication and helps novice sequence diagram readers understand the sequence you're trying to communicate.
Adding numbers is as simple as adding the autonumber
line to the beginning of your sequenceDiagram
in Mermaid.
sequenceDiagram
autonumber
actor C as Client
participant S as Server
participant DB as Database
C->>S: Login (Username, Password)
S->>DB: Select User Info
note over DB: Password is not stored in database
DB-->>S: Salt & Hash
S-->>C: 200 OK & JWT
note over C, S: Subsequent requests include JWT
Note: despite the name autonumber
, I've not seen a way of manually assigning sequence numbers (not that I'd want to: autonumber works great!)
Self-Referential Messaging
Sometimes you want to indicate logic that goes on inside of a system.
For example, the server is responsible for verifying the user's login credentials and generating a JWT. These are both complex operations that should be represented on the diagram, yet do not involve other systems.
In cases like this, you can indicate that a system communicates with itself or does something computationally complex by adding a message from the system to itself as shown below:
sequenceDiagram
autonumber
actor C as Client
participant S as Server
participant DB as Database
C->>S: Login (Username, Password)
S->>DB: Select User Info
note over DB: Password is not stored in database
DB-->>S: Salt & Hash
S->>S: Check Computed Hash using Salt
S->>S: Generate JWT
S-->>C: 200 OK & JWT
note over C, S: Subsequent requests include JWT
If / Else with Alt Blocks
The sequence diagram is coming along nicely and now shows us the "happy path" of our system where nothing went wrong.
However, sometimes you need to be able to illustrate more complex logic such as if statements, loops, error handling, or other special cases.
Mermaid.js gives us different syntax for special blocks, but the code below will use the alt
and else
keywords to illustrate what happens when a user gives valid credentials and invalid credentials:
sequenceDiagram
autonumber
actor C as Client
participant S as Server
participant DB as Database
C->>S: Login (Username, Password)
S->>DB: Select User Info
note over DB: Password is not stored in database
DB-->>S: Salt & Hash
S->>S: Check Computed Hash using Salt
alt Computed Hash Matches
S->>S: Generate JWT
S-->>C: 200 OK & JWT
else No user or wrong password
S-->>C: 401 Unauthorized
end
note over C, S: Subsequent requests include JWT
Here alt
is equivalent to an if
statement in programming while else
and end
are generally understandable to various concepts in conditional logic.
Also note that I am using indentation to help clarify statements as part of the alt
or else
blocks. This indentation is optional, but significantly helps readability in my experience.
Indicating Activation
Finally, our sequence diagram is missing one thing common to the UML Sequence Diagrams I created back in college: activation boxes.
Typically, you draw boxes around objects while they are actively working to solve your task. This helps illustrate which systems are active or waiting at any given time.
Mermaid.js gives us the activate
and deactivate
keywords that govern the scope of these box shapes as shown below:
sequenceDiagram
autonumber
actor C as Client
participant S as Server
participant DB as Database
C->>S: Login (Username, Password)
activate S
S->>DB: Select User Info
activate DB
note over DB: Password is not stored in database
DB-->>S: Salt & Hash
deactivate DB
S->>S: Check Computed Hash using Salt
alt Computed Hash Matches
S->>S: Generate JWT
S-->>C: 200 OK & JWT
else No user or wrong password
S-->>C: 401 Unauthorized
end
deactivate S
note over C, S: Subsequent requests include JWT
Here again I use indentation to help make the scopes more explicit.
Warning: in Mermaid.js invalid diagrams can be hard to diagnose and I've found activation and deactivation to be particularly finnicky, especially when working with scopes like the alt
and else
blocks. I recommend you work iteratively and frequently test your diagrams as you expand them or make refinements.
Mermaid.js sequence diagrams allow you to skip the activate
and deactivate
lines to keep your diagrams condensed by adding a +
and -
syntax to messages.
For example, the following code activates the server with a login call:
C->>S: Login (Username, Password)
activate S
We can combine these two lines instead by writing the code as C->>+S: Login (Username, Password)
. (Note the +
after the >>
and before the :
)
In a similar manner, we can replace code to deactivate a node such as the following:
DB-->>S: Salt & Hash
deactivate DB
This code can be replaced with a more concise DB-->>-S: Salt & Hash
line.
This transforms our earlier logic to the final logic below:
sequenceDiagram
autonumber
actor C as Client
participant S as Server
participant DB as Database
C->>+S: Login (Username, Password)
S->>+DB: Select User Info
note over DB: Password is not stored in database
DB-->>-S: Salt & Hash
S->>S: Check Computed Hash using Salt
alt Computed Hash Matches
S->>S: Generate JWT
S-->>C: 200 OK & JWT
else No user or wrong password
S-->>C: 401 Unauthorized
end
note over C, S: Subsequent requests include JWT
deactivate S
Ultimately, I don't think I like this shorthand and instead prefer to use the activate
/ deactivate
syntax for more readable sequence diagrams, but the option is there for you if you want it.
Next Steps
While sequence diagrams aren't necessarily beginner friendly, working with Mermaid.js sequence diagrams is exponentially less painful than trying to control a diagramming tool to generate and maintain these diagrams.
Personally, I find Mermaid.js diagrams so convenient to use that I now find myself making sequence diagrams where I normally wouldn't have before due to the time and frustration required to build one.
Ultimately, I think Mermaid.js Sequence Diagrams are a good strategic tool for diagramming complex interactions or communicating complex concepts in a visual way in your documentation.
If you'd like to learn more and see a few features I didn't cover, I recommend you check out Mermaid.js' sequence diagram documentation.
And finally, I'm not done exploring what modern software engineers can do with Mermaid.js so stay tuned for more content!
Top comments (0)