How to Design a REST API

Follow these steps to design a REST API – Identify Object Model, Create Resource URIs, Determine Representations and Assign HTTP Methods.

Learning REST in pieces is one thing while applying all these concepts to real application development is completely another challenge.

This tutorial will teach us to design REST APIs for a network-based application. Please note that the takeaway from this whole exercise is learning how to apply REST principles in the application design process.

How to Design a REST API

1. Identify the Resources – Object Modeling

The first step in designing a REST API-based application is identifying the objects that will be presented as resources.

For a network-based application, object modeling is pretty much more straightforward. There can be many things such as devices, managed entities, routers, modems, etc. For simplicity’s sake, we will consider only two resources i.e.

  • Devices
  • Configurations

Here configuration may be a sub-resource of a device. A device can have many configuration options.

Note that both objects/resources in our above model will have a unique identifier, which is the integer id property.

2. Create Model URIs

Now when the object model is ready, it’s time to decide the resource URIs. At this step, while designing the resource URIs – focus on the relationship between resources and their sub-resources. These resource URIs are endpoints for APIs.

In our application, a device is a top-level resource. And, configuration is a sub-resource under the device. Let’s write down the URIs.

/devices
/devices/{id}

/configurations
/configurations/{id}

/devices/{id}/configurations
/devices/{id}/configurations/{configId}

Notice that these URIs do not use any verb or operation. It’s crucial not to include any verb in URIs. URIs should all be nouns only.

3. Determine Resource Representations

Now that resource URIs have been decided, let’s work on their representations. Most representations are defined in either XML or JSON format. We will see XML examples as it is more expressive of how data is composed.

3.1. Collection Resource of Devices

When returning a collection resource, include only the most important information about that resource. This will keep the size of the response payload small, and so will improve the performance of the API.

<devices size="2">

	<link rel="self" href="/devices"/>

	<device id="12345">
		<link rel="self" href="/devices/12345"/>
		<deviceFamily>apple-es</deviceFamily>
		<OSVersion>10.3R2.11</OSVersion>
		<platform>SRX100B</platform>
		<serialNumber>32423457</serialNumber>
		<connectionStatus>up</connectionStatus>
		<ipAddr>192.168.21.9</ipAddr>
		<name>apple-srx_200</name>
		<status>active</status>
	</device>

	<device id="556677">
		<link rel="self" href="/devices/556677"/>
		<deviceFamily>apple-es</deviceFamily>
		<OSVersion>10.3R2.11</OSVersion>
		<platform>SRX100B</platform>
		<serialNumber>6453534</serialNumber>
		<connectionStatus>up</connectionStatus>
		<ipAddr>192.168.20.23</ipAddr>
		<name>apple-srx_200</name>
		<status>active</status>
	</device>

</devices>

3.2. Single Device Resource

Opposite to collection URI, a single resource URI includes complete information about a particular device. It also includes a list of links to sub-resources and other supported operations. This will make your REST API HATEOAS driven.

<device id="12345">
	<link rel="self" href="/devices/12345"/>

	<id>12345</id>
	<deviceFamily>apple-es</deviceFamily>
	<OSVersion>10.0R2.10</OSVersion>
	<platform>SRX100-LM</platform>
	<serialNumber>32423457</serialNumber>
	<name>apple-srx_100_lehar</name>
	<hostName>apple-srx_100_lehar</hostName>
	<ipAddr>192.168.21.9</ipAddr>
	<status>active</status>

	<configurations size="2">
		<link rel="self" href="/configurations" />

		<configuration id="42342">
			<link rel="self" href="/configurations/42342" />
		</configuration>

		<configuration id="675675">
			<link rel="self" href="/configurations/675675" />
		</configuration>
	</configurations>

	<method href="/devices/12345/exec-rpc" rel="rpc"/>
	<method href="/devices/12345/synch-config"rel="synch device configuration"/>
</device>

3.3. Collection Resource of Configurations

Similar to device collection representation, create configuration collection representation with only minimal information.

<configurations size="20">
	<link rel="self" href="/configurations" />

	<configuration id="42342">
		<link rel="self" href="/configurations/42342" />
	</configuration>

	<configuration id="675675">
		<link rel="self" href="/configurations/675675" />
	</configuration>
	…
	…
</configurations>

Please note that configurations collection representation inside device is similar to top-level configurations URI.

The only difference is that configurations for a device are only two, so only two configuration items are listed as subresources under the device.

3.4. Single Configuration Resource

Now, a single configuration resource representation must have all possible information about this resource – including relevant links.

<configuration id="42342">
	<link rel="self" href="/configurations/42342" />
	<content><![CDATA[…]]></content>
	<status>active</status>
	<link rel="very big raw configuration script" href="/configurations/42342/raw" />
</configuration>

3.5. Collection Resource of Configuration under a Single Device

This sub-collection of configurations will be a subset of the primary collection of configurations and will be specific to a device only.

As it is the subset of primary collection, DO NOT create a different representation data field than primary collection. Use the same presentation fields as the primary collection.

<configurations size="2">
	<link rel="self" href="/devices/12345/configurations" />

	<configuration id="53324">
		<link rel="self" href="/devices/12345/configurations/53324" />
		<link rel="detail" href="/configurations/53324" />
	</configuration>

	<configuration id="333443">
		<link rel="self" href="/devices/12345/configurations/333443" />
		<link rel="detail" href="/configurations/333443" />
	</configuration>
</configurations>

Notice that this sub-resource collection has two links. One for its direct representation inside sub-collection i.e. /devices/12345/configurations/333443 and others pointing to its location in the primary collection i.e. /configurations/333443.

Having two links is essential as you can provide access to a device-specific configuration more uniquely, and you will be able to mask some fields (if the design requires it), which shall not be visible in a secondary collection.

3.6. Single Configuration Resource under a Single Device

This representation should have either exactly a similar representation as of Configuration representation from the primary collection, OR you may mask a few fields.

This subresource representation will also have an additional link to its primary presentation.

<configuration id="11223344">
	<link rel="self" href="/devices/12345/configurations/11223344" />
	<link rel="detail" href="/configurations/11223344" />
	<content><![CDATA[…]]></content>
	<status>active</status>
	<link rel="raw configuration content" href="/configurations/11223344/raw" />
</configuration>

Now, before moving forward to the next section, let’s note down a few observations, so you don’t miss them.

  • Resource URIs are all nouns.
  • URIs are usually in two forms – collection of resources and singular resource.
  • Collection may be in two forms primary collection and secondary collection. A secondary collection is a sub-collection from a primary collection only.
  • Each resource/collection contains at least one link i.e. to itself.
  • Collections contain only the most important information about resources.
  • To get complete information about a resource, you only need to access its specific resource URI.
  • Representations can have extra links (i.e. methods in a single device). Here method represents a POST method. You can also have more attributes or form links in an altogether new way.
  • We have not talked about operations on these resources yet.

4. Assigning HTTP Methods

So our resource URIs and their representation are fixed now. Let’s decide all the applications’ possible operations and map those operations to the resource URIs.

For example, a user of our network application can browse, create, update, or delete devices from the network and create/deploy/remove the device configurations. So let’s assign these operations to respective resources.

4.1. Browse all devices or configurations [Primary Collection]

HTTP GET /devices
HTTP GET /configurations

If the collection size is large, you can also apply paging and filtering. e.g., the below requests will fetch the first 20 records from the collection.

HTTP GET /devices?startIndex=0&size=20
HTTP GET /configurations?startIndex=0&size=20

4.2. Browse all configurations under a device [Secondary Collection]

HTTP GET /devices/{id}/configurations

It will be mostly a small-size collection, so there is no need to enable filtering or sorting here.

4.3. Browse a single device or configuration

To get the complete detail of a device or configuration, use GET operation on singular resource URIs.

HTTP GET /devices/{id}
HTTP GET /configurations/{id}

4.4. Browse a single configuration under a device

HTTP GET /devices/{id}/configurations/{configId}

Subresource representation will be either same as or a subset of the primary presentation.

4.5. Create a device or configuration

CREATE is not an idempotent operation and in HTTP protocol – POST is also not idempotent. So use POST.

HTTP POST /devices
HTTP POST /configurations

Please note that the request payload will not contain any id attribute, as the server is responsible for deciding it. The response to CREATE request will look like this:

HTTP/1.1 201 Created
Content-Type: application/xml
Location: http://example.com/network-app/configurations/678678

<configuration id="678678">
	<link rel="self" href="/configurations/678678" />
	<content><![CDATA[…]]></content>
	<status>active</status>
	<link rel="raw configuration content" href="/configurations/678678/raw" />
</configuration>

4.6. Update a device or configuration

The update operation is an idempotent operation, and HTTP PUT is also an idempotent method. So we can use the PUT method for update operations.

HTTP PUT /devices/{id}
HTTP PUT /configurations/{id}

PUT response may look like this.

HTTP/1.1 200 OK
Content-Type: application/xml

<configuration id="678678">
	<link rel="self" href="/configurations/678678" />
	<content><![CDATA[. updated content here .]]></content>
	<status>active</status>
	<link rel="raw configuration content" href="/configurations/678678/raw" />
</configuration>

4.7. Remove a device or configuration

Removing is always a DELETE operation.

HTTP DELETE /devices/{id}
HTTP DELETE /configurations/{id}

A successful response SHOULD be 202 (Accepted) if the resource has been queued for deletion (async operation), or 200 (OK) / 204 (No Content) if the resource has been deleted permanently (sync operation).

In the case of async operation, the application shall return a task id that can be tracked for success/failure status.

Please note that you should put enough analysis in deciding the behavior when a subresource is deleted from the system. Usually, you may want to SOFT DELETE a resource in these requests – in other words, set their status INACTIVE.

By following this approach, you will not need to find and remove its references from other places as well.

4.8. Applying or Removing a configuration on/from a device

In a real application, you will need to apply the configuration on the device – OR you may want to remove the configuration from the device (not from the primary collection). You shall use PUT and DELETE methods in this case, because of their idempotent nature.

//Apply Configuration on a device
HTTP PUT /devices/{id}/configurations

//Remove Configuration on a device
HTTP DELETE /devices/{id}/configurations/{configId}

5. What’s Next?

So far, we have designed only object models, and URIs and then decided on HTTP methods or operations on them. You need to work on other aspects of the application as well:

See the source code of this example application to understand it better.

Happy Learning !!

Comments

Subscribe
Notify of
guest
24 Comments
Most Voted
Newest Oldest
Inline Feedbacks
View all comments