diff --git a/SUMMARY.md b/SUMMARY.md index 2f81a61..eb3f93c 100644 --- a/SUMMARY.md +++ b/SUMMARY.md @@ -17,50 +17,50 @@ ## REST API Guidelines -* [Introduction](core-principles/introduction.md) -* [Core Principles](core-principles/core-principles.md) - * [OpenAPI Specification](core-principles/openapi-specification.md) - * [API Design Platform](core-principles/apiary.md) - * [Design Maturity](core-principles/design-maturity.md) - * [Testing](core-principles/testing.md) +* [Introduction](rest/core-principles/introduction.md) +* [Core Principles](rest/core-principles/README.md) + * [OpenAPI Specification](rest/core-principles/openapi-specification.md) + * [API Design Platform](rest/core-principles/apiary.md) + * [Design Maturity](rest/core-principles/design-maturity.md) + * [Testing](rest/core-principles/testing.md) * [Functionality](core-principles/functional.md) - * [Protocol](protocol/protocol.md) - * [HTTP](protocol/http.md) - * [TLS](protocol/tls.md) - * [Separate Concerns](protocol/separate-concerns.md) - * [Request Methods](protocol/use-appropriate-methods.md) - * [Status Codes](protocol/use-appropriate-status-codes.md) - * Message - * [Message Formats](message/message-formats.md) - * [Content Negotiation](message/content-negotiation.md) - * [HAL](message/hal.md) - * [Problem Detail](message/error-reporting.md) - * [Foreign Key Relations](message/foreign-key-relations.md) - * Application - * [Corporate Data Model](application/harmonize-data.md) - * [Common Data Types](application/common-data-types.md) -* Quality - * [Execution](execution/README.md) - * [Pagination](execution/pagination.md) - * [Asynchronous Tasks](execution/asynchronous-tasks.md) - * [Batch Operations](execution/batch-operations.md) - * [Search Requests](execution/search-requests.md) - * [Query Requests with Large Inputs](execution/query-requests-with-large-inputs.md) - * [Choosing Fields and Embedded Resources](execution/choosing-fields-and-embedded-resoruces.md) - * [Localization](execution/localization.md) - * [Rate Limiting](execution/rate-limiting.md) - * [Caching](execution/caching.md) - * [Evolution](evolution/README.md) - * [Naming Conventions](evolution/naming-conventions.md) - * [Reserved Identifiers](evolution/reserved-identifiers.md) - * [URI Structure](evolution/uri-structure.md) - * [Changes and Versioning](evolution/versioning.md) - * [Testing Enviroments](execution/testing-enviroments.md) -* [Guides](guides/README.md) - * [API Testing CI Environment](guides/api-testing-ci-environment.md) - * [Complete API Development](guides/complete-api-development.md) -* [API Clients](clients/README.md) - * [Loose Coupling](clients/loose-coupling.md) + * [Protocol](rest/protocol/README.md) + * [HTTP](rest/protocol/http.md) + * [TLS](rest/protocol/tls.md) + * [Separate Concerns](rest/protocol/separate-concerns.md) + * [Request Methods](rest/protocol/use-appropriate-methods.md) + * [Status Codes](rest/protocol/use-appropriate-status-codes.md) + * [Message](rest/message/README.md) + * [Message Formats](rest/message/message-formats.md) + * [Content Negotiation](rest/message/content-negotiation.md) + * [HAL](rest/message/hal.md) + * [Problem Detail](rest/message/error-reporting.md) + * [Foreign Key Relations](rest/message/foreign-key-relations.md) + * [Application](rest/application/README.md) + * [Corporate Data Model](rest/application/harmonize-data.md) + * [Common Data Types](rest/application/common-data-types.md) +* [Quality](rest/core-principles/quality.md) + * [Execution](rest/execution/README.md) + * [Pagination](rest/execution/pagination.md) + * [Asynchronous Tasks](rest/execution/asynchronous-tasks.md) + * [Batch Operations](rest/execution/batch-operations.md) + * [Search Requests](rest/execution/search-requests.md) + * [Query Requests with Large Inputs](rest/execution/query-requests-with-large-inputs.md) + * [Choosing Fields and Embedded Resources](rest/execution/choosing-fields-and-embedded-resoruces.md) + * [Localization](rest/execution/localization.md) + * [Rate Limiting](rest/execution/rate-limiting.md) + * [Caching](rest/execution/caching.md) + * [Evolution](rest/evolution/README.md) + * [Naming Conventions](rest/evolution/naming-conventions.md) + * [Reserved Identifiers](rest/evolution/reserved-identifiers.md) + * [URI Structure](rest/evolution/uri-structure.md) + * [Changes and Versioning](rest/evolution/versioning.md) + * [Testing Enviroments](rest/execution/testing-enviroments.md) +* [Guides](rest/guides/README.md) + * [API Testing CI Environment](rest/guides/api-testing-ci-environment.md) + * [Complete API Development](rest/guides/complete-api-development.md) +* [API Clients](rest/clients/README.md) + * [Loose Coupling](rest/clients/loose-coupling.md) ## Kafka Guidelines diff --git a/application/common-data-types.md b/application/common-data-types.md index a00d03d..e69de29 100644 --- a/application/common-data-types.md +++ b/application/common-data-types.md @@ -1,37 +0,0 @@ -# Common Data Types - -## Date and Time Format -Date and Time **MUST** always conform to the [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) format e.g.: `2017-06-21T14:07:17Z` (date time) or `2017-06-21` (date), it **MUST** use the UTC (without time offsets). - -## Duration Format -Duration format **MUST** conform to the [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) standard e.g.: `P3Y6M4DT12H30M5S` (three years, six months, four days, twelve hours, thirty minutes, and five seconds). - -## Time Interval Format -Time Interval format **MUST** conform to the [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) standard e.g.: `2007-03-01T13:00:00Z/2008-05-11T15:30:00Z`. - -## Standard Time Stamps -Where applicable, a resource representation **SHOULD** contain the standard timestamps: - -- `createdAt` -- `updatedAt` -- `finishedAt` - -#### Example - -```json -{ - "createdAt": "2017-01-01T12:00:00Z", - "updatedAt": "2017-01-01T13:00:00Z", - - ... -} -``` - -## Language Code Format -Language codes **MUST** conform to the [ISO 639](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) e.g.: `en` for English. - -## Country Code Format -Country codes **MUST** conform to the [ISO 3166-1 alpha-2](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2) e.g.: `DE` for Germany. - -## Currency Format -Currency codes **MUST** conform to the [ISO 4217](https://en.wikipedia.org/wiki/ISO_4217) e.g.: `EUR` for Euro. diff --git a/core-principles/apiary.md b/core-principles/apiary.md index aa4985e..e69de29 100644 --- a/core-principles/apiary.md +++ b/core-principles/apiary.md @@ -1,16 +0,0 @@ -# API Design Platform - Apiary - -1. [Apiary](https://apiary.io/) is the primary platform supporting [API first approach](./api-first.md). Apiary **MUST** be used during API Design. - -2. Every API description **MUST** be stored in [Apiary](https://apiary.io/) under the ADIDAS GROUP team. - -3. Apiary **MUST** be the **single source of truth** to learn about existing APIs within the organization. - -> NOTE: Apiary supports API-first approach in multiple ways: -> a. Validates API description for correctness and automatically generates API documentation to drive the discussion between stakeholders. \(No more emails with API description flying between stakeholders\) -> -> NOTE: The synchronization between the version control system and adidas [API Description platform](./apiary.md) -> should be automated using CI/CD framework. - - - diff --git a/core-principles/design-maturity.md b/core-principles/design-maturity.md index 5ed72de..e69de29 100644 --- a/core-principles/design-maturity.md +++ b/core-principles/design-maturity.md @@ -1,16 +0,0 @@ -# Design & Implementation Maturity - -## API Design Maturity -> How to design an API - - -Every API design **MUST** be **resource-centric** ([Web API Design Maturity Model Level 2](http://amundsen.com/talks/2016-11-apistrat-wadm/2016-11-apistrat-wadm.pdf)). That is an API design **MUST** revolve around Web-styled _resources_, _relations_ between the resources and the _actions_ the resources may afford. - -An API design **MAY** be **affordance-centric** ([Web API Design Maturity Model Level 3](http://amundsen.com/talks/2016-11-apistrat-wadm/2016-11-apistrat-wadm.pdf)). - -## API Design Implementation Maturity -> How to implement the API design - -Every API design implementation using the HTTP protocol **MUST** use the appropriate **HTTP Request Method** ([Richardson Maturity Model Level 2](https://martinfowler.com/articles/richardsonMaturityModel.html#level2)) to implement an action afforded by a resource. - -An API design implementation **SHOULD** include **hypermedia controls** (HATEOAS) ([Richardson Maturity Model Level 3](https://martinfowler.com/articles/richardsonMaturityModel.html#level3)). diff --git a/core-principles/api-first.md b/core-principles/functional.md similarity index 100% rename from core-principles/api-first.md rename to core-principles/functional.md diff --git a/core-principles/introduction.md b/core-principles/introduction.md index deea0b3..e69de29 100644 --- a/core-principles/introduction.md +++ b/core-principles/introduction.md @@ -1,45 +0,0 @@ -# adidas REST API Guidelines - -The adidas REST API Guidelines defines standards and guidelines for building REST APIs at adidas. These Guidelines has to be followed in addition to the General Guidelines. - -The REST API Guidelines are further split into the following parts: - -* **Core Principles** - - REST API Guidelines Core Principles defines the rules that **MUST** be followed at throughout the full API lifecycle. - -* **Functionality Guidelines** - - * [**Protocol level**](https://adidas-group.gitbooks.io/api-guidelines/content/protocol/) - - Protocol guidelines define the protocols used within the organization. - - * [**Message level**](https://adidas-group.gitbooks.io/api-guidelines/content/message/) - - The Message guidelines define the structure and semantics of messages used to exchange information. - - * [**Application level**](https://adidas-group.gitbooks.io/api-guidelines/content/application/) - - The Application guidelines define the definition and use of application-specific semantics. - -* **Quality Guidelines** - - Evolution and Execution guidelines define the rules for achieving the desired architectural qualities of systems. - - * [**Evolution**](https://adidas-group.gitbooks.io/api-guidelines/content/evolution/) - - Evolution qualities governance, such as testability, maintainability, extensibility, and scalability. - - * [**Execution**](https://adidas-group.gitbooks.io/api-guidelines/content/execution/) - - Execution qualities governance, such as security and usability. - -* **Guides** - Guides and materials supporting the REST API Guidelines - -* **API Clients** - - Section dedicated to consumers of adidas APIs - - - diff --git a/core-principles/openapi-specification.md b/core-principles/openapi-specification.md index c54f215..e69de29 100644 --- a/core-principles/openapi-specification.md +++ b/core-principles/openapi-specification.md @@ -1,7 +0,0 @@ -# OpenAPI Specification -Every API **MUST** be described using an API description format. The API description format used MUST be the [OpenAPI Specification (formerly known as Swagger Specification) version 2.0](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md). - -Every API description **MUST** be published in adidas [API design platform](./apiary.md) and it **SHOULD** be stored in version control system (Bitbucket, GitHub) in the same repository as the API implementation. - -## Language -The API description MUST be written in **American English**. diff --git a/core-principles/testing.md b/core-principles/testing.md index 9a8ca38..e69de29 100644 --- a/core-principles/testing.md +++ b/core-principles/testing.md @@ -1,4 +0,0 @@ -# Testing – Contract Validation -Every API description (contract) using HTTP(S) protocol **MUST** be tested against its API implementation. The tests **MUST** be executed using the [Dredd testing framework](https://github.com/apiaryio/dredd). The Dredd **MUST** [report the test results to Apiary](https://help.apiary.io/tools/automated-testing/testing-reporter/). - -In addition to local runs, the tests **SHOULD** be an integral part the API implementation's CI/CD pipeline. The CI/CD pipeline **SHOULD** be configured to run the test whenever there is a change to either API description (contract) or its implementation. diff --git a/evolution/naming-conventions.md b/evolution/naming-conventions.md index 8e25cf0..e69de29 100644 --- a/evolution/naming-conventions.md +++ b/evolution/naming-conventions.md @@ -1,117 +0,0 @@ -# Naming Conventions - -## General Naming Rules - -- Use American English -- Don't use acronyms -- Use `camelCase` unless stated otherwise -- Reconcile terms with adidas CDM - -Every identifier **MUST** be in American English and written in `lowercase`. An identifier **SHOULD NOT** contain acronyms. CamelCase (`camelCase`) **MUST** be used to delimit combined words. - -## URI -Every URI **MUST** follow the General Rules except for the `camelCase` rule. Instead, a hyphen (`-`) **SHOULD** be used to delimit combined words (kebab-case). Besides, a URI **MUST NOT** end with a trailing slash (`/`). - -#### Example -A well-formed URI: - -``` -/system-orders/1234/author -``` - -### Query Parameters and Path Fragments -Every URI query parameter or fragment **MUST** follow the General Rules. Also, they **MUST NOT** clash with the [reserved query parameter names](https://tools.adidas-group.com/confluence/display/EA/API+Interaction#APIInteraction-Query_Parameters). - -### URI Template Variables -In addition to General Naming Rules, URI Template Variable names **MUST** follow the [RFC6570](https://tools.ietf.org/html/rfc6570#section-2.3). That is, the variable names can consist only from `ALPHA / DIGIT / "_" / pct-encoded`. - -> NOTE: Per RFC6570 Hyphen (`-`) is NOT legal URI Template variable name character. - -#### Example -A well-formed URI Template Variable: - -``` -/system-orders/{orderId}/author -``` - -## Representation Format Fields -Every representation format field **MUST** conform to the General Naming Rules. - -#### Example -A well-formed resource representation: - -```json -{ - "_links": { - "self": { - "href": "/orders/1234" - }, - "author": { - "href": "/users/john" - } - }, - "orderNumber": 1234, - "itemCount": 42, - "status": "pending" -} -``` - -## Relation Type Identifier -Every custom [relation identifier](https://github.com/for-GET/know-your-http-well/blob/master/relations.md) **MUST** be in `lowercase` with words separated by the hyphen (`-`). - -#### Example -A well-formed resource representation with custom relation `fulfillment-provider`: - -```json -{ - "_links": { - "fulfillment-provider": { - "href": "/users/natalie" - } - } -} -``` - - -## HTTP Headers -Every HTTP Header should use `Hyphenated-Pascal-Case`. A custom HTTP Header **SHOULD NOT** start with `X-` ([RFC6648](https://tools.ietf.org/html/rfc6648)). - -#### Example - -``` -Order-Metadata-Header: 42 -``` - - -## API Description -Naming conventions within API Description document. - -### API Name -Every API Description API name **MUST** start with API domain enclosed in square brackets (e.g. `[API Domain] My API`). Words **MUST** be separated by space. - -#### Example - -```yaml -swagger: '2.0' -info: - version: '1.0.0' - title: '[Demo] Orders API' -``` - -### Resource Name -Every resource **MUST** have a name (defined by `x-summary` field). Resource name **MUST** be in `Title Case`. Words **MUST** be separated by a space. - -#### Example -```yaml -/orders: - x-summary: List of Orders -``` - -### Action Name -Every action (operation) **MUST** have a name (defined by `summary` field). Action name **MUST** be in `Title Case`. Words **MUST** be separated by a space. - -#### Example -```yaml -get: - summary: Retrieve List of Orders -``` diff --git a/evolution/uri-structure.md b/evolution/uri-structure.md index a9ecbcd..e69de29 100644 --- a/evolution/uri-structure.md +++ b/evolution/uri-structure.md @@ -1,8 +0,0 @@ -# URI Design -URI is meant to express a **identity of a resource**. URI is an identifier and it **MUST NOT** convey any other information. - -The API design process **MUST NOT** start with the design of URIs. Contrary, the URI **SHOULD** be amongst the last few things added to the API design. - -At adidas, URIs are subject to [naming conventions](https://adidas-group.gitbooks.io/api-guidelines/content/evolution/naming-conventions.html). - -To read more about the problematics refer to [RFC 7320: URI Design and Ownership](https://tools.ietf.org/html/rfc7320). diff --git a/evolution/versioning.md b/evolution/versioning.md index a45eedc..e69de29 100644 --- a/evolution/versioning.md +++ b/evolution/versioning.md @@ -1,102 +0,0 @@ -# Changes and Versioning - -> _The fundamental principle is that you can’t break existing clients, because you don’t know what they implement, and you don’t control them. In doing so, you need to turn a backwards-incompatible change into a compatible one._ -> -> _– _[_Mark Nottingham_](https://www.mnot.net/blog/2011/10/25/web_api_versioning_smackdown) - -Any change to an API **MUST NOT** break existing clients. - -Any change to: -1. **Resource identifier** \(resource name / URI\) including any **query parameters** and their semantics -1. **Resource metadata** \(e.g. HTTP headers\) -1. **Action** the resource affords \(e.g. available HTTP Methods\) -1. **Relation** with other resources \(e.g Links\) -1. **Representation format** \(e.g. HTTP request and response bodies\) - -**MUST** follow the [**Rules for Extending**](https://adidas-group.gitbooks.io/api-guidelines/content/core-principles/rules-for-extending.html). - -## Identifier Stability \(No URI Versioning\) - -A change **MUST NOT** affect **existing** resource identifiers \(name / URI\). Furthermore, a resource identifier **MUST NOT** contain a semantic version to convey a version of resource or its representation format. - -> _The reason to make a real REST API is to get evolvability … a "v1" is a .... to your API customers, indicating RPC/HTTP \(not REST\)_ -> -> _– _[_Roy T. Fielding_](https://twitter.com/fielding/status/376835835670167552) - -#### Example - -Adding a new action to existing resource with identifier `/greeting` doesn't change its identifier to `/v2/greeting` \(or `/greeting-with-new-action` etc.\). - -## Backward-incompatible Changes - -A change to _resource identifier_, _resource metadata_, _resource actions_ and _resource relations_ that can't follow the [Rules for Extending](https://adidas-group.gitbooks.io/api-guidelines/content/core-principles/rules-for-extending.html) **MUST** result into a **new resource variant**. Existing resource variant **MUST** be preserved. - -A change to _representation format_ **SHOULD NOT** result into a new resource variant. - -#### Example - -Currently, optional URI Query Parameter `first` on an existing resource `/greeting?first=John&last=Appleseed` needs to be made required. Since this change violates the 3rd rule of extending and could break existing clients a new variant of the resource is created with different URI `/named-greeting?first=John&last=Appleseed`. - -### Representation Format Changes - -> A representation format is the serialization format \(media type\) used in request and response bodies, and typically it represents a resource or its part, possibly with additional hypermedia controls. - -If a change can't follow the Rules for Extending the representation format media type **MUST** be changed. If the media type has been changed the previous media type, **MUST** be available via [Content Negotiation](https://adidas-group.gitbooks.io/api-guidelines/content/message/content-negotiation.html). - -If the media type conveys the version parameter, the version parameter **SHOULD** follow [Semantic versioning](http://semver.org/). - -#### Example - -Media type _before_ a breaking change: - -``` -application/vnd.example.resource+json; version=2 -``` - -Media type _after_ a breaking change: - -``` -application/vnd.example.resource+json; version=3 -``` - -> NOTE: In the case of technical limitations with semi-colon separated HTTP header values, the semantic version MAY be incorporated in the media type identifier, for example: `application/vnd.example.resource.v2+json` However, the use of semicolon-separated version information is preferred. - -## API Description Versioning - -API Description in the OpenAPI specification format **MUST** have the `version` field. The `version` field **MUST** follow [Semantic versioning](http://semver.org/): - -> Given a version number MAJOR.MINOR.PATCH, increment the: -> -> * MAJOR version when you make **incompatible** API changes, -> * MINOR version when you add functionality in a **backwards-compatible** manner -> * PATCH version when you make **backwards-compatible bug fixes** - -The API Description version **SHOULD** be updated accordingly to API design change. - -#### Example - -Following API Description - -```yaml -swagger: '2.0' -info: - version: '2.1.3' - title: '[Demo] Inventory API' - description: 'Inventory service API' -``` - -Has MAJOR version 2, MINOR version 1 and PATCH version 3. - -#### Demo - -API description \(OAS2\) files demonstrating a proposal of an backward-incompatible change turned into a backward compatible change are available at [Bitbucket \(diff\) ](https://bitbucket.org/apidesigner/demo-versioning-api/pull-requests/1/add-name-parameter/diff)and documented in Apiary: - -* [Production version](https://demoversioningproduction.docs.apiary.io/#) as being consumed by clients -* [Development version](https://demoversioningdevelopment.docs.apiary.io/#) proposing a backward incompatible change - -#### Recommended Reading - -* [Evolving HTTP APIs](https://www.mnot.net/blog/2012/12/04/api-evolution) - - - diff --git a/execution/README.md b/execution/README.md index 3477681..e69de29 100644 --- a/execution/README.md +++ b/execution/README.md @@ -1,2 +0,0 @@ -# Execution -Performance qualities, such as security and usability, which are observable at run time. diff --git a/execution/asynchronous-tasks.md b/execution/asynchronous-tasks.md index 2c61486..e69de29 100644 --- a/execution/asynchronous-tasks.md +++ b/execution/asynchronous-tasks.md @@ -1,26 +0,0 @@ -# Asynchronous Tasks -If an API operation is asynchronous, but a client could track its progress, the response to such an asynchronous operation **MUST** return, in the case of success, the **202 Accepted** status code together with an `application/hal+json` representation of a new **task-tracking resource**. - -## Task Tracking Resource -The task-tracking resource **SHOULD** convey the information about the status of an asynchronous task. - -Retrieval of such a resource using the HTTP GET Request Method **SHOULD** be designed as follows: - -1. Task is Still Processing - - Return **200 OK** and representation of the current status. - -2. Task Successfully Completed - - Return **303 See Other** together with [HTTP Location Header](https://tools.ietf.org/html/rfc7231#section-7.1.2) with URI or a outcome resource. - -3. Task Failed - - Return **200 OK** and `application/problem+json` with the problem detail information on the task has failed. - - -## Design Note -The asynchronous operation task-tracking resource can be either **polled** by client or the client might initially provide a **callback** to be executed when the operation finishes. - -In the case of callback, the API and its client MUST agree on what HTTP method and request format is used for the callback invitation. If built within adidas, the "client" API is also the subject of the adidas API guidelines. - diff --git a/execution/caching.md b/execution/caching.md index 1fe746d..e69de29 100644 --- a/execution/caching.md +++ b/execution/caching.md @@ -1,45 +0,0 @@ -# Caching -Every API implementation **SHOULD** return both the cache expiry information ([`Cache-Control` HTTP header](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control)) and specific resource version information ([`ETag` HTTP Header](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/ETag)). - -## Cache-Control -Every API implementation's response **SHOULD** include information about cache-ability and cache expiration of the response. For HTTP 1.1 this is achieved using the `Cache-Control` header. - - -### Common Cache-Control Scenarios -Two, most common scenarios for controlling the cache-ability of a response includes (1) Setting expiration and revalidation and (2) disabling the caching of a response. Refer to the [Cache-Control Documentation](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control) for additional controls. - -#### 1. Cache Expiration & Revalidation -The common scenario to set cache expiration and revalidation policy is to use the `max-age` and `must-revalidate` directives: - -``` -HTTP/1.1 200 OK -Date: Mon, 19 Aug 2017 00:00:00 CEST -Last-Modified: Mon, 19 Aug 2017 00:00:00 CEST -Cache-Control: max-age=3600,must-revalidate -Content-Type: application/hal+json; charset=UTF-8 - -... -``` - -#### 2. Disabling Cache -To disable caching completely API implementation **SHOULD** use the `no-cache` and `no-store` directives: - -``` -HTTP/1.1 200 OK -Date: Mon, 19 Aug 2017 00:00:00 CEST -Last-Modified: Mon, 19 Aug 2017 00:00:00 CEST -Cache-Control: no-cache, no-store, must-revalidate -Content-Type: application/hal+json; charset=UTF-8 - -... -``` - -## ETag -Every API implementation's response to a [cacheable request](https://github.com/for-GET/know-your-http-well/blob/master/methods.md#cacheable) **SHOULD** include the [`ETag` HTTP Header](https://tools.ietf.org/html/rfc7232#section-2.3) to identify the specific version of the returned resource. - -Every API client **SHOULD** use [`If-None-Match` HTTP header](https://tools.ietf.org/html/rfc7232#section-3.2) whenever it's performing a cacheable request. The value of `If-None-Match` should be the value of the `ETag` header stored from a previous request. The client **MUST** be ready to handle the **304 Not Modified** response from the server to use the legal copy. - -#### How ETag works -ETags are unique identifiers for a particular version of a resource found by a URL. They are used for cache validation, to check for modifications quickly. - -A client requests a resource from the server at a particular URI. The server responds with the specific ETag value in the HTTP ETag header field. ETag and the resource will be stored locally by the client. Subsequent requests from the client are done with the If-None-Match header, which now contains the ETag value from the previous request. The server now compares the values. If they are the same, it responds with HTTP Status Code 304 Not Modified. If not, the resource is sent. diff --git a/execution/choosing-fields-and-embedded-resoruces.md b/execution/choosing-fields-and-embedded-resoruces.md index 515738c..e69de29 100644 --- a/execution/choosing-fields-and-embedded-resoruces.md +++ b/execution/choosing-fields-and-embedded-resoruces.md @@ -1,80 +0,0 @@ -# Choosing Fields & Embedded Resources - - -## Response Message Fields -Every request that may result in a response with a non-trivial body **SHOULD** implement the `fields` query parameter. If provided, the value of this parameter must be a comma-separated list of top-level response message fields. - -Upon receiving such a request, in the event of a 2xx response, the service **SHOULD** respond with a message that includes only top-level fields specified in the `fields` parameter. That includes HAL-specific fields (`_links` and `_embedded`). - -#### Example -Retrieve only some details of an Order resource: - -HTTP Request -``` -GET /order/1234?fields=_links,orderNumber,status HTTP/1.1 -Accept: application/hal+json -``` - -HTTP Response -``` -HTTP/1.1 200 OK -Content-Type: application/hal+json - -{ - "_links": { - "self": { "href": "/orders/1234" }, - "author": { "href": "/users/john" }, - "items": [ ... ] - }, - "orderNumber": 1234, - "status": "pending" -} -``` - -## Embedded Resources -Similarly to the `fields` query parameter, every request that might result in a response containing related embedded resource representations **SHOULD** implement the `embedded` query parameter. If, provided the value of the `embedded` query parameter **MUST** be a comma-separated list of relation identifiers. - -Upon receiving such a request, in the event of a 2xx response, the service **SHOULD** respond with a message that "embeds" (see HAL `_embedded` field) only the related resources specified in the `embedded` parameter. - - -#### Example -Embed only information about the Author of an Order resource. We are not interested in Items that are in this order. - -HTTP Request - -``` -GET /order/1234?embed=author HTTP/1.1 -Accept: application/hal+json -``` - -HTTP Response -``` -HTTP/1.1 200 OK -Content-Type: application/hal+json - -{ - "_links": { - "self": { "href": "/orders/1234" }, - "author": { "href": "/users/john" }, - "items": [ ... ] - }, - "orderNumber": 1234, - "itemCount": 42, - "status": "pending", - "_embedded": { - "author": { - "_links": { "self": "/users/john" }, - "name": "John Appleseed", - "email": "john@apple.com" - } - } -} -``` - -## Reasonable Defaults -When `fields` and `embedded` parameters are not provided or not implemented the server **SHOULD** return reasonable default field and/or embedded resources. The defaults **MUST** always contain the `_links` field, where available. - -## Resource Variants -The facility of `fields` and `embedded` parameters doesn't impose any restriction of creating new resource variants. - -It is OK to create a new resource just as a compound resource only to provide selected fields or blend-embed some existing resources together. diff --git a/execution/localization.md b/execution/localization.md index eb96e61..e69de29 100644 --- a/execution/localization.md +++ b/execution/localization.md @@ -1,37 +0,0 @@ -# Localization - -## Language Variants -If a resource has multiple language variants and the difference between variants is only in the language of human-readable fields, then the [`Accept-Language`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept-Language) request HTTP header **SHOULD** be used to select the desired language variant. - -#### Example - -``` -GET /article HTTP/1.1 -Accept-Language: en,en-US,fr;q=0.6 -``` - -``` -HTTP/1.1 200 OK -Content-Type: application/hal+json;charset=UTF-8 -Content-Language: en -Vary: Accept-Language - -... -``` - -## Language or Country-specific Data Structure -If the difference between language or country specific variants of a resource is bigger than just in the content of human readable strings, for example, the data structure of the resource representation is different, then a query parameter **SHOULD** be used to communicate the requested variant. - -#### Example - -``` -GET /article?market=en_US HTTP/1.1 -``` -``` -HTTP/1.1 200 OK -Content-Type: application/hal+json;charset=UTF-8 -Content-Language: en -Vary: Accept-Language - -... -``` diff --git a/execution/pagination.md b/execution/pagination.md index fc4a22c..e69de29 100644 --- a/execution/pagination.md +++ b/execution/pagination.md @@ -1,27 +0,0 @@ -# Pagination -A collection resource **SHOULD** provide the [`first`, `last`, `next` and `prev` link](https://tools.ietf.org/html/rfc5988#section-6.2.2)s for navigation within the collection. - -#### Example -The Collection of Orders using the collection navigation link and `offset` and `limit` query parameters: - - -```json -{ - "_links": { - "self": { "href": "/orders?offset=100&limit=10" }, - "prev": { "href": "/orders?offset=90&limit=10" }, - "next": { "href": "/orders?offset=110&limit=10" }, - "first": { "href": "/orders?limit=10" }, - "last": { "href": "/orders?offset=900&limit=10" } - }, - "total_count": 910, - "_embedded": { - "order": [ - { ... }, - { ... }, - - ... - ] - } -} -``` diff --git a/execution/query-requests-with-large-inputs.md b/execution/query-requests-with-large-inputs.md index 6d6bb87..e69de29 100644 --- a/execution/query-requests-with-large-inputs.md +++ b/execution/query-requests-with-large-inputs.md @@ -1,17 +0,0 @@ -# Query Requests with Large Inputs -While HTTP doesn't impose any limit on the length of a URI, some implementation of server or client might have difficulties handling long URIs (usually URIs with many or large query parameters). - -Every endpoint with such a URI **MUST** use the HTTP **POST** Request Method and send the query string in HTTP Request Message body using the `application/x-www-form-urlencoded` media type. - - -#### Example - -``` -POST /orders HTTP/1.1 -Content-Type: application/x-www-form-urlencoded - -search=attributes&color=white&size=56&... -``` - - -> _NOTE: Since this operation is safe and idempotent, using the POST method violates the HTTP protocol semantics and results in loss of cache-ability._ diff --git a/execution/rate-limiting.md b/execution/rate-limiting.md index 3d96593..e69de29 100644 --- a/execution/rate-limiting.md +++ b/execution/rate-limiting.md @@ -1,63 +0,0 @@ -# Rate Limiting -The API rate limiting is provided by the selected adidas API management platform – Mashery. - -Rate limit information is provided in the for of HTTP headers. There are two types of rate limits: **Quota** and **Throttle**. The quota is a limit enforced per a longer period (typically a day). The throttle is the limit of calls per second. - -## Quota Limit -The limit on the number of calls per a period (day). The default quota limit is 5000 calls per day. - -#### Example -Example response to a request over the quota limit: - -``` -HTTP/1.1 403 Forbidden -Content-Type: application/problem+json - -X-Error-Detail-Header: Account Over Rate Limit -X-Mashery-Error-Code: ERR_403_DEVELOPER_OVER_RATE - -{ - "title": "Rate Limit Exceeded", - "detail": "Account Over Rate Limit" -} - -``` - -## Throttle Limit -The limit on the number of calls per second. The default throttle limit is two calls per second. - -#### Example -Example response to a request over the throttle limit: - -``` -HTTP/1.1 403 Forbidden -Content-Type: application/problem+json - -Retry-After: 1 -X-Error-Detail-Header: Account Over Queries Per Second Limit -X-Mashery-Error-Code: ERR_403_DEVELOPER_OVER_QPS - -{ - "title": "Quota Limit Exceeded", - "detail": "Account Over Queries Per Second Limit" -} -``` - -> NOTE: The `Retry-After` gives a hint how long before the same request should be repeated (in seconds). - - -## Detail Information -By default, the headers do not contain details about the current usage and quotas. The default can be changed in the API management. - -#### Example -A successful response with the details about throttle (`X-Plan-QPS`) and quota (`X-Plan-Quota`) rate limits: - -``` -HTTP/1.1 200 OK - -X-Plan-QPS-Allotted: 10 -X-Plan-QPS-Current: 1 -X-Plan-Quota-Allotted: 1000 -X-Plan-Quota-Current: 2 -X-Plan-Quota-Reset: Tuesday, June 6, 2017 12:00:00 AM GMT -``` diff --git a/execution/testing-enviroments.md b/execution/testing-enviroments.md index f51c49a..e69de29 100644 --- a/execution/testing-enviroments.md +++ b/execution/testing-enviroments.md @@ -1,3 +0,0 @@ -# Testing Environments -Every API implementation **SHOULD** aim to provide a consistent, seamless way to create **test accounts** and access **test fixtures** to facilitate the development of API client applications. - diff --git a/guides/README.md b/guides/README.md index bf7dfc5..e69de29 100644 --- a/guides/README.md +++ b/guides/README.md @@ -1,9 +0,0 @@ -# Guides -API-related guides: - -- [API Design Process](https://tools.adidas-group.com/confluence/display/EA/API+Design+Process) -- Migration of Legacy Services (SOAP) -- API Testing with Dredd -- Continuous Integration / Deployment / Delivery -- [Apiary](https://help.apiary.io/api_101/understanding-apiary/) -- API Management \ No newline at end of file diff --git a/guides/api-testing-ci-environment.md b/guides/api-testing-ci-environment.md index 49fd22e..e69de29 100644 --- a/guides/api-testing-ci-environment.md +++ b/guides/api-testing-ci-environment.md @@ -1,101 +0,0 @@ -# Jenkins CI Environment for Apiary Project - -This guide describes steps necessary for testing an API described in a swagger file with the [Dredd API Testing Framework](https://github.com/apiaryio/dredd) in a CI Environment (Jenkins, TeamCity). - -## Environment Prerequisites -The following must be available in the CI environment before testing: - -1. **Node.js** runtime MUST be available in the CI environment: - - ``` - $ node -v - v7.5.0 - ``` - -1. **Ruby** runtime MUST be available in the CI environment: - - ``` - $ ruby -v - ruby 2.4.0p0 (2016-12-24 revision 57164) [x86_64-darwin16] - ``` - -1. [**Dredd**](https://github.com/apiaryio/dredd) MUST be installed globally in the CI environment: - - ``` - $ npm install -g dredd --no-optional - ``` - - ``` - $ dredd --version - dredd v2.2.5 (Darwin 16.4.0; x64) - ``` - -1. [**Apiary CLI Tool**](https://help.apiary.io/tools/apiary-cli) MUST be installed globally in the CI environment: - - ``` - $ gem install apiaryio - ``` - - ``` - $ apiary version - 0.8.0 - ``` - -1. **Apiary API Key** MUST be set in the CI Environment environment variables: - - ``` - $ export APIARY_API_KEY=xyz - ``` - - To obtain an Apiary API key, head to (NOTE: You will need the "ALL" Scope) - -## Testing an API - - -### Test Run Prerequisites -To test an API within the CI environment provisioned as mentioned in the environment prerequisites, you will need the following: - -1. The name (subdomain) of API project at Apiary - - ``` - $ export APIARY_API_NAME=bomapi3 - ``` - - > See [How to find the Apiary API name](https://help.apiary.io/faq/find-api-name/) for more details. - -1. A `swagger.yaml` file with the description of API being tested - - To fetch the swagger.yaml file from Apiary run the following command before the test: - - ``` - $ apiary fetch --api-name=$APIARY_API_NAME --output="swagger.yaml" - ``` - - The swagger document for Apiary project `bomapi3` was saved as local file `./swagger.yaml`. - - > See [Fetching Published Documentation](https://help.apiary.io/tools/apiary-cli/#fetching-published-documentation). - -1. The host (address) of the service being tested - - ``` - $ export API_HOST=http://deheremap7336.emea.adsint.biz:8004` - ``` - -### Running the Test - -With all of the above (`APIARY_API_KEY`, `APIARY_API_NAME`, `API_HOST`, set up and `swagger.yaml` file present in the current directory), run: - - -``` -$ dredd swagger.yaml $API_HOST -r apiary -``` - -> See [Dredd Command-line Interface](https://dredd.readthedocs.io/en/latest/usage-cli/). - -The Dredd will perform the tests and exits usually if the tests have passed. You can check the test result as with any other Unix tools with: - -``` -$ echo $? -``` - -Everything else but `0` should break the build. The test results will be visible in the CLI (log) as well as in Apiary. diff --git a/message/content-negotiation.md b/message/content-negotiation.md index bd71338..e69de29 100644 --- a/message/content-negotiation.md +++ b/message/content-negotiation.md @@ -1,28 +0,0 @@ - -# Content Negotiation -Every API **MUST** implement and every API Consumer **MUST** use the [HTTP content negotiation](https://tools.ietf.org/html/rfc7231#section-3.4) where a representation of a resource is requested. - -> NOTE: The content negotiation plays the key role in evolving an API, **change management and versioning**. - -#### Example -A client is programmed to understand the `application/vnd.example.resource+json; version=2` message format semantics. The client requests a representation of the `/greeting` resource in desired the media type (including its version) from the server: - -``` -GET /greeting HTTP/1.1 -Accept: application/vnd.example.resource+json; version=2 -... -``` - -The server can provide only a newer version of the requested media type `version=2.1.3`. But since the newer version is backward compatible with the requested `version=2` (related: Changes & Versioning) it can satisfy the request and responds: - -``` -HTTP/1.1 200 OK -Content-Type: application/vnd.example.resource+json; version=2.1.3 -... -``` - -> NOTE: A server that doesn't have the requested representation media type available MUST respond with the HTTP Status Code **406 Not Acceptable**. -> -> NOTE: A server MAY have multiple choices available and MAY respond with the **300 Multiple Choices** response. In which case client SHOULD choose from the presented choices. -> -> You can read more about content negotiation at [MDN Content negotiation](https://developer.mozilla.org/en-US/docs/Web/HTTP/Content_negotiation). diff --git a/message/error-reporting.md b/message/error-reporting.md index d43451b..e69de29 100644 --- a/message/error-reporting.md +++ b/message/error-reporting.md @@ -1,120 +0,0 @@ -# Problem Detail -The [`application/problem+json`](https://tools.ietf.org/html/rfc7807) (Problem Detail) **MUST** be used to communicate details about an error. - -Problem Detail is intended for use with the HTTP status codes 4xx and 5xx. Problem Detail **MUST NOT** be used with 2xx status code responses. - -At the minimum, any Problem Detail response **MUST** have the `title` and `detail` fields. - -#### Example - -```json -{ - "title": "Authentication required", - "detail": "Missing authentication credentials for the Greeting resource." -} -``` - -## Optional Fields -It **SHOULD** has the `type` field with the identifier of the error, besides it **MAY** have the `instance` field with the URI of the resource in question. If the Problem Detail response has the `status` field it **MUST** have the same value as HTTP Status code from of the response. - - -```json -{ - "type": "https://adidas-group.com/problems/scv/unauthorized", - "title": "Authentication required", - "detail": "Missing authentication credentials for the Greeting resource.", - "instance": "/greeting", - "status": 401 -} -``` - -> NOTE: The `type` field is an identifier, and as such it **MAY** be used to denote additional error codes. Keep in mind that the identifier should be a URI. - -## Additional Fields -If needed, the Problem Detail **MAY** include additional fields, refer to [RFC7807](https://tools.ietf.org/html/rfc7807) for details. - -## Validation Errors -When necessary, a Problem Detail response **MAY** include additional error details about the problems that have occurred. - -These additional errors **MUST** be under the `errors` and **MUST** follow the Problem Detail structure. - -#### Example - -Request: - -``` -POST /my-resource HTTP/1.1 -Content-Type: application/json - -{ - "age": -32, - "color": "cyan" -} -``` - -Response: - -``` -HTTP/1.1 400 Bad Request -Content-Type: application/problem+json -Content-Language: en - -{ - "type": "https://example.net/validation_error", - "title": "Your request parameters didn't validate.", - "instance": "/my-resource", - "status": 400, - - "errors": [ - { - "type": "https://example.net/invalid_params", - "instance": "/age", - "title": "Invalid Parameter", - "detail": "age must be a positive integer" - }, - { - "type": "https://example.net/invalid_params", - "instance": "/color", - "title": "Invalid Parameter", - "detail": "color must be 'green', 'red' or 'blue'" - } - ] -} -``` - - - -## Problem Detail and Content Negotiation -#### Example -A request is made to retrieve a resource representation: - -``` -GET /greeting HTTP/1.1 -Accept: application/hal+json -``` - -However, in order to make this request, the client needs to be authorized. Since the request is made without the authorization credentials the **401 Unauthorized** response is returned together with details using the `application/problem+json` media type: - -``` -HTTP/1.1 401 Unauthorized -Content-Type: application/problem+json -Content-Language: en - -{ - "type": "https://adidas-group.com/problems/scv/unauthorized", - "title": "Authentication required", - "detail": "Missing authentication credentials for the Greeting resource.", - "instance": "/greeting", - "status": 401 -} -``` - -## No Stack Traces or Server Logs -> _Problem details are not a debugging tool for the underlying implementation; rather, they are a way to expose greater detail about the HTTP interface itself._ -> -> _– [RFC7807](https://tools.ietf.org/html/rfc7807)_ - -A Problem Detail response **MUST NOT** contain a program stack trace or server log for debugging purposes. Instead, provide a `logref` field with reference to the particular server log. - -## Working with Problem Detail -There are a whole plethora of libraries working with Problem Detail, for example, see [Zalando / Problem](https://github.com/zalando/problem) (Java). diff --git a/message/foreign-key-relations.md b/message/foreign-key-relations.md index 6df2fe3..e69de29 100644 --- a/message/foreign-key-relations.md +++ b/message/foreign-key-relations.md @@ -1,67 +0,0 @@ -# Foreign Key Relations - -## Link or Embed Foreign Key Relation -When a resource representation includes relation with another (foreign) resource, the relation **MUST** be expressed as a link relation or embed the related resource. - -#### Example -Use: - -```json -{ - "_links": { - "author": { "href": "/users/john" } - ... - } - ... -} -``` - -or: - -```json -{ - ... - "_embedded": { - "author": { - "_links": { "self": "/users/john" }, - "name": "John Appleseed", - "email": "john@apple.com" - } - } -} -``` - -instead: - -```json -{ - ... - "authorHref": "/users/john" -} -``` - -## Nest Foreign Key Relation -If a foreign object has another identifier, but URI or the foreign object isn't a resource, the object **MUST** be nested. - -#### Example -Use: - -```json -{ - "author": { - "id": "1234", - "name": "John Appleseed", - "email": "john@apple.com" - } -} -``` - -instead: - -```json -{ - "authorId": "1234" -} -``` - -> NOTE: As a rule of thumb, in an HTTP message body, there SHOULD NOT be any field with trailing "_id," "_href," "_url" etc. in its name. diff --git a/message/hal.md b/message/hal.md index 553eb7d..e69de29 100644 --- a/message/hal.md +++ b/message/hal.md @@ -1,114 +0,0 @@ -# HAL -The [`application/hal+json`](http://stateless.co/hal_specification.html) (HAL) **MUST** be used as the representation format of a resource. - -## Introduction to HAL -> _HAL is a simple format that gives a consistent and easy way to hyperlink between resources in your API._ - -This document is an informal introduction to the HAL media type. For more details see [HAL - Hypertext Application Language Specification](http://stateless.co/hal_specification.html). - -## Simple Document Example -The simplest Hal document looks like an empty JSON (it is an empty JSON!): - -```json -{ -} -``` - -A document representing a "Greeting" resource might look like: - -```json -{ - "message": "Hello World!", - "_links": { - "self": { - "href": "/greeting" - } - } -} -``` -The field `_links` has a special meaning in HAL. It denotes a list of link relations - a pair of a relation identifier and a link (URI). - -These link relations are used to express the relation of a resource with other resources. - -In our case the "Greeting" resource isn't related to other resources but itself, hence the `self` relation pointing to the Greeting resource. - -> NOTE: It is **customary** for every resource representation to include the `self` link relation. - -> NOTE: The href **MUST** always be **relative path to the API root** (e.g. without the host and scheme). - -## Relation Example -A more complex document example could be an "Order" resource that has a related resource "Author" (a person who created the order. It might look like: - -```json -{ - "_links": { - "self": { - "href": "/orders/1234" - }, - "author": { - "href": "/users/john" - } - }, - "orderNumber": 1234, - "itemCount": 42, - "status": "pending" -} -``` - -## Embedding Example -Let's assume there is an "Orders" resource which is a collection of all orders from different authors. There is the relation between the Orders resource and possibly many Order resources. - -We could express this in the `_links` object using the `order` relation, but sometimes it is practical to "embed" (entirely or partially) related resources representations in the originating resource representation. For a scenario like this HAL offers the `_embedded` field. - -The `_embedded` field's object just contains the related resources HAL representations: - - -```json -{ - "_links": { - "self": { "href": "/orders" } - }, - "_embedded": { - "order": [ - { - "_links": { - "self": { "href": "/orders/1" } - }, - "orderNumber": "1", - "status": "pending" - }, - { - "_links": { - "self": { "href": "/orders/2" } - }, - "orderNumber": "2", - "status": "cancelled" - } - ] - } -} - -``` - -It is important to understand that embedded resource representation might be only **partial** and might also contain their own embedded resources. - -The embedded resource representation should be used as a **convenience** function (e.g. to reduce the initial number of calls needed at application launch). - -Where a full and up-to-date representation of a resource is needed the link relation should exercise the affordance (e.g. `GET /orders/2`). - -#### Real-world Examples - -Some APIs using HAL: - -- [Amazon AppStream REST API](http://docs.aws.amazon.com/appstream/latest/developerguide/appstream-api-rest.html) -- [FoxyCart](https://wiki.foxycart.com/v/2.0/start) -- [Clarify.io](http://docs.clarify.io/overview/) -- [University of Oxford / Mobile Oxford](http://api.m.ox.ac.uk/browser/#/) - - -## Working with HAL -Refer to the [extensive list of libraries that work with HAL](https://github.com/mikekelly/hal_specification/wiki/Libraries). - -### Spring Framework -Spring framework supports HAL out of the box. More info can be found in [Spring Documentation](https://spring.io/guides/gs/rest-hateoas/) -and [examples](https://github.com/spring-guides/gs-rest-hateoas). diff --git a/protocol/separate-concerns.md b/protocol/separate-concerns.md index f8380eb..e69de29 100644 --- a/protocol/separate-concerns.md +++ b/protocol/separate-concerns.md @@ -1,49 +0,0 @@ -# Separate Concerns -Every API using HTTP/S API **MUST** precisely follow the concern separation of an HTTP message: - -1. A _resource identifier_–URI **MUST** be used to indicate **identity** only -1. _HTTP request method_ **MUST** be used to communicate the **action semantics** (intent and safety) -1. _HTTP response status_ code **MUST** be used to communicate the **information about the result** of the attempt to understand and satisfy the request -1. _HTTP message body_ **MUST** be used to transfer the **message content** -1. _HTTP message headers_ **MUST** be used to transfer the **metadata** about the message and its content -1. _URI query parameter_ **SHOULD NOT** be used to transfer metadata - - -#### Example 1 -The rule - -> A resource identifier–URI **MUST** be used to indicate identity only - -implies there **MUST NOT** be any information about the representation media type, version of the resource or anything else in the URI. - -For example, URIs `/greeting.json` or `/v2.1.3/greeting` are **illegal** as they are not used for identification of a resource only but they convey the information about representation format or version. URIs are not meant to carry any other information but the identifier of the resource. - - -#### Example 2 -The rule - -> HTTP message body MUST be used to transfer the message content - -Implies an HTTP GET request **MUST NOT** use HTTP message body to identify the resource. For example a request: - -``` -GET /greeting HTTP/1.1 -Content-Type: application/json -... - - -{ - "filter": "string" - "depth": 3 -} -``` - -is **not acceptable** (ignoring the fact that HTTP GET method shouldn't have the body). To express identity use URI and query parameters instead e.g. `/greeting?filter=string&depth=3`. - ---- - -> _Keep things simple while designing by separating the concerns between the different parts of the request and response cycle. Keeping simple rules here allows for greater focus on larger and harder problems._ -> -> _Requests and responses will be made to address a particular resource or collection. Use the path to indicate identity, the body to transfer the contents and headers to communicate metadata. Query params may be used as a means to pass header information also in edge cases, but headers are preferred as they are more flexible and can convey more diverse information._ -> -> _– [Heroku HTTP API Design Guide](https://geemus.gitbooks.io/http-api-design/content/en/foundations/separate-concerns.html)_ diff --git a/protocol/tls.md b/protocol/tls.md index 1dad60a..e69de29 100644 --- a/protocol/tls.md +++ b/protocol/tls.md @@ -1,4 +0,0 @@ -# Transport Layer Security (TLS) -Every API **MUST** require secure connections with **TLS 1.2**. That is, an API using the HTTP protocol **MUST** use **HTTPS**. - -Any non-TLS requests **SHOULD** be ignored. In **HTTP** environments where this is not possible, a non-TLS request **SHOULD** result in the **403 Forbidden** response. \ No newline at end of file diff --git a/protocol/use-appropriate-methods.md b/protocol/use-appropriate-methods.md index fc40a44..e69de29 100644 --- a/protocol/use-appropriate-methods.md +++ b/protocol/use-appropriate-methods.md @@ -1,45 +0,0 @@ -# Use Appropriate Request Methods -Every API **MUST** use appropriate [HTTP request methods](https://github.com/for-GET/know-your-http-well/blob/master/methods.md) for every operation. - -Every API designer, implementer and consumer **MUST** understand the semantic of the HTTP METHOD she is using. - -At a minimum everyone **MUST** be familiar with the semantics of ["Common" HTTP Request Methods](https://github.com/for-GET/know-your-http-well/blob/master/methods.md#common): **DELETE**, **GET**, **HEAD**, **PUT**, **POST** and the [**PATCH** HTTP Request Method](https://tools.ietf.org/html/rfc5789#section-2). In addition, everyone **MUST** be aware which methods are **Safe**, **Idempotent** and **Cacheable**. - -### Safe Methods -As per HTTP specification, the **GET** and **HEAD** methods should be used only for retrieval of resource representations – and they do not update/delete the resource on the server. Both methods are said to be considered “safe“. -This allows user agents to represent other methods, such as POST, PUT and DELETE, in a special way, so that the user is made aware of the fact that a possibly unsafe action is being requested – and they can update/delete the resource on the server and so should be used carefully. - - -### Idempotent Methods -The term idempotent is used more comprehensively to describe an operation that will produce the same results if executed once or multiple times. This is a beneficial property in many situations, as it means that a transaction can be repeated or retried as often as necessary without causing unintended effects. With non-idempotent operations, the algorithm may have to keep track of whether the operation was already performed or not. -In HTTP specification, The methods **GET**, **HEAD**, **PUT** and **DELETE** are declared idempotent methods. Other methods OPTIONS and TRACE **SHOULD NOT** have side effects, so both are also inherently idempotent. - -### Cacheable Methods -Request methods are considered "cacheable" if it is possible and useful to answer a current client request with a stored response from a prior request. **GET** and **HEAD** are defined to be cacheable. - ---- - -#### Example 1 -> GET /user/new -> Description: Creates new user - -Using GET for unsafe non-idempotent operations is **not acceptable**. - -#### Example 2 -> POST /status -> Description: Updates the status of a user approval request (to “Approved” or “Rejected”) - -Using the POST method for a status update is **not acceptable** (use PATCH). - -#### Example 3 -> PUT /user -> Description: Creates a new user - -Using the PUT method for creating a new resource is **not acceptable** (use POST). - -#### Example 4 -> PUT: /user -> Description: Updates some user details - -Using the PUT method for a partial update is **not acceptable** (use PATCH). - diff --git a/protocol/use-appropriate-status-codes.md b/protocol/use-appropriate-status-codes.md index 6ba5f8f..e69de29 100644 --- a/protocol/use-appropriate-status-codes.md +++ b/protocol/use-appropriate-status-codes.md @@ -1,44 +0,0 @@ -# Use Appropriate Status Codes -Every API **MUST** use the appropriate [HTTP Status Codes](https://github.com/for-GET/know-your-http-well/blob/master/status-codes.md) to communicate the result of a request operation. - -Every API designer, implementer and consumer **MUST** understand the semantic of the HTTP Status Code she is using. - -At a minimum everyone **MUST** be familiar with the semantics of ["Common" HTTP Status Codes](https://github.com/for-GET/know-your-http-well/blob/master/status-codes.md#common). - -#### Example - -#### Use Codes 4xx or 5xx to Communicate Errors -A request: - -``` -GET /orders/1234 HTTP/1.1 -... -``` - -resulting in the **200 OK** response, when the requested resource (as identified by request URI) couldn't be found: - -``` -HTTP/1.1 200 OK -Content-Type: application/json -... - - -{ - "code": "NOT_FOUND_ERR_CODE" - "message" "Order 1234 wasn't found" -} -``` -is **not acceptable**. - -Instead the - -``` -HTTP/1.1 404 Not Found -... -``` - -should be returned. - -#### Recommended Reading -- [How to Think About HTTP Status Codes](https://www.mnot.net/blog/2017/05/11/status_codes) - diff --git a/core-principles/contract.md b/rest/README.md similarity index 100% rename from core-principles/contract.md rename to rest/README.md diff --git a/application/README.md b/rest/application/README.md similarity index 100% rename from application/README.md rename to rest/application/README.md diff --git a/rest/application/common-data-types.md b/rest/application/common-data-types.md new file mode 100644 index 0000000..a00d03d --- /dev/null +++ b/rest/application/common-data-types.md @@ -0,0 +1,37 @@ +# Common Data Types + +## Date and Time Format +Date and Time **MUST** always conform to the [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) format e.g.: `2017-06-21T14:07:17Z` (date time) or `2017-06-21` (date), it **MUST** use the UTC (without time offsets). + +## Duration Format +Duration format **MUST** conform to the [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) standard e.g.: `P3Y6M4DT12H30M5S` (three years, six months, four days, twelve hours, thirty minutes, and five seconds). + +## Time Interval Format +Time Interval format **MUST** conform to the [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) standard e.g.: `2007-03-01T13:00:00Z/2008-05-11T15:30:00Z`. + +## Standard Time Stamps +Where applicable, a resource representation **SHOULD** contain the standard timestamps: + +- `createdAt` +- `updatedAt` +- `finishedAt` + +#### Example + +```json +{ + "createdAt": "2017-01-01T12:00:00Z", + "updatedAt": "2017-01-01T13:00:00Z", + + ... +} +``` + +## Language Code Format +Language codes **MUST** conform to the [ISO 639](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) e.g.: `en` for English. + +## Country Code Format +Country codes **MUST** conform to the [ISO 3166-1 alpha-2](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2) e.g.: `DE` for Germany. + +## Currency Format +Currency codes **MUST** conform to the [ISO 4217](https://en.wikipedia.org/wiki/ISO_4217) e.g.: `EUR` for Euro. diff --git a/application/harmonize-data.md b/rest/application/harmonize-data.md similarity index 100% rename from application/harmonize-data.md rename to rest/application/harmonize-data.md diff --git a/clients/README.md b/rest/clients/README.md similarity index 100% rename from clients/README.md rename to rest/clients/README.md diff --git a/clients/loose-coupling.md b/rest/clients/loose-coupling.md similarity index 100% rename from clients/loose-coupling.md rename to rest/clients/loose-coupling.md diff --git a/core-principles/README.md b/rest/core-principles/README.md similarity index 100% rename from core-principles/README.md rename to rest/core-principles/README.md diff --git a/core-principles/rules-for-extending.md b/rest/core-principles/api-first.md similarity index 100% rename from core-principles/rules-for-extending.md rename to rest/core-principles/api-first.md diff --git a/rest/core-principles/apiary.md b/rest/core-principles/apiary.md new file mode 100644 index 0000000..aa4985e --- /dev/null +++ b/rest/core-principles/apiary.md @@ -0,0 +1,16 @@ +# API Design Platform - Apiary + +1. [Apiary](https://apiary.io/) is the primary platform supporting [API first approach](./api-first.md). Apiary **MUST** be used during API Design. + +2. Every API description **MUST** be stored in [Apiary](https://apiary.io/) under the ADIDAS GROUP team. + +3. Apiary **MUST** be the **single source of truth** to learn about existing APIs within the organization. + +> NOTE: Apiary supports API-first approach in multiple ways: +> a. Validates API description for correctness and automatically generates API documentation to drive the discussion between stakeholders. \(No more emails with API description flying between stakeholders\) +> +> NOTE: The synchronization between the version control system and adidas [API Description platform](./apiary.md) +> should be automated using CI/CD framework. + + + diff --git a/core-principles/version-control-system.md b/rest/core-principles/contract.md similarity index 100% rename from core-principles/version-control-system.md rename to rest/core-principles/contract.md diff --git a/evolution/json.md b/rest/core-principles/core-principles.md similarity index 100% rename from evolution/json.md rename to rest/core-principles/core-principles.md diff --git a/rest/core-principles/design-maturity.md b/rest/core-principles/design-maturity.md new file mode 100644 index 0000000..5ed72de --- /dev/null +++ b/rest/core-principles/design-maturity.md @@ -0,0 +1,16 @@ +# Design & Implementation Maturity + +## API Design Maturity +> How to design an API + + +Every API design **MUST** be **resource-centric** ([Web API Design Maturity Model Level 2](http://amundsen.com/talks/2016-11-apistrat-wadm/2016-11-apistrat-wadm.pdf)). That is an API design **MUST** revolve around Web-styled _resources_, _relations_ between the resources and the _actions_ the resources may afford. + +An API design **MAY** be **affordance-centric** ([Web API Design Maturity Model Level 3](http://amundsen.com/talks/2016-11-apistrat-wadm/2016-11-apistrat-wadm.pdf)). + +## API Design Implementation Maturity +> How to implement the API design + +Every API design implementation using the HTTP protocol **MUST** use the appropriate **HTTP Request Method** ([Richardson Maturity Model Level 2](https://martinfowler.com/articles/richardsonMaturityModel.html#level2)) to implement an action afforded by a resource. + +An API design implementation **SHOULD** include **hypermedia controls** (HATEOAS) ([Richardson Maturity Model Level 3](https://martinfowler.com/articles/richardsonMaturityModel.html#level3)). diff --git a/rest/core-principles/introduction.md b/rest/core-principles/introduction.md new file mode 100644 index 0000000..deea0b3 --- /dev/null +++ b/rest/core-principles/introduction.md @@ -0,0 +1,45 @@ +# adidas REST API Guidelines + +The adidas REST API Guidelines defines standards and guidelines for building REST APIs at adidas. These Guidelines has to be followed in addition to the General Guidelines. + +The REST API Guidelines are further split into the following parts: + +* **Core Principles** + + REST API Guidelines Core Principles defines the rules that **MUST** be followed at throughout the full API lifecycle. + +* **Functionality Guidelines** + + * [**Protocol level**](https://adidas-group.gitbooks.io/api-guidelines/content/protocol/) + + Protocol guidelines define the protocols used within the organization. + + * [**Message level**](https://adidas-group.gitbooks.io/api-guidelines/content/message/) + + The Message guidelines define the structure and semantics of messages used to exchange information. + + * [**Application level**](https://adidas-group.gitbooks.io/api-guidelines/content/application/) + + The Application guidelines define the definition and use of application-specific semantics. + +* **Quality Guidelines** + + Evolution and Execution guidelines define the rules for achieving the desired architectural qualities of systems. + + * [**Evolution**](https://adidas-group.gitbooks.io/api-guidelines/content/evolution/) + + Evolution qualities governance, such as testability, maintainability, extensibility, and scalability. + + * [**Execution**](https://adidas-group.gitbooks.io/api-guidelines/content/execution/) + + Execution qualities governance, such as security and usability. + +* **Guides** + Guides and materials supporting the REST API Guidelines + +* **API Clients** + + Section dedicated to consumers of adidas APIs + + + diff --git a/rest/core-principles/openapi-specification.md b/rest/core-principles/openapi-specification.md new file mode 100644 index 0000000..c54f215 --- /dev/null +++ b/rest/core-principles/openapi-specification.md @@ -0,0 +1,7 @@ +# OpenAPI Specification +Every API **MUST** be described using an API description format. The API description format used MUST be the [OpenAPI Specification (formerly known as Swagger Specification) version 2.0](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md). + +Every API description **MUST** be published in adidas [API design platform](./apiary.md) and it **SHOULD** be stored in version control system (Bitbucket, GitHub) in the same repository as the API implementation. + +## Language +The API description MUST be written in **American English**. diff --git a/execution/security.md b/rest/core-principles/quality.md similarity index 100% rename from execution/security.md rename to rest/core-principles/quality.md diff --git a/rest/core-principles/testing.md b/rest/core-principles/testing.md new file mode 100644 index 0000000..9a8ca38 --- /dev/null +++ b/rest/core-principles/testing.md @@ -0,0 +1,4 @@ +# Testing – Contract Validation +Every API description (contract) using HTTP(S) protocol **MUST** be tested against its API implementation. The tests **MUST** be executed using the [Dredd testing framework](https://github.com/apiaryio/dredd). The Dredd **MUST** [report the test results to Apiary](https://help.apiary.io/tools/automated-testing/testing-reporter/). + +In addition to local runs, the tests **SHOULD** be an integral part the API implementation's CI/CD pipeline. The CI/CD pipeline **SHOULD** be configured to run the test whenever there is a change to either API description (contract) or its implementation. diff --git a/rest/core-principles/version-control-system.md b/rest/core-principles/version-control-system.md new file mode 100644 index 0000000..e69de29 diff --git a/evolution/README.md b/rest/evolution/README.md similarity index 100% rename from evolution/README.md rename to rest/evolution/README.md diff --git a/rest/evolution/json.md b/rest/evolution/json.md new file mode 100644 index 0000000..e69de29 diff --git a/rest/evolution/naming-conventions.md b/rest/evolution/naming-conventions.md new file mode 100644 index 0000000..8e25cf0 --- /dev/null +++ b/rest/evolution/naming-conventions.md @@ -0,0 +1,117 @@ +# Naming Conventions + +## General Naming Rules + +- Use American English +- Don't use acronyms +- Use `camelCase` unless stated otherwise +- Reconcile terms with adidas CDM + +Every identifier **MUST** be in American English and written in `lowercase`. An identifier **SHOULD NOT** contain acronyms. CamelCase (`camelCase`) **MUST** be used to delimit combined words. + +## URI +Every URI **MUST** follow the General Rules except for the `camelCase` rule. Instead, a hyphen (`-`) **SHOULD** be used to delimit combined words (kebab-case). Besides, a URI **MUST NOT** end with a trailing slash (`/`). + +#### Example +A well-formed URI: + +``` +/system-orders/1234/author +``` + +### Query Parameters and Path Fragments +Every URI query parameter or fragment **MUST** follow the General Rules. Also, they **MUST NOT** clash with the [reserved query parameter names](https://tools.adidas-group.com/confluence/display/EA/API+Interaction#APIInteraction-Query_Parameters). + +### URI Template Variables +In addition to General Naming Rules, URI Template Variable names **MUST** follow the [RFC6570](https://tools.ietf.org/html/rfc6570#section-2.3). That is, the variable names can consist only from `ALPHA / DIGIT / "_" / pct-encoded`. + +> NOTE: Per RFC6570 Hyphen (`-`) is NOT legal URI Template variable name character. + +#### Example +A well-formed URI Template Variable: + +``` +/system-orders/{orderId}/author +``` + +## Representation Format Fields +Every representation format field **MUST** conform to the General Naming Rules. + +#### Example +A well-formed resource representation: + +```json +{ + "_links": { + "self": { + "href": "/orders/1234" + }, + "author": { + "href": "/users/john" + } + }, + "orderNumber": 1234, + "itemCount": 42, + "status": "pending" +} +``` + +## Relation Type Identifier +Every custom [relation identifier](https://github.com/for-GET/know-your-http-well/blob/master/relations.md) **MUST** be in `lowercase` with words separated by the hyphen (`-`). + +#### Example +A well-formed resource representation with custom relation `fulfillment-provider`: + +```json +{ + "_links": { + "fulfillment-provider": { + "href": "/users/natalie" + } + } +} +``` + + +## HTTP Headers +Every HTTP Header should use `Hyphenated-Pascal-Case`. A custom HTTP Header **SHOULD NOT** start with `X-` ([RFC6648](https://tools.ietf.org/html/rfc6648)). + +#### Example + +``` +Order-Metadata-Header: 42 +``` + + +## API Description +Naming conventions within API Description document. + +### API Name +Every API Description API name **MUST** start with API domain enclosed in square brackets (e.g. `[API Domain] My API`). Words **MUST** be separated by space. + +#### Example + +```yaml +swagger: '2.0' +info: + version: '1.0.0' + title: '[Demo] Orders API' +``` + +### Resource Name +Every resource **MUST** have a name (defined by `x-summary` field). Resource name **MUST** be in `Title Case`. Words **MUST** be separated by a space. + +#### Example +```yaml +/orders: + x-summary: List of Orders +``` + +### Action Name +Every action (operation) **MUST** have a name (defined by `summary` field). Action name **MUST** be in `Title Case`. Words **MUST** be separated by a space. + +#### Example +```yaml +get: + summary: Retrieve List of Orders +``` diff --git a/evolution/reserved-identifiers.md b/rest/evolution/reserved-identifiers.md similarity index 100% rename from evolution/reserved-identifiers.md rename to rest/evolution/reserved-identifiers.md diff --git a/rest/evolution/uri-structure.md b/rest/evolution/uri-structure.md new file mode 100644 index 0000000..a9ecbcd --- /dev/null +++ b/rest/evolution/uri-structure.md @@ -0,0 +1,8 @@ +# URI Design +URI is meant to express a **identity of a resource**. URI is an identifier and it **MUST NOT** convey any other information. + +The API design process **MUST NOT** start with the design of URIs. Contrary, the URI **SHOULD** be amongst the last few things added to the API design. + +At adidas, URIs are subject to [naming conventions](https://adidas-group.gitbooks.io/api-guidelines/content/evolution/naming-conventions.html). + +To read more about the problematics refer to [RFC 7320: URI Design and Ownership](https://tools.ietf.org/html/rfc7320). diff --git a/rest/evolution/versioning.md b/rest/evolution/versioning.md new file mode 100644 index 0000000..a45eedc --- /dev/null +++ b/rest/evolution/versioning.md @@ -0,0 +1,102 @@ +# Changes and Versioning + +> _The fundamental principle is that you can’t break existing clients, because you don’t know what they implement, and you don’t control them. In doing so, you need to turn a backwards-incompatible change into a compatible one._ +> +> _– _[_Mark Nottingham_](https://www.mnot.net/blog/2011/10/25/web_api_versioning_smackdown) + +Any change to an API **MUST NOT** break existing clients. + +Any change to: +1. **Resource identifier** \(resource name / URI\) including any **query parameters** and their semantics +1. **Resource metadata** \(e.g. HTTP headers\) +1. **Action** the resource affords \(e.g. available HTTP Methods\) +1. **Relation** with other resources \(e.g Links\) +1. **Representation format** \(e.g. HTTP request and response bodies\) + +**MUST** follow the [**Rules for Extending**](https://adidas-group.gitbooks.io/api-guidelines/content/core-principles/rules-for-extending.html). + +## Identifier Stability \(No URI Versioning\) + +A change **MUST NOT** affect **existing** resource identifiers \(name / URI\). Furthermore, a resource identifier **MUST NOT** contain a semantic version to convey a version of resource or its representation format. + +> _The reason to make a real REST API is to get evolvability … a "v1" is a .... to your API customers, indicating RPC/HTTP \(not REST\)_ +> +> _– _[_Roy T. Fielding_](https://twitter.com/fielding/status/376835835670167552) + +#### Example + +Adding a new action to existing resource with identifier `/greeting` doesn't change its identifier to `/v2/greeting` \(or `/greeting-with-new-action` etc.\). + +## Backward-incompatible Changes + +A change to _resource identifier_, _resource metadata_, _resource actions_ and _resource relations_ that can't follow the [Rules for Extending](https://adidas-group.gitbooks.io/api-guidelines/content/core-principles/rules-for-extending.html) **MUST** result into a **new resource variant**. Existing resource variant **MUST** be preserved. + +A change to _representation format_ **SHOULD NOT** result into a new resource variant. + +#### Example + +Currently, optional URI Query Parameter `first` on an existing resource `/greeting?first=John&last=Appleseed` needs to be made required. Since this change violates the 3rd rule of extending and could break existing clients a new variant of the resource is created with different URI `/named-greeting?first=John&last=Appleseed`. + +### Representation Format Changes + +> A representation format is the serialization format \(media type\) used in request and response bodies, and typically it represents a resource or its part, possibly with additional hypermedia controls. + +If a change can't follow the Rules for Extending the representation format media type **MUST** be changed. If the media type has been changed the previous media type, **MUST** be available via [Content Negotiation](https://adidas-group.gitbooks.io/api-guidelines/content/message/content-negotiation.html). + +If the media type conveys the version parameter, the version parameter **SHOULD** follow [Semantic versioning](http://semver.org/). + +#### Example + +Media type _before_ a breaking change: + +``` +application/vnd.example.resource+json; version=2 +``` + +Media type _after_ a breaking change: + +``` +application/vnd.example.resource+json; version=3 +``` + +> NOTE: In the case of technical limitations with semi-colon separated HTTP header values, the semantic version MAY be incorporated in the media type identifier, for example: `application/vnd.example.resource.v2+json` However, the use of semicolon-separated version information is preferred. + +## API Description Versioning + +API Description in the OpenAPI specification format **MUST** have the `version` field. The `version` field **MUST** follow [Semantic versioning](http://semver.org/): + +> Given a version number MAJOR.MINOR.PATCH, increment the: +> +> * MAJOR version when you make **incompatible** API changes, +> * MINOR version when you add functionality in a **backwards-compatible** manner +> * PATCH version when you make **backwards-compatible bug fixes** + +The API Description version **SHOULD** be updated accordingly to API design change. + +#### Example + +Following API Description + +```yaml +swagger: '2.0' +info: + version: '2.1.3' + title: '[Demo] Inventory API' + description: 'Inventory service API' +``` + +Has MAJOR version 2, MINOR version 1 and PATCH version 3. + +#### Demo + +API description \(OAS2\) files demonstrating a proposal of an backward-incompatible change turned into a backward compatible change are available at [Bitbucket \(diff\) ](https://bitbucket.org/apidesigner/demo-versioning-api/pull-requests/1/add-name-parameter/diff)and documented in Apiary: + +* [Production version](https://demoversioningproduction.docs.apiary.io/#) as being consumed by clients +* [Development version](https://demoversioningdevelopment.docs.apiary.io/#) proposing a backward incompatible change + +#### Recommended Reading + +* [Evolving HTTP APIs](https://www.mnot.net/blog/2012/12/04/api-evolution) + + + diff --git a/examples.md b/rest/examples.md similarity index 100% rename from examples.md rename to rest/examples.md diff --git a/rest/execution/README.md b/rest/execution/README.md new file mode 100644 index 0000000..3477681 --- /dev/null +++ b/rest/execution/README.md @@ -0,0 +1,2 @@ +# Execution +Performance qualities, such as security and usability, which are observable at run time. diff --git a/execution/api-keys.md b/rest/execution/api-keys.md similarity index 100% rename from execution/api-keys.md rename to rest/execution/api-keys.md diff --git a/rest/execution/asynchronous-tasks.md b/rest/execution/asynchronous-tasks.md new file mode 100644 index 0000000..2c61486 --- /dev/null +++ b/rest/execution/asynchronous-tasks.md @@ -0,0 +1,26 @@ +# Asynchronous Tasks +If an API operation is asynchronous, but a client could track its progress, the response to such an asynchronous operation **MUST** return, in the case of success, the **202 Accepted** status code together with an `application/hal+json` representation of a new **task-tracking resource**. + +## Task Tracking Resource +The task-tracking resource **SHOULD** convey the information about the status of an asynchronous task. + +Retrieval of such a resource using the HTTP GET Request Method **SHOULD** be designed as follows: + +1. Task is Still Processing + + Return **200 OK** and representation of the current status. + +2. Task Successfully Completed + + Return **303 See Other** together with [HTTP Location Header](https://tools.ietf.org/html/rfc7231#section-7.1.2) with URI or a outcome resource. + +3. Task Failed + + Return **200 OK** and `application/problem+json` with the problem detail information on the task has failed. + + +## Design Note +The asynchronous operation task-tracking resource can be either **polled** by client or the client might initially provide a **callback** to be executed when the operation finishes. + +In the case of callback, the API and its client MUST agree on what HTTP method and request format is used for the callback invitation. If built within adidas, the "client" API is also the subject of the adidas API guidelines. + diff --git a/execution/authentication.md b/rest/execution/authentication.md similarity index 100% rename from execution/authentication.md rename to rest/execution/authentication.md diff --git a/execution/batch-operations.md b/rest/execution/batch-operations.md similarity index 100% rename from execution/batch-operations.md rename to rest/execution/batch-operations.md diff --git a/rest/execution/caching.md b/rest/execution/caching.md new file mode 100644 index 0000000..1fe746d --- /dev/null +++ b/rest/execution/caching.md @@ -0,0 +1,45 @@ +# Caching +Every API implementation **SHOULD** return both the cache expiry information ([`Cache-Control` HTTP header](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control)) and specific resource version information ([`ETag` HTTP Header](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/ETag)). + +## Cache-Control +Every API implementation's response **SHOULD** include information about cache-ability and cache expiration of the response. For HTTP 1.1 this is achieved using the `Cache-Control` header. + + +### Common Cache-Control Scenarios +Two, most common scenarios for controlling the cache-ability of a response includes (1) Setting expiration and revalidation and (2) disabling the caching of a response. Refer to the [Cache-Control Documentation](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control) for additional controls. + +#### 1. Cache Expiration & Revalidation +The common scenario to set cache expiration and revalidation policy is to use the `max-age` and `must-revalidate` directives: + +``` +HTTP/1.1 200 OK +Date: Mon, 19 Aug 2017 00:00:00 CEST +Last-Modified: Mon, 19 Aug 2017 00:00:00 CEST +Cache-Control: max-age=3600,must-revalidate +Content-Type: application/hal+json; charset=UTF-8 + +... +``` + +#### 2. Disabling Cache +To disable caching completely API implementation **SHOULD** use the `no-cache` and `no-store` directives: + +``` +HTTP/1.1 200 OK +Date: Mon, 19 Aug 2017 00:00:00 CEST +Last-Modified: Mon, 19 Aug 2017 00:00:00 CEST +Cache-Control: no-cache, no-store, must-revalidate +Content-Type: application/hal+json; charset=UTF-8 + +... +``` + +## ETag +Every API implementation's response to a [cacheable request](https://github.com/for-GET/know-your-http-well/blob/master/methods.md#cacheable) **SHOULD** include the [`ETag` HTTP Header](https://tools.ietf.org/html/rfc7232#section-2.3) to identify the specific version of the returned resource. + +Every API client **SHOULD** use [`If-None-Match` HTTP header](https://tools.ietf.org/html/rfc7232#section-3.2) whenever it's performing a cacheable request. The value of `If-None-Match` should be the value of the `ETag` header stored from a previous request. The client **MUST** be ready to handle the **304 Not Modified** response from the server to use the legal copy. + +#### How ETag works +ETags are unique identifiers for a particular version of a resource found by a URL. They are used for cache validation, to check for modifications quickly. + +A client requests a resource from the server at a particular URI. The server responds with the specific ETag value in the HTTP ETag header field. ETag and the resource will be stored locally by the client. Subsequent requests from the client are done with the If-None-Match header, which now contains the ETag value from the previous request. The server now compares the values. If they are the same, it responds with HTTP Status Code 304 Not Modified. If not, the resource is sent. diff --git a/rest/execution/choosing-fields-and-embedded-resoruces.md b/rest/execution/choosing-fields-and-embedded-resoruces.md new file mode 100644 index 0000000..515738c --- /dev/null +++ b/rest/execution/choosing-fields-and-embedded-resoruces.md @@ -0,0 +1,80 @@ +# Choosing Fields & Embedded Resources + + +## Response Message Fields +Every request that may result in a response with a non-trivial body **SHOULD** implement the `fields` query parameter. If provided, the value of this parameter must be a comma-separated list of top-level response message fields. + +Upon receiving such a request, in the event of a 2xx response, the service **SHOULD** respond with a message that includes only top-level fields specified in the `fields` parameter. That includes HAL-specific fields (`_links` and `_embedded`). + +#### Example +Retrieve only some details of an Order resource: + +HTTP Request +``` +GET /order/1234?fields=_links,orderNumber,status HTTP/1.1 +Accept: application/hal+json +``` + +HTTP Response +``` +HTTP/1.1 200 OK +Content-Type: application/hal+json + +{ + "_links": { + "self": { "href": "/orders/1234" }, + "author": { "href": "/users/john" }, + "items": [ ... ] + }, + "orderNumber": 1234, + "status": "pending" +} +``` + +## Embedded Resources +Similarly to the `fields` query parameter, every request that might result in a response containing related embedded resource representations **SHOULD** implement the `embedded` query parameter. If, provided the value of the `embedded` query parameter **MUST** be a comma-separated list of relation identifiers. + +Upon receiving such a request, in the event of a 2xx response, the service **SHOULD** respond with a message that "embeds" (see HAL `_embedded` field) only the related resources specified in the `embedded` parameter. + + +#### Example +Embed only information about the Author of an Order resource. We are not interested in Items that are in this order. + +HTTP Request + +``` +GET /order/1234?embed=author HTTP/1.1 +Accept: application/hal+json +``` + +HTTP Response +``` +HTTP/1.1 200 OK +Content-Type: application/hal+json + +{ + "_links": { + "self": { "href": "/orders/1234" }, + "author": { "href": "/users/john" }, + "items": [ ... ] + }, + "orderNumber": 1234, + "itemCount": 42, + "status": "pending", + "_embedded": { + "author": { + "_links": { "self": "/users/john" }, + "name": "John Appleseed", + "email": "john@apple.com" + } + } +} +``` + +## Reasonable Defaults +When `fields` and `embedded` parameters are not provided or not implemented the server **SHOULD** return reasonable default field and/or embedded resources. The defaults **MUST** always contain the `_links` field, where available. + +## Resource Variants +The facility of `fields` and `embedded` parameters doesn't impose any restriction of creating new resource variants. + +It is OK to create a new resource just as a compound resource only to provide selected fields or blend-embed some existing resources together. diff --git a/rest/execution/localization.md b/rest/execution/localization.md new file mode 100644 index 0000000..eb96e61 --- /dev/null +++ b/rest/execution/localization.md @@ -0,0 +1,37 @@ +# Localization + +## Language Variants +If a resource has multiple language variants and the difference between variants is only in the language of human-readable fields, then the [`Accept-Language`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept-Language) request HTTP header **SHOULD** be used to select the desired language variant. + +#### Example + +``` +GET /article HTTP/1.1 +Accept-Language: en,en-US,fr;q=0.6 +``` + +``` +HTTP/1.1 200 OK +Content-Type: application/hal+json;charset=UTF-8 +Content-Language: en +Vary: Accept-Language + +... +``` + +## Language or Country-specific Data Structure +If the difference between language or country specific variants of a resource is bigger than just in the content of human readable strings, for example, the data structure of the resource representation is different, then a query parameter **SHOULD** be used to communicate the requested variant. + +#### Example + +``` +GET /article?market=en_US HTTP/1.1 +``` +``` +HTTP/1.1 200 OK +Content-Type: application/hal+json;charset=UTF-8 +Content-Language: en +Vary: Accept-Language + +... +``` diff --git a/rest/execution/pagination.md b/rest/execution/pagination.md new file mode 100644 index 0000000..fc4a22c --- /dev/null +++ b/rest/execution/pagination.md @@ -0,0 +1,27 @@ +# Pagination +A collection resource **SHOULD** provide the [`first`, `last`, `next` and `prev` link](https://tools.ietf.org/html/rfc5988#section-6.2.2)s for navigation within the collection. + +#### Example +The Collection of Orders using the collection navigation link and `offset` and `limit` query parameters: + + +```json +{ + "_links": { + "self": { "href": "/orders?offset=100&limit=10" }, + "prev": { "href": "/orders?offset=90&limit=10" }, + "next": { "href": "/orders?offset=110&limit=10" }, + "first": { "href": "/orders?limit=10" }, + "last": { "href": "/orders?offset=900&limit=10" } + }, + "total_count": 910, + "_embedded": { + "order": [ + { ... }, + { ... }, + + ... + ] + } +} +``` diff --git a/rest/execution/query-requests-with-large-inputs.md b/rest/execution/query-requests-with-large-inputs.md new file mode 100644 index 0000000..6d6bb87 --- /dev/null +++ b/rest/execution/query-requests-with-large-inputs.md @@ -0,0 +1,17 @@ +# Query Requests with Large Inputs +While HTTP doesn't impose any limit on the length of a URI, some implementation of server or client might have difficulties handling long URIs (usually URIs with many or large query parameters). + +Every endpoint with such a URI **MUST** use the HTTP **POST** Request Method and send the query string in HTTP Request Message body using the `application/x-www-form-urlencoded` media type. + + +#### Example + +``` +POST /orders HTTP/1.1 +Content-Type: application/x-www-form-urlencoded + +search=attributes&color=white&size=56&... +``` + + +> _NOTE: Since this operation is safe and idempotent, using the POST method violates the HTTP protocol semantics and results in loss of cache-ability._ diff --git a/rest/execution/rate-limiting.md b/rest/execution/rate-limiting.md new file mode 100644 index 0000000..3d96593 --- /dev/null +++ b/rest/execution/rate-limiting.md @@ -0,0 +1,63 @@ +# Rate Limiting +The API rate limiting is provided by the selected adidas API management platform – Mashery. + +Rate limit information is provided in the for of HTTP headers. There are two types of rate limits: **Quota** and **Throttle**. The quota is a limit enforced per a longer period (typically a day). The throttle is the limit of calls per second. + +## Quota Limit +The limit on the number of calls per a period (day). The default quota limit is 5000 calls per day. + +#### Example +Example response to a request over the quota limit: + +``` +HTTP/1.1 403 Forbidden +Content-Type: application/problem+json + +X-Error-Detail-Header: Account Over Rate Limit +X-Mashery-Error-Code: ERR_403_DEVELOPER_OVER_RATE + +{ + "title": "Rate Limit Exceeded", + "detail": "Account Over Rate Limit" +} + +``` + +## Throttle Limit +The limit on the number of calls per second. The default throttle limit is two calls per second. + +#### Example +Example response to a request over the throttle limit: + +``` +HTTP/1.1 403 Forbidden +Content-Type: application/problem+json + +Retry-After: 1 +X-Error-Detail-Header: Account Over Queries Per Second Limit +X-Mashery-Error-Code: ERR_403_DEVELOPER_OVER_QPS + +{ + "title": "Quota Limit Exceeded", + "detail": "Account Over Queries Per Second Limit" +} +``` + +> NOTE: The `Retry-After` gives a hint how long before the same request should be repeated (in seconds). + + +## Detail Information +By default, the headers do not contain details about the current usage and quotas. The default can be changed in the API management. + +#### Example +A successful response with the details about throttle (`X-Plan-QPS`) and quota (`X-Plan-Quota`) rate limits: + +``` +HTTP/1.1 200 OK + +X-Plan-QPS-Allotted: 10 +X-Plan-QPS-Current: 1 +X-Plan-Quota-Allotted: 1000 +X-Plan-Quota-Current: 2 +X-Plan-Quota-Reset: Tuesday, June 6, 2017 12:00:00 AM GMT +``` diff --git a/execution/search-requests.md b/rest/execution/search-requests.md similarity index 100% rename from execution/search-requests.md rename to rest/execution/search-requests.md diff --git a/rest/execution/security.md b/rest/execution/security.md new file mode 100644 index 0000000..e69de29 diff --git a/rest/execution/testing-enviroments.md b/rest/execution/testing-enviroments.md new file mode 100644 index 0000000..f51c49a --- /dev/null +++ b/rest/execution/testing-enviroments.md @@ -0,0 +1,3 @@ +# Testing Environments +Every API implementation **SHOULD** aim to provide a consistent, seamless way to create **test accounts** and access **test fixtures** to facilitate the development of API client applications. + diff --git a/rest/guides/README.md b/rest/guides/README.md new file mode 100644 index 0000000..bf7dfc5 --- /dev/null +++ b/rest/guides/README.md @@ -0,0 +1,9 @@ +# Guides +API-related guides: + +- [API Design Process](https://tools.adidas-group.com/confluence/display/EA/API+Design+Process) +- Migration of Legacy Services (SOAP) +- API Testing with Dredd +- Continuous Integration / Deployment / Delivery +- [Apiary](https://help.apiary.io/api_101/understanding-apiary/) +- API Management \ No newline at end of file diff --git a/rest/guides/api-testing-ci-environment.md b/rest/guides/api-testing-ci-environment.md new file mode 100644 index 0000000..49fd22e --- /dev/null +++ b/rest/guides/api-testing-ci-environment.md @@ -0,0 +1,101 @@ +# Jenkins CI Environment for Apiary Project + +This guide describes steps necessary for testing an API described in a swagger file with the [Dredd API Testing Framework](https://github.com/apiaryio/dredd) in a CI Environment (Jenkins, TeamCity). + +## Environment Prerequisites +The following must be available in the CI environment before testing: + +1. **Node.js** runtime MUST be available in the CI environment: + + ``` + $ node -v + v7.5.0 + ``` + +1. **Ruby** runtime MUST be available in the CI environment: + + ``` + $ ruby -v + ruby 2.4.0p0 (2016-12-24 revision 57164) [x86_64-darwin16] + ``` + +1. [**Dredd**](https://github.com/apiaryio/dredd) MUST be installed globally in the CI environment: + + ``` + $ npm install -g dredd --no-optional + ``` + + ``` + $ dredd --version + dredd v2.2.5 (Darwin 16.4.0; x64) + ``` + +1. [**Apiary CLI Tool**](https://help.apiary.io/tools/apiary-cli) MUST be installed globally in the CI environment: + + ``` + $ gem install apiaryio + ``` + + ``` + $ apiary version + 0.8.0 + ``` + +1. **Apiary API Key** MUST be set in the CI Environment environment variables: + + ``` + $ export APIARY_API_KEY=xyz + ``` + + To obtain an Apiary API key, head to (NOTE: You will need the "ALL" Scope) + +## Testing an API + + +### Test Run Prerequisites +To test an API within the CI environment provisioned as mentioned in the environment prerequisites, you will need the following: + +1. The name (subdomain) of API project at Apiary + + ``` + $ export APIARY_API_NAME=bomapi3 + ``` + + > See [How to find the Apiary API name](https://help.apiary.io/faq/find-api-name/) for more details. + +1. A `swagger.yaml` file with the description of API being tested + + To fetch the swagger.yaml file from Apiary run the following command before the test: + + ``` + $ apiary fetch --api-name=$APIARY_API_NAME --output="swagger.yaml" + ``` + + The swagger document for Apiary project `bomapi3` was saved as local file `./swagger.yaml`. + + > See [Fetching Published Documentation](https://help.apiary.io/tools/apiary-cli/#fetching-published-documentation). + +1. The host (address) of the service being tested + + ``` + $ export API_HOST=http://deheremap7336.emea.adsint.biz:8004` + ``` + +### Running the Test + +With all of the above (`APIARY_API_KEY`, `APIARY_API_NAME`, `API_HOST`, set up and `swagger.yaml` file present in the current directory), run: + + +``` +$ dredd swagger.yaml $API_HOST -r apiary +``` + +> See [Dredd Command-line Interface](https://dredd.readthedocs.io/en/latest/usage-cli/). + +The Dredd will perform the tests and exits usually if the tests have passed. You can check the test result as with any other Unix tools with: + +``` +$ echo $? +``` + +Everything else but `0` should break the build. The test results will be visible in the CLI (log) as well as in Apiary. diff --git a/guides/complete-api-development.md b/rest/guides/complete-api-development.md similarity index 100% rename from guides/complete-api-development.md rename to rest/guides/complete-api-development.md diff --git a/message/README.md b/rest/message/README.md similarity index 100% rename from message/README.md rename to rest/message/README.md diff --git a/rest/message/content-negotiation.md b/rest/message/content-negotiation.md new file mode 100644 index 0000000..bd71338 --- /dev/null +++ b/rest/message/content-negotiation.md @@ -0,0 +1,28 @@ + +# Content Negotiation +Every API **MUST** implement and every API Consumer **MUST** use the [HTTP content negotiation](https://tools.ietf.org/html/rfc7231#section-3.4) where a representation of a resource is requested. + +> NOTE: The content negotiation plays the key role in evolving an API, **change management and versioning**. + +#### Example +A client is programmed to understand the `application/vnd.example.resource+json; version=2` message format semantics. The client requests a representation of the `/greeting` resource in desired the media type (including its version) from the server: + +``` +GET /greeting HTTP/1.1 +Accept: application/vnd.example.resource+json; version=2 +... +``` + +The server can provide only a newer version of the requested media type `version=2.1.3`. But since the newer version is backward compatible with the requested `version=2` (related: Changes & Versioning) it can satisfy the request and responds: + +``` +HTTP/1.1 200 OK +Content-Type: application/vnd.example.resource+json; version=2.1.3 +... +``` + +> NOTE: A server that doesn't have the requested representation media type available MUST respond with the HTTP Status Code **406 Not Acceptable**. +> +> NOTE: A server MAY have multiple choices available and MAY respond with the **300 Multiple Choices** response. In which case client SHOULD choose from the presented choices. +> +> You can read more about content negotiation at [MDN Content negotiation](https://developer.mozilla.org/en-US/docs/Web/HTTP/Content_negotiation). diff --git a/rest/message/error-reporting.md b/rest/message/error-reporting.md new file mode 100644 index 0000000..d43451b --- /dev/null +++ b/rest/message/error-reporting.md @@ -0,0 +1,120 @@ +# Problem Detail +The [`application/problem+json`](https://tools.ietf.org/html/rfc7807) (Problem Detail) **MUST** be used to communicate details about an error. + +Problem Detail is intended for use with the HTTP status codes 4xx and 5xx. Problem Detail **MUST NOT** be used with 2xx status code responses. + +At the minimum, any Problem Detail response **MUST** have the `title` and `detail` fields. + +#### Example + +```json +{ + "title": "Authentication required", + "detail": "Missing authentication credentials for the Greeting resource." +} +``` + +## Optional Fields +It **SHOULD** has the `type` field with the identifier of the error, besides it **MAY** have the `instance` field with the URI of the resource in question. If the Problem Detail response has the `status` field it **MUST** have the same value as HTTP Status code from of the response. + + +```json +{ + "type": "https://adidas-group.com/problems/scv/unauthorized", + "title": "Authentication required", + "detail": "Missing authentication credentials for the Greeting resource.", + "instance": "/greeting", + "status": 401 +} +``` + +> NOTE: The `type` field is an identifier, and as such it **MAY** be used to denote additional error codes. Keep in mind that the identifier should be a URI. + +## Additional Fields +If needed, the Problem Detail **MAY** include additional fields, refer to [RFC7807](https://tools.ietf.org/html/rfc7807) for details. + +## Validation Errors +When necessary, a Problem Detail response **MAY** include additional error details about the problems that have occurred. + +These additional errors **MUST** be under the `errors` and **MUST** follow the Problem Detail structure. + +#### Example + +Request: + +``` +POST /my-resource HTTP/1.1 +Content-Type: application/json + +{ + "age": -32, + "color": "cyan" +} +``` + +Response: + +``` +HTTP/1.1 400 Bad Request +Content-Type: application/problem+json +Content-Language: en + +{ + "type": "https://example.net/validation_error", + "title": "Your request parameters didn't validate.", + "instance": "/my-resource", + "status": 400, + + "errors": [ + { + "type": "https://example.net/invalid_params", + "instance": "/age", + "title": "Invalid Parameter", + "detail": "age must be a positive integer" + }, + { + "type": "https://example.net/invalid_params", + "instance": "/color", + "title": "Invalid Parameter", + "detail": "color must be 'green', 'red' or 'blue'" + } + ] +} +``` + + + +## Problem Detail and Content Negotiation +#### Example +A request is made to retrieve a resource representation: + +``` +GET /greeting HTTP/1.1 +Accept: application/hal+json +``` + +However, in order to make this request, the client needs to be authorized. Since the request is made without the authorization credentials the **401 Unauthorized** response is returned together with details using the `application/problem+json` media type: + +``` +HTTP/1.1 401 Unauthorized +Content-Type: application/problem+json +Content-Language: en + +{ + "type": "https://adidas-group.com/problems/scv/unauthorized", + "title": "Authentication required", + "detail": "Missing authentication credentials for the Greeting resource.", + "instance": "/greeting", + "status": 401 +} +``` + +## No Stack Traces or Server Logs +> _Problem details are not a debugging tool for the underlying implementation; rather, they are a way to expose greater detail about the HTTP interface itself._ +> +> _– [RFC7807](https://tools.ietf.org/html/rfc7807)_ + +A Problem Detail response **MUST NOT** contain a program stack trace or server log for debugging purposes. Instead, provide a `logref` field with reference to the particular server log. + +## Working with Problem Detail +There are a whole plethora of libraries working with Problem Detail, for example, see [Zalando / Problem](https://github.com/zalando/problem) (Java). diff --git a/rest/message/foreign-key-relations.md b/rest/message/foreign-key-relations.md new file mode 100644 index 0000000..6df2fe3 --- /dev/null +++ b/rest/message/foreign-key-relations.md @@ -0,0 +1,67 @@ +# Foreign Key Relations + +## Link or Embed Foreign Key Relation +When a resource representation includes relation with another (foreign) resource, the relation **MUST** be expressed as a link relation or embed the related resource. + +#### Example +Use: + +```json +{ + "_links": { + "author": { "href": "/users/john" } + ... + } + ... +} +``` + +or: + +```json +{ + ... + "_embedded": { + "author": { + "_links": { "self": "/users/john" }, + "name": "John Appleseed", + "email": "john@apple.com" + } + } +} +``` + +instead: + +```json +{ + ... + "authorHref": "/users/john" +} +``` + +## Nest Foreign Key Relation +If a foreign object has another identifier, but URI or the foreign object isn't a resource, the object **MUST** be nested. + +#### Example +Use: + +```json +{ + "author": { + "id": "1234", + "name": "John Appleseed", + "email": "john@apple.com" + } +} +``` + +instead: + +```json +{ + "authorId": "1234" +} +``` + +> NOTE: As a rule of thumb, in an HTTP message body, there SHOULD NOT be any field with trailing "_id," "_href," "_url" etc. in its name. diff --git a/rest/message/hal.md b/rest/message/hal.md new file mode 100644 index 0000000..553eb7d --- /dev/null +++ b/rest/message/hal.md @@ -0,0 +1,114 @@ +# HAL +The [`application/hal+json`](http://stateless.co/hal_specification.html) (HAL) **MUST** be used as the representation format of a resource. + +## Introduction to HAL +> _HAL is a simple format that gives a consistent and easy way to hyperlink between resources in your API._ + +This document is an informal introduction to the HAL media type. For more details see [HAL - Hypertext Application Language Specification](http://stateless.co/hal_specification.html). + +## Simple Document Example +The simplest Hal document looks like an empty JSON (it is an empty JSON!): + +```json +{ +} +``` + +A document representing a "Greeting" resource might look like: + +```json +{ + "message": "Hello World!", + "_links": { + "self": { + "href": "/greeting" + } + } +} +``` +The field `_links` has a special meaning in HAL. It denotes a list of link relations - a pair of a relation identifier and a link (URI). + +These link relations are used to express the relation of a resource with other resources. + +In our case the "Greeting" resource isn't related to other resources but itself, hence the `self` relation pointing to the Greeting resource. + +> NOTE: It is **customary** for every resource representation to include the `self` link relation. + +> NOTE: The href **MUST** always be **relative path to the API root** (e.g. without the host and scheme). + +## Relation Example +A more complex document example could be an "Order" resource that has a related resource "Author" (a person who created the order. It might look like: + +```json +{ + "_links": { + "self": { + "href": "/orders/1234" + }, + "author": { + "href": "/users/john" + } + }, + "orderNumber": 1234, + "itemCount": 42, + "status": "pending" +} +``` + +## Embedding Example +Let's assume there is an "Orders" resource which is a collection of all orders from different authors. There is the relation between the Orders resource and possibly many Order resources. + +We could express this in the `_links` object using the `order` relation, but sometimes it is practical to "embed" (entirely or partially) related resources representations in the originating resource representation. For a scenario like this HAL offers the `_embedded` field. + +The `_embedded` field's object just contains the related resources HAL representations: + + +```json +{ + "_links": { + "self": { "href": "/orders" } + }, + "_embedded": { + "order": [ + { + "_links": { + "self": { "href": "/orders/1" } + }, + "orderNumber": "1", + "status": "pending" + }, + { + "_links": { + "self": { "href": "/orders/2" } + }, + "orderNumber": "2", + "status": "cancelled" + } + ] + } +} + +``` + +It is important to understand that embedded resource representation might be only **partial** and might also contain their own embedded resources. + +The embedded resource representation should be used as a **convenience** function (e.g. to reduce the initial number of calls needed at application launch). + +Where a full and up-to-date representation of a resource is needed the link relation should exercise the affordance (e.g. `GET /orders/2`). + +#### Real-world Examples + +Some APIs using HAL: + +- [Amazon AppStream REST API](http://docs.aws.amazon.com/appstream/latest/developerguide/appstream-api-rest.html) +- [FoxyCart](https://wiki.foxycart.com/v/2.0/start) +- [Clarify.io](http://docs.clarify.io/overview/) +- [University of Oxford / Mobile Oxford](http://api.m.ox.ac.uk/browser/#/) + + +## Working with HAL +Refer to the [extensive list of libraries that work with HAL](https://github.com/mikekelly/hal_specification/wiki/Libraries). + +### Spring Framework +Spring framework supports HAL out of the box. More info can be found in [Spring Documentation](https://spring.io/guides/gs/rest-hateoas/) +and [examples](https://github.com/spring-guides/gs-rest-hateoas). diff --git a/message/message-formats.md b/rest/message/message-formats.md similarity index 100% rename from message/message-formats.md rename to rest/message/message-formats.md diff --git a/miscellaneous.md b/rest/miscellaneous.md similarity index 100% rename from miscellaneous.md rename to rest/miscellaneous.md diff --git a/protocol/README.md b/rest/protocol/README.md similarity index 100% rename from protocol/README.md rename to rest/protocol/README.md diff --git a/protocol/http.md b/rest/protocol/http.md similarity index 100% rename from protocol/http.md rename to rest/protocol/http.md diff --git a/protocol/know-your-http.md b/rest/protocol/know-your-http.md similarity index 100% rename from protocol/know-your-http.md rename to rest/protocol/know-your-http.md diff --git a/rest/protocol/message.md b/rest/protocol/message.md new file mode 100644 index 0000000..e69de29 diff --git a/rest/protocol/protocol.md b/rest/protocol/protocol.md new file mode 100644 index 0000000..e69de29 diff --git a/rest/protocol/separate-concerns.md b/rest/protocol/separate-concerns.md new file mode 100644 index 0000000..f8380eb --- /dev/null +++ b/rest/protocol/separate-concerns.md @@ -0,0 +1,49 @@ +# Separate Concerns +Every API using HTTP/S API **MUST** precisely follow the concern separation of an HTTP message: + +1. A _resource identifier_–URI **MUST** be used to indicate **identity** only +1. _HTTP request method_ **MUST** be used to communicate the **action semantics** (intent and safety) +1. _HTTP response status_ code **MUST** be used to communicate the **information about the result** of the attempt to understand and satisfy the request +1. _HTTP message body_ **MUST** be used to transfer the **message content** +1. _HTTP message headers_ **MUST** be used to transfer the **metadata** about the message and its content +1. _URI query parameter_ **SHOULD NOT** be used to transfer metadata + + +#### Example 1 +The rule + +> A resource identifier–URI **MUST** be used to indicate identity only + +implies there **MUST NOT** be any information about the representation media type, version of the resource or anything else in the URI. + +For example, URIs `/greeting.json` or `/v2.1.3/greeting` are **illegal** as they are not used for identification of a resource only but they convey the information about representation format or version. URIs are not meant to carry any other information but the identifier of the resource. + + +#### Example 2 +The rule + +> HTTP message body MUST be used to transfer the message content + +Implies an HTTP GET request **MUST NOT** use HTTP message body to identify the resource. For example a request: + +``` +GET /greeting HTTP/1.1 +Content-Type: application/json +... + + +{ + "filter": "string" + "depth": 3 +} +``` + +is **not acceptable** (ignoring the fact that HTTP GET method shouldn't have the body). To express identity use URI and query parameters instead e.g. `/greeting?filter=string&depth=3`. + +--- + +> _Keep things simple while designing by separating the concerns between the different parts of the request and response cycle. Keeping simple rules here allows for greater focus on larger and harder problems._ +> +> _Requests and responses will be made to address a particular resource or collection. Use the path to indicate identity, the body to transfer the contents and headers to communicate metadata. Query params may be used as a means to pass header information also in edge cases, but headers are preferred as they are more flexible and can convey more diverse information._ +> +> _– [Heroku HTTP API Design Guide](https://geemus.gitbooks.io/http-api-design/content/en/foundations/separate-concerns.html)_ diff --git a/rest/protocol/tls.md b/rest/protocol/tls.md new file mode 100644 index 0000000..1dad60a --- /dev/null +++ b/rest/protocol/tls.md @@ -0,0 +1,4 @@ +# Transport Layer Security (TLS) +Every API **MUST** require secure connections with **TLS 1.2**. That is, an API using the HTTP protocol **MUST** use **HTTPS**. + +Any non-TLS requests **SHOULD** be ignored. In **HTTP** environments where this is not possible, a non-TLS request **SHOULD** result in the **403 Forbidden** response. \ No newline at end of file diff --git a/rest/protocol/use-appropriate-methods.md b/rest/protocol/use-appropriate-methods.md new file mode 100644 index 0000000..fc40a44 --- /dev/null +++ b/rest/protocol/use-appropriate-methods.md @@ -0,0 +1,45 @@ +# Use Appropriate Request Methods +Every API **MUST** use appropriate [HTTP request methods](https://github.com/for-GET/know-your-http-well/blob/master/methods.md) for every operation. + +Every API designer, implementer and consumer **MUST** understand the semantic of the HTTP METHOD she is using. + +At a minimum everyone **MUST** be familiar with the semantics of ["Common" HTTP Request Methods](https://github.com/for-GET/know-your-http-well/blob/master/methods.md#common): **DELETE**, **GET**, **HEAD**, **PUT**, **POST** and the [**PATCH** HTTP Request Method](https://tools.ietf.org/html/rfc5789#section-2). In addition, everyone **MUST** be aware which methods are **Safe**, **Idempotent** and **Cacheable**. + +### Safe Methods +As per HTTP specification, the **GET** and **HEAD** methods should be used only for retrieval of resource representations – and they do not update/delete the resource on the server. Both methods are said to be considered “safe“. +This allows user agents to represent other methods, such as POST, PUT and DELETE, in a special way, so that the user is made aware of the fact that a possibly unsafe action is being requested – and they can update/delete the resource on the server and so should be used carefully. + + +### Idempotent Methods +The term idempotent is used more comprehensively to describe an operation that will produce the same results if executed once or multiple times. This is a beneficial property in many situations, as it means that a transaction can be repeated or retried as often as necessary without causing unintended effects. With non-idempotent operations, the algorithm may have to keep track of whether the operation was already performed or not. +In HTTP specification, The methods **GET**, **HEAD**, **PUT** and **DELETE** are declared idempotent methods. Other methods OPTIONS and TRACE **SHOULD NOT** have side effects, so both are also inherently idempotent. + +### Cacheable Methods +Request methods are considered "cacheable" if it is possible and useful to answer a current client request with a stored response from a prior request. **GET** and **HEAD** are defined to be cacheable. + +--- + +#### Example 1 +> GET /user/new +> Description: Creates new user + +Using GET for unsafe non-idempotent operations is **not acceptable**. + +#### Example 2 +> POST /status +> Description: Updates the status of a user approval request (to “Approved” or “Rejected”) + +Using the POST method for a status update is **not acceptable** (use PATCH). + +#### Example 3 +> PUT /user +> Description: Creates a new user + +Using the PUT method for creating a new resource is **not acceptable** (use POST). + +#### Example 4 +> PUT: /user +> Description: Updates some user details + +Using the PUT method for a partial update is **not acceptable** (use PATCH). + diff --git a/rest/protocol/use-appropriate-status-codes.md b/rest/protocol/use-appropriate-status-codes.md new file mode 100644 index 0000000..6ba5f8f --- /dev/null +++ b/rest/protocol/use-appropriate-status-codes.md @@ -0,0 +1,44 @@ +# Use Appropriate Status Codes +Every API **MUST** use the appropriate [HTTP Status Codes](https://github.com/for-GET/know-your-http-well/blob/master/status-codes.md) to communicate the result of a request operation. + +Every API designer, implementer and consumer **MUST** understand the semantic of the HTTP Status Code she is using. + +At a minimum everyone **MUST** be familiar with the semantics of ["Common" HTTP Status Codes](https://github.com/for-GET/know-your-http-well/blob/master/status-codes.md#common). + +#### Example + +#### Use Codes 4xx or 5xx to Communicate Errors +A request: + +``` +GET /orders/1234 HTTP/1.1 +... +``` + +resulting in the **200 OK** response, when the requested resource (as identified by request URI) couldn't be found: + +``` +HTTP/1.1 200 OK +Content-Type: application/json +... + + +{ + "code": "NOT_FOUND_ERR_CODE" + "message" "Order 1234 wasn't found" +} +``` +is **not acceptable**. + +Instead the + +``` +HTTP/1.1 404 Not Found +... +``` + +should be returned. + +#### Recommended Reading +- [How to Think About HTTP Status Codes](https://www.mnot.net/blog/2017/05/11/status_codes) +