RESTful Node.js: A Structured Approach
  • Book Cover
  • About the Author
  • Links and Resources
  • Part I: The Why
    • Foreword
    • Preface
    • Chapter 1: Introduction
      • The Rise of REST and Distributed Systems
      • Problem #1: Structureless Design, Structureless REST
      • The Emergence of JavaScript and Node.js
      • Problem #2: Structureless JavaScript, Structureless Node.js
      • Behold, the Solution: A Structured Approach
      • Summary
  • Part 2: The Theory
    • Chapter 2: REST Origins
      • A Brief History of the Web and the Birth of REST
      • REST vs. HTTP
      • REST - The Abstract Web Architecture
      • HTTP - A Peak at REST's Concrete Implementation
      • What does it mean for an API to be RESTful?
      • Measuring "RESTfulness" with Richardson Maturity Model
      • Pragmatic REST vs Dogmatic REST
      • Summary
    • Chapter 3: RESTful API Design Guidelines and "Best Practices"
      • Theories vs. Principles vs. Guidelines
      • URI Design
      • Method Verbs
      • Status Codes
      • Representational Design
      • Metadata Design
      • Versioning Strategies
      • Security Considerations
      • Documentation
      • Case Study: GitHub
      • Summary
    • Chapter 4: Structured JavaScript Architecture
      • The Monstrous Monolith and Its Downfall
      • Layered/N-Tier Architecture: The Unpopular Proven Way
      • Microservices and Distributed Computing: A Popular Misdirection
      • Summary
    • Chapter 5: The 8 Step Recipe
      • Route Name (URI)
      • Input Request
      • Middleware
      • Validation
      • Domain
      • Events
      • Output Response
      • Test, Refactor, Document
      • Summary
  • Part 3: The Code
    • Chapter 6: Introduction to the Bookstore API
      • The Bookstore API Endpoint Specifications
      • API Design and Code Structure
      • Project Setup
      • Summary
    • Chapter 7: Retrieving Books from our API
      • Retrieving All Books - Planning
      • Retrieving All Books - Implementation
      • Retrieving A Book By ID - Planning
      • Retrieving A Book By ID - Implementation
      • Summary
    • Chapter 8: Adding Authentication to our API
      • Registering the User - Planning
      • Registering the User - Implementation
      • Logging the User In - Planning
      • Logging the User In - Implementation
      • Getting Authenticated User - Planning
      • Getting Authenticated User - Implementation
      • Summary
    • Chapter 9: Adding the Create, Update, and Delete Operations to our API
      • Creating A Book Listing - Planning
      • Creating A Book Listing - Implementation
      • Updating A Book Listing By ID - Planning
      • Updating A Book Listing By ID - Implementation
      • Deleting A Book Listing By ID - Planning
      • Deleting A Book Listing By ID - Implementation
      • Summary
    • Chapter 10: Testing our API
      • Testing the Request
      • Testing the Middleware
      • Testing the Validation
      • Testing the Domain
      • Testing the Event
      • Testing the Response
      • Testing the Controller
      • Integration Test
      • Summary
  • Conclusion
    • Final Words
  • Bonus!
    • Refactoring to HATEOAS
  • Appendix
    • Sources & References
Powered by GitBook
On this page
  • A Not-So-RESTful Case Study: PivotalTracker
  • A Truly RESTful Case Study: Twilio
Edit on GitHub
  1. Part 2: The Theory
  2. Chapter 2: REST Origins

What does it mean for an API to be RESTful?

PreviousHTTP - A Peak at REST's Concrete ImplementationNextMeasuring "RESTfulness" with Richardson Maturity Model

Last updated 3 years ago

The most asked question with the most ambiguous answer(s). "What does it mean for a web API to be RESTful?".

In short, as we saw in the previous chapter, because HTTP has fulfilled almost every requirement of the REST constraints, the only thing missing is the HATEOAS requirement.

A REST API should be entered with no prior knowledge beyond the initial URI (bookmark) and set of standardized media types that are appropriate for the intended audience (i.e., expected to be understood by any client that might use the API). From that point on, all application state transitions must be driven by client selection of server-provided choices that are present in the received representations or implied by the user’s manipulation of those representations. The transitions may be determined (or limited by) the client’s knowledge of media types and resource communication mechanisms, both of which may be improved on-the-fly (e.g., code-on-demand). [Failure here implies that out-of-band information is driving interaction instead of hypertext.]

-Roy Fielding

To put simply, every response returned from the server to the client must provide appropriate links to the other resources in the application.

A Not-So-RESTful Case Study: PivotalTracker

I am getting frustrated by the number of people calling any HTTP-based interface a REST API.

-Roy Fielding

I dug a little deeper to just make sure, and have confirmed that this API is truly by no means RESTful. Let's explore why is not a REST API.

First, let's take a look at the GET /projects/{project_id} endpoint.

The response:

{
  "account_id": 100,
  "atom_enabled": false,
  "automatic_planning": true,
  "bugs_and_chores_are_estimatable": false,
  "created_at": "2021-01-12T12:00:05Z",
  "current_iteration_number": 1,
  "enable_following": true,
  "enable_incoming_emails": true,
  "enable_tasks": true,
  "has_google_domain": false,
  "id": 1900,
  "initial_velocity": 10,
  "iteration_length": 1,
  "kind": "project",
  "name": "Executioner",
  "number_of_done_iterations_to_show": 4,
  "point_scale": "0,1,2,3",
  "point_scale_is_custom": false,
  "project_type": "private",
  "public": false,
  "start_time": "2021-01-12T12:00:00Z",
  "time_zone": {
    "kind": "time_zone",
    "olson_name": "America/Los_Angeles",
    "offset": "-08:00"
  },
  "updated_at": "2021-01-12T12:00:05Z",
  "velocity_averaged_over": 3,
  "version": 1,
  "week_start_day": "Monday"
}

There is no sign of any links.

What about the POST /projects endpoint?

The response:

{
  "account_id": 100,
  "atom_enabled": true,
  "automatic_planning": true,
  "bugs_and_chores_are_estimatable": false,
  "created_at": "2021-01-12T12:00:05Z",
  "current_iteration_number": 15,
  "description": "Expeditionary Battle Planetoid",
  "enable_following": true,
  "enable_incoming_emails": true,
  "enable_tasks": true,
  "has_google_domain": false,
  "id": 99,
  "initial_velocity": 10,
  "iteration_length": 1,
  "kind": "project",
  "name": "Death Star",
  "number_of_done_iterations_to_show": 4,
  "point_scale": "0,1,2,3",
  "point_scale_is_custom": false,
  "profile_content": "This is a machine of war such as the universe has never known. It's colossal, the size of a class-four moon. And it possesses firepower unequaled in the history of warfare.",
  "project_type": "private",
  "public": false,
  "start_date": "2020-09-28",
  "start_time": "2021-01-12T12:00:10Z",
  "time_zone": {
    "kind": "time_zone",
    "olson_name": "America/Los_Angeles",
    "offset": "-08:00"
  },
  "updated_at": "2021-01-12T12:00:10Z",
  "velocity_averaged_over": 3,
  "version": 66,
  "week_start_day": "Monday"
}

Again, it gives the same general structure as the GET request previously, there are no links what's so ever.

So there you have it, PivotalTracker, although being a very well documented and easy to use API, is indeed not RESTful.

A Truly RESTful Case Study: Twilio

But hold on there... let's not end this section on a bad note, because the truth is that there are plenty of good public APIs that are truly RESTful. One of the more well known APIs (by developers) is the Twilio API. I got to say, Twilio has done a great job documenting all of their APIs and have definitely been able to adhere (almost 100%) to the hypermedia constraints by providing as many links within their responses as possible.

Let's begin by first examining the POST https://api.twilio.com/2010-04-01/Accounts.json create account endpoint.

The response:

{
  "auth_token": "auth_token",
  "date_created": "Thu, 30 Jul 2015 20:00:00 +0000",
  "date_updated": "Thu, 30 Jul 2015 20:00:00 +0000",
  "friendly_name": "friendly_name",
  "owner_account_sid": "ACX",
  "sid": "ACX",
  "status": "active",
  "subresource_uris": {
    "available_phone_numbers": "/2010-04-01/Accounts/ACX/AvailablePhoneNumbers.json",
    "calls": "/2010-04-01/Accounts/ACX/Calls.json",
    "conferences": "/2010-04-01/Accounts/ACX/Conferences.json",
    "incoming_phone_numbers": "/2010-04-01/Accounts/ACX/IncomingPhoneNumbers.json",
    "notifications": "/2010-04-01/Accounts/ACX/Notifications.json",
    "outgoing_caller_ids": "/2010-04-01/Accounts/ACX/OutgoingCallerIds.json",
    "recordings": "/2010-04-01/Accounts/ACX/Recordings.json",
    "transcriptions": "/2010-04-01/Accounts/ACX/Transcriptions.json",
    "addresses": "/2010-04-01/Accounts/ACX/Addresses.json",
    "signing_keys": "/2010-04-01/Accounts/ACX/SigningKeys.json",
    "connect_apps": "/2010-04-01/Accounts/ACX/ConnectApps.json",
    "sip": "/2010-04-01/Accounts/ACX/SIP.json",
    "authorized_connect_apps": "/2010-04-01/Accounts/ACX/AuthorizedConnectApps.json",
    "usage": "/2010-04-01/Accounts/ACX/Usage.json",
    "keys": "/2010-04-01/Accounts/ACX/Keys.json",
    "applications": "/2010-04-01/Accounts/ACX/Applications.json",
    "short_codes": "/2010-04-01/Accounts/ACX/SMS/ShortCodes.json",
    "queues": "/2010-04-01/Accounts/ACX/Queues.json",
    "messages": "/2010-04-01/Accounts/ACX/Messages.json",
    "balance": "/2010-04-01/Accounts/ACX/Balance.json"
  },
  "type": "Full",
  "uri": "/2010-04-01/Accounts/ACX.json"
}

As you can see not only does it contain the "uri" property of the account that has just been created, it also provides a bunch of "subresource_uris".

Next, let's checkout the GET https://api.twilio.com/2010-04-01/Accounts/ACXXXXX.json fetch account endpoint.

The response:

{
  "auth_token": "auth_token",
  "date_created": "Thu, 30 Jul 2015 20:00:00 +0000",
  "date_updated": "Thu, 30 Jul 2015 20:00:00 +0000",
  "friendly_name": "friendly_name",
  "owner_account_sid": "ACX",
  "sid": "ACX",
  "status": "active",
  "subresource_uris": {
    "available_phone_numbers": "/2010-04-01/Accounts/ACX/AvailablePhoneNumbers.json",
    "calls": "/2010-04-01/Accounts/ACX/Calls.json",
    "conferences": "/2010-04-01/Accounts/ACX/Conferences.json",
    "incoming_phone_numbers": "/2010-04-01/Accounts/ACX/IncomingPhoneNumbers.json",
    "notifications": "/2010-04-01/Accounts/ACX/Notifications.json",
    "outgoing_caller_ids": "/2010-04-01/Accounts/ACX/OutgoingCallerIds.json",
    "recordings": "/2010-04-01/Accounts/ACX/Recordings.json",
    "transcriptions": "/2010-04-01/Accounts/ACX/Transcriptions.json",
    "addresses": "/2010-04-01/Accounts/ACX/Addresses.json",
    "signing_keys": "/2010-04-01/Accounts/ACX/SigningKeys.json",
    "connect_apps": "/2010-04-01/Accounts/ACX/ConnectApps.json",
    "sip": "/2010-04-01/Accounts/ACX/SIP.json",
    "authorized_connect_apps": "/2010-04-01/Accounts/ACX/AuthorizedConnectApps.json",
    "usage": "/2010-04-01/Accounts/ACX/Usage.json",
    "keys": "/2010-04-01/Accounts/ACX/Keys.json",
    "applications": "/2010-04-01/Accounts/ACX/Applications.json",
    "short_codes": "/2010-04-01/Accounts/ACX/SMS/ShortCodes.json",
    "queues": "/2010-04-01/Accounts/ACX/Queues.json",
    "messages": "/2010-04-01/Accounts/ACX/Messages.json",
    "balance": "/2010-04-01/Accounts/ACX/Balance.json"
  },
  "type": "Full",
  "uri": "/2010-04-01/Accounts/ACX.json"
}

Again, same general format.

This is great because it gives you everything you need. Imagine as a consumer of this API when I make a fetch to a specified account ID, I can more or less access all necessary endpoints of that particular user without ever consulting the documentation.

Do I need to know what the usage for that particular account will look like? We have the information right here "usage": "/2010-04-01/Accounts/ACXX/Usage.json".

What about all the calls or notifications we want to see for that particular account? They are all under the "subresource_uris" property of this response.

Let's examine a "REST API". For those we are not familiar with , it's essential a project management tracking tool similar to Trello and Jira. When I first used this API, I thought to myself, where did the word "REST" come from in terms of its title on the documentation page?

The official documentation can be found here: .

The official documentation that we are going to be exploring can be found here:

PivotalTracker
https://www.pivotaltracker.com/help/api/rest/v5
https://www.twilio.com/docs/usage/api
Depiction of how HTTP (the protocol) is an implementation of REST (the architectural style).
PivotalTracker's web interface.
PivotalTracker's "REST" API v5
The official Twilio API Documentation in 2020.
https://www.twilio.com/docs