Design API - vidyasekaran/current_learning GitHub Wiki
Below excerpts are from URL : https://restfulapi.net/ (this is a very good resource for all references)
https://restfulapi.net/rest-architectural-constraints/ https://restfulapi.net/security-essentials/
What is REST - REST is acronym for Representational State Transfer. It is architectural style for distributed hypermedia systems and was first presented by Roy Fielding in 2000 in his famous dissertation.
REST defines 6 architectural constraints which make any web service – a true RESTful API.
-
Uniform Interface - A resource should have only one logical URI, and that should provide a way to fetch related or additional data. It is better to synonymize a resource with a web page. Any single resource should not be too large and contain each and everything in its representation. Whenever relevant, a resource should contain links (HATEOAS) pointing to relative URIs to fetch related information.
Keyword : One uri, HATEOAS
-
Client Server - Servers and clients may also be replaced and developed independently, as long as the interface between them is not altered.
Keyword : Contract based interface, Loose Coupling.
-
StateLess - No client context shall be stored on the server between requests. The client is responsible for managing the state of the application. Server will treat every request as new. No session, no history.
Keyword : No session , no history.
-
Cacheable - Caching can be implemented on the server or client-side. Caching improving scalability and performance.
Keyword: - Scalability, Performance.
-
Layered - REST allows you to use a layered system architecture where you deploy the APIs on server A, and store data on server B and authenticate requests in Server C, for example. A client cannot ordinarily tell whether it is connected directly to the end server or an intermediary along the way.
-
On demand code (optional) - Well, this constraint is optional. Most of the time, you will be sending the static representations of resources in the form of XML or JSON. But when you need to, you are free to return executable code to support a part of your application, e.g., clients may call your API to get a UI widget rendering code. It is permitted.
"All the above constraints help you build a truly RESTful API, and you should follow them. Still, at times, you may find yourself violating one or two constraints. Do not worry; you are still making a RESTful API – but not “truly RESTful.”
**Rest Resource Naming Guide **
REST APIs use Uniform Resource Identifiers (URIs) to address resources. REST API designers should create URIs that convey a REST API’s resource model to its potential client developers. When resources are named well, an API is intuitive and easy to use. If done poorly, that same API can feel difficult to use and understand.
The constraint of a **uniform interface **is partially addressed by the combination of URIs and HTTP verbs and using them in line with the standards and conventions.
In REST, primary data representation is called Resource. Having a strong and consistent REST resource naming strategy – will prove one of the best design decisions in the long term.
A resource can be a singleton or a collection. - For example, “customers” is a collection resource and “customer” is a singleton resource (in a banking domain). We can identify “customers” collection resource using the URI “/customers”. We can identify a single “customer” resource using the URI “/customers/{customerId}”.
A resource may contain sub-collection resources also. For example, sub-collection resource “accounts” of a particular “customer” can be identified using the URN “/customers/{customerId}/accounts” (in a banking domain). Similarly, a singleton resource “account” inside the sub-collection resource “accounts” can be identified as follows: “/customers/{customerId}/accounts/{accountId}”.
RESTful URI should refer to a resource that is a thing (noun) instead of referring to an action (verb) because nouns have properties which verbs do not have – similar to resources have attributes. Some examples of a resource are:
For more clarity, let’s divide the resource archetypes into four categories (document, collection, store and controller) and then you should always target to put a resource into one archetype and then use it’s naming convention consistently. For uniformity’s sake, resist the temptation to design resources that are hybrids of more than one archetype.
A REST API is composed of 4 distinct resource archetypes: document, collection, store and controller.
- document - A document resource is a singular concept that is akin to an object instance or database record. In REST, you can view it as a single resource inside resource collection.
Use “singular” name to denote document resource archetype.
http://api.example.com/device-management/managed-devices/{device-id}
http://api.example.com/user-management/users/{id}
http://api.example.com/user-management/users/admin
- Collection - A collection resource is a server-managed directory of resources. Clients may propose new resources to be added to a collection. However, it is up to the collection to choose to create a new resource or not. A collection resource chooses what it wants to contain and also decides the URIs of each contained resource.
Use the “plural” name to denote the collection resource archetype.
http://api.example.com/device-management/managed-devices
http://api.example.com/user-management/users
http://api.example.com/user-management/users/{id}/accounts
- **Store ** - A store is a client-managed resource repository. A store resource lets an API client put resources in, get them back out, and decide when to delete them. A store never generates new URIs. Instead, each stored resource has a URI. The URI was chosen by a client when it was initially put into the store.
Use “plural” name to denote store resource archetype.
http://api.example.com/song-management/users/{id}/playlists
- Controller - A controller resource models a procedural concept. Controller resources are like executable functions, with parameters and return values; inputs and outputs.
Use “verb” to denote controller archetype.
http://api.example.com/cart-management/users/{id}/cart/checkout http://api.example.com/song-management/users/{id}/playlist/play
Consistency is the key
Use consistent resource naming conventions and URI formatting for minimum ambiguily and maximum readability and maintainability. You may implement below design hints to achieve consistency:
1.** Use forward slash (/) to indicate hierarchical relationships**
The forward slash (/) character is used in the path portion of the URI to indicate a hierarchical relationship between resources. e.g.
http://api.example.com/device-management http://api.example.com/device-management/managed-devices
- Do not use trailing forward slash (/) in URIs
http://api.example.com/device-management/managed-devices/ http://api.example.com/device-management/managed-devices /This is much better version/
- Use hyphens (-) to improve the readability of URIs
http://api.example.com/inventory-management/managed-entities/{id}/install-script-location //More readable http://api.example.com/inventory-management/managedEntities/{id}/installScriptLocation //Less readable
- Do not use underscores ( _ )
To avoid this confusion, use hyphens (-) instead of underscores ( _ ).
http://api.example.com/inventory-management/managed-entities/{id}/install-script-location //More readable http://api.example.com/inventory_management/managed_entities/{id}/install_script_location //More error prone
- Use lowercase letters in URIs
When convenient, lowercase letters should be consistently preferred in URI paths.
RFC 3986 defines URIs as case-sensitive except for the scheme and host components. e.g.
http://api.example.org/my-folder/my-doc //1 HTTP://API.EXAMPLE.ORG/my-folder/my-doc //2 http://api.example.org/My-Folder/my-doc //3 In above examples, 1 and 2 are same but 3 is not as it uses My-Folder in capital letters.
- Do not use file extentions
File extensions look bad and do not add any advantage. Removing them decreases the length of URIs as well. No reason to keep them. http://api.example.com/device-management/managed-devices.xml /Do not use it/ http://api.example.com/device-management/managed-devices /This is correct URI/
Never use CRUD function names in URIs instead HTTP request methods should be used to indicate which CRUD function is performed
URIs should not be used to indicate that a CRUD function is performed. URIs should be used to uniquely identify resources and not any action upon them. HTTP request methods should be used to indicate which CRUD function is performed.
HTTP GET http://api.example.com/device-management/managed-devices //Get all devices HTTP POST http://api.example.com/device-management/managed-devices //Create new Device
HTTP GET http://api.example.com/device-management/managed-devices/{id} //Get device for given Id HTTP PUT http://api.example.com/device-management/managed-devices/{id} //Update device for given Id HTTP DELETE http://api.example.com/device-management/managed-devices/{id} //Delete device for given Id
Use query component to filter URI collection
Many times, you will come across requirements where you will need a collection of resources sorted, filtered or limited based on some certain resource attribute. For this, do not create new APIs – rather enable sorting, filtering and pagination capabilities in resource collection API and pass the input parameters as query parameters. e.g.
http://api.example.com/device-management/managed-devices http://api.example.com/device-management/managed-devices?region=USA http://api.example.com/device-management/managed-devices?region=USA&brand=XYZ http://api.example.com/device-management/managed-devices?region=USA&brand=XYZ&sort=installation-date
https://restfulapi.net/rest-api-design-tutorial-with-example/
Steps in designing REST Services
- Identify Object Model - identifying the objects which 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 sake, we will consider only two resources i.e.
Devices
Configurations
- 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 its sub-resources. These resource URIs are endpoints for RESTful services.
In our application, a device is a top-level resource. And configuration is sub-resource under the device. Let’s write down the URIs.
/devices /devices/{id}
/configurations /configurations/{id}
/devices/{id}/configurations /devices/{id}/configurations/{id}
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.
- Determine Representations
Now when resource URIs have been decided, let’s work on their representations. Mostly representations are defined in either XML or JSON format.
Collection of Device Resource
When returning a collection resource, include only the most important information about resources. This will keep the size of payload small, and so will improve the performance of REST APIs.
apple-es apple-esSingle Device Resource
Opposite to collection URI, here include complete information of a device in this URI. Here, also include a list of links for sub-resources and other supported operations. This will make your REST API HATEOAS driven.
<id>12345</id>
<deviceFamily>apple-es</deviceFamily>
<configuration id="42342">
<link rel="self" href="/configurations/42342" />
</configuration>
Configuration Resource Collection
Similar to device collection representation, create configuration collection representation with only minimal information.
Single Configuration Resource
Now, single configuration resource representation must have all possible information about this resource – including relevant links. active
Configuration Resource Collection Under Single Device
<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>
Notice that this subresource collection has two links. One for its direct representation inside sub-collection i.e. /devices/12345/configurations/333443 and other pointing to its location in primary collection i.e. /configurations/333443.
Having two links is essential as you can provide access to a device- specific configuration in a more unique manner, and you will have the ability to mask some fields (if design requires it), which shall not be visible in a secondary collection.
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. Secondary collection is sub-collection from a primary collection only. Each resource/collection contain at least one link i.e. to itself. Collections contain only most important information about resources. To get complete information about a resource, you need to access through its specific resource URI only. Representations can have extra links (i.e. methods in single device). Here method represent a POST method. You can have more attributes or form links in altogether new way also. We have not talked about operations on these resources yet.
4.** Assign HTTP Methods**
So our resource URIs and their representation are fixed now. Let’s decide the possible operations in the application and map these operations on resource URIs. A user of our network application can perform browse, create, update, or delete operations. So let’s assign them.
Browse all devices or configurations [Primary Collection]
HTTP GET /devices HTTP GET /configurations
If the collection size is large, you can apply paging and filtering as well. e.g., Below requests will fetch the first 20 records from collection.
HTTP GET /devices?startIndex=0&size=20 HTTP GET /configurations?startIndex=0&size=20
Browse all devices or configurations [Secondary Collection] HTTP GET /devices/{id}/configurations It will be mostly a small size collection – so no need to enable filtering or soring here.
Browse single device or configuration [Primary Collection] 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}
Browse single device or configuration [Secondary Collection] HTTP GET /devices/{id}/configurations/{id}
Subresource representation will be either same as or a subset of primary presentation.
Create a device or configuration
Create is not idempotent operation, and in HTTP protocol – POST is also not idempotent. So use POST.
HTTP POST /devices HTTP POST /configurations
Please note that 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
activeUpdate a device or configuration Update operation is an idempotent operation and HTTP PUT is also is idempotent method. So we can use 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
activeRemove 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 resource has been queues for deletion (async operation), or 200 (OK) / 204 (No Content) if resource has been deleted permanently (sync operation).
Applying or Removing a configuration 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 its idempotent nature.
//Apply Configuration on a device HTTP PUT /devices/{id}/configurations
//Remove Configuration on a device
HTTP DELETE /devices/{id}/configurations/{id}
- More Actions
So far, we have designed only object models, URIs and then decided HTTP methods or operations on them. You need to work on other aspects of the application as well:
- Logging
- Security
- Discovery etc.
In the next article, we will create this application in java to get a more detailed understanding.
Chapter 1 : Introduction refer - REST API Design Rulebook
Chapter 2 : Identifier Design with URIs (for more details refer above the "Rest Constraints - Rest Architectural Constraints" or below URL https://restfulapi.net/rest-architectural-constraints/ )
Chapter 3 : Interaction Design with HTTP -
REST APIs embrace all aspects of the HyperText Transfer Protocol, version 1.1* (HTTP/1.1) including its request methods, response codes, and message headers. This book divides its coverage of HTTP between two chapters, with this chapter discussing request methods and response status codes. Incorporating metadata in a REST API design, with HTTP’s request and response headers, is the subject of Chapter 4.
Request Methods - Clients specify the desired interaction method in the Request-Line part of an HTTP request message. Request-Line = Method SP Request-URI SP HTTP-Version CRLF
Each HTTP method has specific, well-defined semantics within the context of a REST API’s resource model.
**The purpose of **
**GET ** is to retrieve a representation of a resource’s state. **HEAD ** is used to retrieve the metadata associated with the resource’s state. **PUT ** should be used to add a new resource to a store or update a resource. **DELETE ** removes a resource from its parent. **POST ** should be used to create a new resource within a collection and execute controllers.
**Rule: **GET and POST must not be used to tunnel other request methods. Rule: GET must be used to retrieve a representation of a resource
A REST API client uses the GET method in a request message to retrieve the state of a resource, in some representational form. A client’s GET request message may contain headers but no body
$ curl -v http://api.example.restapi.org/greeting --> A command prompt showing the curl command. GET is curl’s default method, so it doesn’t need to be specified explicitly. The -v option makes the curl command’s output more verbose.
GET /greeting HTTP/1.1 --> The request message’s Request-Line indicates that the GET method was used on the greeting resource. User-Agent: curl/7.20.1 --> The request message’s list of headers starts here. ** Host: api.example.restapi.org** Accept: /
< **HTTP/1.1 200 OK ** --> The response message starts here, with the Status-Line discussed in “Response Status Codes” on page 28. The 200 OK status code tells curl that its request was successful.
< Date: Sat, 20 Aug 2011 16:02:40 GMT --> The response message’s list of headers starts here. < Server: Apache < Expires: Sat, 20 Aug 2011 16:03:40 GMT < Cache-Control: max-age=60, must-revalidate < ETag: text/html:hello world < Content-Length: 130 < Last-Modified: Sat, 20 Aug 2011 16:02:17 GMT < Vary: Accept-Encoding < Content-Type: text/html <!doctype html>
<title>Greeting</title> --> The response message’s body starts here.