What Is REST?

Basics

REST stands for REpresentational State Transfer.

It is an architectural style for APIs (Application-Program Interfaces). It focuses on element interactions rather than implementations.

REST is language-independent concept.

REST is designed for performance, scalability, simplicity, modifiability, visibility, portability, and reliability.

REST systems usually communicate over HTTP, using the verbs GET, POST, PUT, DELETE.

Concepts

Separation of Client and Server
Stateless Server Requests
Cacheable Requests
Uniform Interface (URI)

You're API can be RESTful without following 100% of the REST architecture.

Benefits

REST is built on pre-existing standards, such as HTTP, instead of making new ones.

Encryption and data transport integrity rely on pre-existing standards, such as SLL (Secure Sockets Layer) and TLS (Transport Layer Security).

Most web programmers will already be familiar with the building blocks of REST.

Disadvantages

REST is stateless because HTTP is stateless (no data is stored between request-response cycles).

REST does not support push-notifications from the server to the client. The client would have to poll the server for updates, or use some other web hook.

There is room for disagreement about which applications are "RESTful".

Architecture

REST takes a resource-based approach. You locate a resource on the server, and then update it or delete it or get some information about it.

With SOAP, the client does not choose a resource directly. The client use calls a web service method (or operation) which may set off any number of tasks before returning a value.

The basic idea of REST is that retrieving information about a resource should be as simple as invoking its URL. For example, invoking "www.techtarget.com/restfulapi/quizzes" could return the JSON "{ "quizzes" : [ "Java", "DevOps", "IoT"] }". And the URLs are designed to be human-readable.

Microservices

REST is a light-weight messaging solution appropriate to the microservices architecture.

REST over HTTP offers little more than message exchange. For instance, it does not contribute to security.

Data Format

RESTful services usually return data in JSON or XMl format. REST itself does not restrict what data formats can be used.

HTTP Methods

GET: returns the resource
PUT: saves a new resource
DELETE: deletes a resource

POST: some more complex operation

Why Use An API?

You need to communicate across networks.
You need to communicate across proxies.
You need to communicate across firewalls.
You are building a mobile app.
Terminology

URI, URL, URN

URI stands for Uniform Resource Identifier.
URL stands for Uniform Resource Locator. Example: https://a.b.com/d
URN stands for Uniform Resource Name.

URLs and URNs are both types of URIs.

Breaking Change

A breaking change is any change to the API (the contract) that forces a consumer to also make a change.

Includes:
- changing the Request or Response format
- adding a required Property to the Request
- removing a Property from the Response
- changing a Property name or data type

API Design

Design your API before you start coding it.

Once you publish an API, you'll have clients building their code on top of yours.
The cost of altering your API goes up quickly, the more people rely on it.

Parts Of The API

Request = Verb + URI (with Query String) + Headers + Content

Response = Status Code + Headers + Content

URI

A URI is a path to a resource on your server.
Ex: api.myserver.com/people is a path to the "people" resources.

Your URIs should be Nouns. Ex: Repositories, Customers, Contracts, Books.
Leave the Verbs to the HTTP Request Verbs.

Query String

Query strings should always be optional.

They are commonly used for Formatting, Sorting, Searching, etc.

Data Types

Enum

Specify possible values of a request parameter or a model property.

Enum types in REST are assumed to be complete. Adding, removing, or modifying a value counts as a breaking change (i.e. version change).


paths:
  /items:
    get:
      parameters:
        - in: query
          name: sort
          description: Sort order
          schema:
            type: string
            enum: [asc, desc]
          description: >
            Sort order:
             * `asc` - Ascending, from A to Z
             * `desc` - Descending, from Z to A

[OpenAPI specification for enum]
[OpenAPI specification for enum github page]
The following properties are taken directly from the JSON Schema definition and follow the same specifications:
...enum
[JSON Schema enum]
The enum keyword is used to restrict a value to a fixed set of values. It must be an array with at least one element, where each element is unique.
- "fixed set" - this is where the "not extensible" discussions are coming from

Open-ended List

[Zalando REST API Guidelines: open-ended lists]

Enumerations are per definition closed sets of values, that are assumed to be complete and not intended for extension. This closed principle of enumerations imposes compatibility issues when an enumeration must be extended. To avoid these issues, we strongly recommend to use an open-ended list of values instead of an enumeration unless:
- the API has full control of the enumeration values, i.e. the list of values does not depend on any external tool or interface, and
- the list of value is complete with respect to any thinkable and unthinkable future feature.

To specify an open-ended list of values use the marker x-extensible-enum as follows:

Example:

delivery_methods:
  type: string
  x-extensible-enum:
    - PARCEL
    - LETTER
    - EMAIL

Note: x-extensible-enum is not JSON Schema conform but will be ignored by most tools.
Note: Swagger supports the "x-" prefix for vendor extensions.

[Microsoft Azure enum extensions]
Enum definitions in OpenAPI indicate that only a particular set of values may be used for a property or parameter. When the property is represented on the wire as a string, it would be a natural choice to represent the property type in C# and Java as an enum. However, not all enumeration values should necessarily be represented as strongly typed enums - there are additional considerations, such as how often expected values might change, since adding a new value to a strongly typed enum is a breaking change requiring an updated API version. Additionally, there is some metadata that is required to create a useful enum, such as a descriptive name, which is not represented in vanilla OpenAPI. For this reason, enums are not automatically turned into strongly typed enum types - instead they are rendered in the documentation comments for the property or parameter to indicate allowed values. To indicate that an enum will rarely change and that C#/Java enum semantics are desired, use the x-ms-enum extension. Note that depending on the code generation language the behavior of this extension may differ.

In C# and Java, an enum type is generated and is declared as the type of the related request/response object. The enum is serialized as the string expected by the REST API.

Example:

accountType:
  type: string
  enum:
  - Standard_LRS
  - Standard_ZRS
  - Standard_GRS
  - Standard_RAGRS
  - Premium_LRS
  x-ms-enum:
    name: AccountType
    modelAsString: false
    values:
    - value: Standard_LRS
      description: Locally redundant storage.
      name: StandardLocalRedundancy
    - value: Standard_ZRS
      description: Zone-redundant storage.
    - value: Standard_GRS
      name: StandardGeoRedundancy
    - value: Standard_RAGRS
    - value: Premium_LRS

[oneOf with const values is mentioned at the end of this]
[JSON Draft 6 mentions const instead of 1-value enum]

Currently, oneOf must specify object types:

schema:
  oneOf:
    - $ref: '#/components/schemas/Cat'
    - $ref: '#/components/schemas/Dog'
The suggestion is to accept primitives as well:

schema:
  oneOf:
    - const: foo
      title: The Foo Thing
    - const: bar
      title: The Bar Thing
      description: There's some explanation about the bar thing

Dictionary

aka Hashmap aka Associative Array


HTTP Verbs

PUT

Put: the entire object sent with the request is saved at that URI

One danger of PUT is that since the entire object is updated, you must make sure the values you've got are up-to-date. Otherwise, you'll end up reverting the values of some fields unintentionally.
- maybe you send in the timestamp of the last GET you ran?
- and the backend can check if any UPDATES have occured since that GET?

PATCH

Patch: a partial object is sent with the request and updates part of the URI resource

A patch endpoint accepts a Patch Document which lists the add/edit/delete operations to run on each part of the resource.
All operations are supposed to be saved as one atomic operation, or not at all.
And as with Put, you need to check that the object is in a state that can accept these changes.

[readthedocs PUT vs PATCH]
[blog PUT vs PATCH]

[HTTP PATCH specification]
"With PATCH, however, the enclosed entity contains a set of instructions describing how a resource currently residing on the origin server should be modified to produce a new version...and it also MAY have side effects on other resources."
"If the entire patch document cannot be successfully applied, then the server MUST NOT apply any of the changes."

The examples I'm seeing of PATCH routes don't name what part of the object is being updated.
[Routes]
Routes

aka Paths

[RFC3986 Search and Filter]
Basically, search/filter belong in the query string because they help to specify the resource.

[RFC3986 Hierarchy of Delimiters]
Reserved delimiters: ":", "/", "?", "#", "[", "]", "@"
Sub-delimiters: "!", "$", "&", "'", "(", ")", "*", "+", ",", ";", "="
OAS

[OAS on GitHub]

OAS stands for OpenAPI Specification.
OAS is a format for documenting RESTful APIs.
OAS is language-agnostic, machine-readable, and human-readable.

You can test your OAS by opening it in Swagger UI.

[Looks like a useful resource of OAS syntax]

Terminology

Endpoint: a relative URI

Operation: an HTTP Verb

Operation Parameters: input and output parameters

Path Templating: the use of curly braces {} to mark a variable section of a URI
Ex: /users/{userId}/contacts means that you should insert the User Id into the URI

Fields:
    All field names are case-sensitive
    Fixed Fields have a declared name
    Patterned Fields have a regex-driven name

Format
    
Your documentation should be valid in both JSON and YAML format.

Recommended file name is openapi.json or openapi.yaml

Data Types

string
number
integer
boolean
array (with child "items")
object (with child "properies")

Info Object

The Info Object provides metadata about the API.


{
  "title": "Sample Pet Store App",
  "description": "This is a sample server for a pet store.",
  "termsOfService": "http://example.com/terms/",
  "contact": {
    "name": "API Support",
    "url": "http://www.example.com/support",
    "email": "support@example.com"
  },
  "license": {
    "name": "Apache 2.0",
    "url": "https://www.apache.org/licenses/LICENSE-2.0.html"
  },
  "version": "1.0.1"
}


title: Sample Pet Store App
description: This is a sample server for a pet store.
termsOfService: http://example.com/terms/
contact:
  name: API Support
  url: http://www.example.com/support
  email: support@example.com
license:
  name: Apache 2.0
  url: https://www.apache.org/licenses/LICENSE-2.0.html
version: 1.0.1

Contact Object

The Contact Object provides contact information.


{
  "name": "API Support",
  "url": "http://www.example.com/support",
  "email": "support@example.com"
}


name: API Support
url: http://www.example.com/support
email: support@example.com

License Object

Server Object

All relative paths are relative to these URLs.

Single server:

{
  "url": "https://development.gigantic-server.com/v1",
  "description": "Development server"
}


url: https://development.gigantic-server.com/v1
description: Development server

Multiple servers:

{
  "servers": [
    {
      "url": "https://development.gigantic-server.com/v1",
      "description": "Development server"
    },
    {
      "url": "https://staging.gigantic-server.com/v1",
      "description": "Staging server"
    },
    {
      "url": "https://api.gigantic-server.com/v1",
      "description": "Production server"
    }
  ]
}


servers:
- url: https://development.gigantic-server.com/v1
  description: Development server
- url: https://staging.gigantic-server.com/v1
  description: Staging server
- url: https://api.gigantic-server.com/v1
  description: Production server

Path Object

A relative path to an Endpoint and the Endpoint's Operations.

Paths must begin with a "/" slash.
Path templates are allowed.


{
  "/pets": {
    "get": {
      "description": "Returns all pets from the system that the user has access to",
      "responses": {
        "200": {          
          "description": "A list of pets.",
          "content": {
            "application/json": {
              "schema": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/pet"
                }
              }
            }
          }
        }
      }
    }
  }
}


/pets:
  get:
    description: Returns all pets from the system that the user has access to
    responses:
      '200':
        description: A list of pets.
        content:
          application/json:
            schema:
              type: array
              items:
                $ref: '#/components/schemas/pet'

Components

The components section holds reusable data structures that can be referenced repeatedly.


components:
  # Reusable schemas (data models)
  schemas:
    ...
  # Reusable path, query, header and cookie parameters
  parameters:
    ...
  # Security scheme definitions (see Authentication)
  securitySchemes:
    ...
  # Reusable request bodies
  requestBodies:
    ...
  # Reusable responses, such as 401 Unauthorized or 400 Bad Request
  responses:
    ...
  # Reusable response headers
  headers:
    ...
  # Reusable examples
  examples:
    ...
  # Reusable links
  links:
    ...
  # Reusable callbacks
  callbacks:
    ...

You do not make a list of these subsections. You simple enter multiple values.

components:
  schemas:
    User:
      type: object
      ...
    Pet:
      type: object
      ...

You can address a component thus:

something:
  - $ref "#/components/schemas/MySchema"
References never have sibling elements.

requestBody can also accept a list of possible schemas:

paths:
  /my/path:
    post:
      summary: My Summary
      requestBody:
        content:
          application/json:
            schema:
              oneOf:
                - $ref: "#/components/requestBodies/MyRequestBodyA"
                - $ref: "#/components/requestBodies/MyRequestBodyB"
I'm not sure this is actually supported by OAS. There are many error reports against different editing tools saying that this part is not supported, and currently editor.swagger.io doesn't display it right.
This Swagger documentation shows an example of it, so it should be valid:
[Swagger requestBody/schema/oneOf example]

Inheritance And Polymorphism

[On Swagger]

You can define composition/inheritance hierarchies for your components.

components:
  schemas:
    BasicErrorModel:
      type: object
      required:
        - message
        - code
      properties:
        message:
          type: string
        code:
          type: integer
          minimum: 100
          maximum: 600
    ExtendedErrorModel:
      allOf: # Combines the BasicErrorModel and this inline model
        - $ref: '#/components/schemas/BasicErrorModel'
        - type: object
          required:
            - rootCause
          properties:
            rootCause:
              type: string

Richardson Maturity Model

[Original Article]

Leonard Richardson analyzed a hundred different web service designs and divided them into four categories based on how much they are REST compliant. This model of division of REST services to identify their maturity level is called Richardson Maturity Model.

Richardson used three factors to decide the maturity of a service:
- URI
- HTTP Methods
- HATEOAS (Hypermedia as the Engine of Application State)
The more a service employs these technologies, the more mature it shall be considered.

In this analysis, Richardson described these maturity levels as below:

Level Zero

Level zero of maturity does not make use of any of URI, HTTP Methods, or HATEOAS capabilities.

These services have a single URI and use a single HTTP method (typically POST). For example, most Web Services (WS-*)-based services use a single URI to identify an endpoint, and HTTP POST to transfer SOAP-based payloads, effectively ignoring the rest of the HTTP verbs.

Similarly, XML-RPC based services which send data as Plain Old XML (POX). These are the most primitive ways of building SOA applications with a single POST method and using XML to communicate between services.

Level One

Level one of maturity makes use of URIs only.

These services employ many URIs but only a single HTTP verb – generally HTTP POST. They give each individual resource in their universal URI. Every resource is separately identified by a unique URI – and that makes them better than level zero.

Level Two

Level two of maturity makes use of URIs and HTTP.

Level two services host numerous URI-addressable resources. Such services support several of the HTTP verbs on each exposed resource – Create, Read, Update and Delete (CRUD) services. Here the state of resources, typically representing business entities, can be manipulated over the network.

Here the service designer expects people to put some effort into mastering the APIs – generally by reading the supplied documentation.

Level 2 is the good use-case of REST principles, which advocate using different verbs based on the HTTP request methods and the system can have multiple resources.

Level Three

Level three of maturity makes use of all three: URIs, HTTP, and HATEOAS.

This is the most mature level of Richardson’s model which encourages easy discoverability and makes it easy for the responses to be self-explanatory by using HATEOAS.

The service leads consumers through a trail of resources, causing application state transitions as a result.
HATEOAS

About

HATEOAS stands for Hypermedia as the Engine of Application State.
Hypermedia refers to any content that contains links to other forms of media, such as images, movies, or text.

This is a constraint of REST architecture.
REST lets you include hypermedia links in your response contents so clients can dynamically navigate to the appropriate resource.

Example

{
    "departmentId": 10,
    "departmentName": "Administration",
    "locationId": 1700,
    "managerId": 200,
    "links": [
        {
            "href": "10/employees",
            "rel": "employees",
            "type" : "GET"
        }
    ]
}
The client can use "links" to jump to the resource they want. It specifies the HTTP verb and relative url.

This can free you from backward-compatibility constraints.
If your clients are used to following these links to find resources, then you can change where the resources are and simply update the links being returned to the clients.

In addition, clients can discover the functionality of your web service by starting at one point and walking the network.

There is no strong standard for link format.

Possible Pitfalls

Regarding the claim that "clients do not need to hardcode URIs anymore".

The client no longer hardcodes URIs, because they look them up through the web service itself.
But, they do need to hardcode the link labels, such as "rel":"employees" in the example above. So hardcoding is still required.

And there will be a performance hit to lookup these links from the root web service every time. You can cache the results, but then you must decide how often to refresh the crawl, since these values could change anytime.

Postman

About

[Postman]

Postman is a development environment for APIs.

Features:
- Send REST, SOAP, or GraphQL requests
- Automate testing and integrate it into your pipeline
- Design and Mock expected behavior
- Generate and Publish documentation of your API
- Monitor the health of your API
- Collaborate in real-time with other developers
- Built-in version control

Make A Request

Open Postman > Click + to open a new window > Select a HTTP Verb > enter the URL > click Send
Swagger

Swagger Specification

The Swagger Specification is a text format for documenting RESTful APIs.

The Swagger Specification was renamed to the OpenAPI Specification (OAS) when Swagger donated it to the OpenAPI Initiative.

Swagger UI

Swagger UI is a tool that will translate your OAS into an interactive API console.

Swashbuckle

generating OAS from .Net Core WebAPI projects
https://docs.microsoft.com/en-us/aspnet/core/tutorials/getting-started-with-swashbuckle?view=aspnetcore-3.1&tabs=visual-studio

generate on build instead of dynamicallty on view-page
https://github.com/domaindrivendev/Swashbuckle.AspNetCore/issues/541
"Now available on Nuget - dotnet-swagger.1.2.0-beta1"

Vendor Extensions

aks Specification Extensions

Vendor extensions are custom properties.
Vendor extensions can be used to describe extra functionality not covered by the standard Swagger specification.

Vendor extension property names start with "x-".
Vendor extensions are supported at root level, in info, in paths, in reponses, and in tags.

[Vendor Extensions in Swagger]

Example:

securityDefinitions:
  APIGatewayAuthorizer:
    type: apiKey
    name: Authorization
    in: header
    x-amazon-apigateway-authtype: oauth2
    x-amazon-apigateway-authorizer:
      type: token
      authorizerUri: arn:aws:apigateway:us-east-1:lambda:path/2015-03-31/functions/arn:aws:lambda:us-east-1:account-id:function:function-name/invocations
      authorizerCredentials: arn:aws:iam::account-id:role
      identityValidationExpression: "^x-[a-z]+"
      authorizerResultTtlInSeconds: 60