Daniel Bryant, Simon and I recently had a discussion about how to represent system communication with external APIs. The requirement for integration with external APIs is now extremely common but it's not immediately obvious how to clearly show them in architectural diagrams.
How to Represent an External System?
The first thing we discussed was what symbol to use for a system supplying an API. Traditionally, UML has used the Actor (stick man) symbol to represent a "user or any other system that interacts with the subject" (UML Superstructure Specification, v2.1.2). Therefore a system providing an API may look like this:
I've found that this symbol tends to confuse those who aren't well versed in UML as most people assume that the Actor symbol always represents a *person* rather than a system. Sometimes this is stereotyped to make it more obvious e.g.
However the symbol is very powerful and tends to overpower the stereotype. Therefore I prefer to use a stereotyped box for an external system supplying an API. Let's compare two context diagrams using Boxes vs Stick Actors.
In which diagram is it more obvious what are systems or people?
Note that ArchiMate has a specific symbol for Application Service that can be used to represent an API:
(Application Service notation from the Open Group's ArchiMate 2.1 Specification)
An API or the System that Supplies it?
Whatever symbol we choose, what we've done is to show the *system* rather than the actual API. The API is a definition of a service provided by the system in question. How should we provide more details about the API?
There are a number of ways we could do this but my preference is to give details of the API on the connector (line connecting two elements/boxes). In C4 the guidelines for a container diagram includes listing protocol information on the connector and an API can be viewed as the layer above the protocol. For example:
Multiple APIs per External System
Many API providers supply multiple services/APIs (I'm not referring to different operations within an API but multiple sets of operations in different APIs, which may even use different underlying protocols.) For example a financial marketplace may have APIs that do the following:
- Allow a bulk, batch download of static data (such as details of companies listed on a stock market) via xml over HTTP.
- Supply real time, low latency updates of market prices via bespoke messages over UDP.
- Allow entry of trades via industry standard FPML over a queuing system.
- Supply a bulk, batch download of trades for end-of-day reconciliation via FPML over HTTP.
Two of the services use the same protocol (xml over HTTP) but have very different content and use. One of the APIs is used to constantly supply information after user subscription (market data) and the last service involves the user supplying all the information with no acknowledgment (although it should reconcile at EOD).
There are multiple ways of showing this. We could:
- Have a single service element, list the APIs on it and have all components linking to it.
- Show each service/API as a separate box and connect the components that use the individual service to the relevant box.
- Show a single service element with multiple connections. Each connection is labeled and represents an API.
- Use a Port and Connector style notation to represent each API from the service provider. Provide a key for the ports.
- Use a UML style 'cup and ball' notation to define interfaces and their usage.
Some examples are below:
A Single Service element and simple description
In the above diagram the containers are stating what they are using but contain no information about how to use the APIs. We don't know if it is a single API (with different operations) or anything about the mechanisms used to transport the data. This isn't very useful for anyone implementing a solution or resolving operational issues.
Single, Service box with descriptive connectors
In this diagram there is a single, service box with descriptive connectors. The above diagram shows all the information so is much more useful as a diagnostic or implementation tool. However it does look quite crowded.
Services/APIs shown as separate boxes
Here the external system has its services/APIs shown as separate boxes. This contains all the information but might be mistaken as defining the internal structure of the external system. We want to show the services it provides but we know nothing about the internal structure.
Using Ports to Represent APIs
In the above diagram the services/APIs are shown as 'ports' on the external system and the details have been moved into a separate key/table. This is less likely to be mistaken as showing any internal structure of the external service. (Note that I could have also shown outgoing rPorts from the Brokerage System.)
This final diagram is using a UML style interface provider and requirer. This is a clean diagram but requires the user to be aware of what the cup and ball means (although I could have explained this in the key).
Any of these solutions could be appropriate depending on the complexity of the API set you are trying to represent. I'd suggest starting with a simple representation (i.e. fully labeled connections) and moving to a more complex one if needed BUT remember to use a key to explain any elements you use!