Added REST API and protocol reference documentation.

This commit is contained in:
Jimmy Campbell 2019-02-25 18:26:55 -05:00
Родитель 9a10d4a7c2
Коммит 90ee8710ad
10 изменённых файлов: 1462 добавлений и 1 удалений

Просмотреть файл

@ -6,7 +6,24 @@ You can use this repo to ask questions or share feedback about the Azure App Con
Documentation: https://aka.ms/azconfig
# Contributing
## REST API Reference
The following reference pages are available to describe the Azure App Configuration API surface in detail.
**Resources**
* [Keys](./docs/REST/keys.md)
* [Key-Values](./docs/REST/kv.md)
* [Labels](./docs/REST/labels.md)
* [Locks](./docs/REST/locks.md)
* [Revisions](./docs/REST/revisions.md)
**Protocol**
* [Authentication](./docs/REST/authentication.md)
* [Consistency Model](./docs/REST/consistency.md)
* [Common Headers](./docs/REST/headers.md)
* [Throttling](./docs/REST/throttling.md)
## Contributing
This project welcomes contributions and suggestions. Most contributions require you to agree to a
Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us

291
docs/REST/authentication.md Normal file
Просмотреть файл

@ -0,0 +1,291 @@
# Authentication - REST API Reference
#
All HTTP requests must be authenticated using the **HMAC-SHA256** authentication scheme and transmitted over TLS.
*Prerequisites*:
- **Credential** - \<Access Key ID\>
- **Secret** - base64 decoded Access Key Value. ``base64_decode(<Access Key Value>)``
Provide each request with all HTTP headers required for Authentication. The minimum required are:
| Request Header | Description |
| --------------- | ------------ |
| **Host** | Internet host and port number. See section [3.2.2](https://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.2.2) |
| **Date** | Date and Time at which the request was originated. It can not be more than 15 min off from current GMT. The value is an HTTP-date, as described in section [3.3.1](https://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.3.1)
| **x-ms-date** | Same as ```Date``` above. It can be used instead when the agent can't directly access ```Date``` request header or a proxy modifies it. If ```x-ms-date``` and ```Date``` are both provided, ```x-ms-date``` takes precedence. |
| **x-ms-content-sha256** | base64 encoded SHA256 hash of the request body. It must be provided even of there is no body. ```base64_encode(SHA256(body))```|
| **Authorization** | Authentication information required by **HMAC-SHA256** scheme. Format and details are explained below. |
**Example:**
```
Host: example.azconfig.io
Date: Fri, 11 May 2018 18:48:36 GMT
x-ms-content-sha256: 47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=
Authorization: HMAC-SHA256 Credential=a4016f0fa8fb0ef2, SignedHeaders=Host;x-ms-date;x-ms-content-sha256, Signature=jMXmttaxBJ0NmLlFKLZUkI8jdFu/8yqcTYzbkI3DGdU=
```
#
#
# Authorization Header
#
**Syntax:**
``Authorization``: **HMAC-SHA256** ```Credential```=\<value\>, ```SignedHeaders```=\<value\>, ```Signature```=\<value\>
#
#
| Argument | Description |
| ------ | ------ |
| **HMAC-SHA256** | Authorization Scheme _(required)_ |
| **Credential** | The ID of the access key used to compute the Signature. _(required)_ |
| **SignedHeaders** | HTTP Request Headers added to the signature. _(required)_ |
| **Signature** | base64 encoded HMACSHA256 of **String-To-Sign**. _(required)_|
#
#
### Credential
ID of the access key used to compute the **Signature**.
#
### Signed Headers
Semicolon separated HTTP request header names required to sign the request. These HTTP headers must be correctly provided with the request as well. **Don't use whitespaces**.
**Required HTTP request headers**:
```Host```;```x-ms-content-sha256```;```x-ms-date```[or ```Date```]
Any other HTTP request headers can also be added to the signing. Just append them to the ```SignedHeaders``` argument.
**Example:**
Host;x-ms-content-sha256;x-ms-date;```Content-Type```;```Accept```
#
#
### Signature
Base64 encoded HMACSHA256 hash of the **String-To-Sign** using the access key identified by `Credential`.
```base64_encode(HMACSHA256(String-To-Sign, Secret))```
#
#
##### String-To-Sign
It represents canonical representation of the request:
_String-To-Sign=_
**HTTP_METHOD** + '\n' +
**path_and_query** + '\n' +
**signed_headers_values**
| Argument | Description |
| ------ | ------ |
| **HTTP_METHOD** | Uppercased HTTP method name used with the request. See [section 9](https://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html) |
|**path_and_query** | Concatenation of request absolute URI path and query string. See [section 3.3](https://tools.ietf.org/html/rfc3986#section-3.3).
| **signed_headers_values** | Semicolon separated values of all HTTP request headers listed in **SignedHeaders**. The format follows **SignedHeaders** semantic. |
**Example:**
```js
string-To-Sign=
"GET" + '\n' + // VERB
"/kv?fields=*" + '\n' + // path_and_query
"Fri, 11 May 2018 18:48:36 GMT;example.azconfig.io;47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=" // signed_headers_values
```
#
#
### **Errors**
#
#
```sh
HTTP/1.1 401 Unauthorized
WWW-Authenticate: HMAC-SHA256
```
**Reason:** Authorization request header with HMAC-SHA256 scheme is not provided.
**Solution:** Provide valid ```Authorization``` HTTP request header
#
#
#
```sh
HTTP/1.1 401 Unauthorized
WWW-Authenticate: HMAC-SHA256 error="invalid_token" error_description="The access token has expired"
```
**Reason:** ```Date``` or ```x-ms-date``` request header is more than 15 minutes off from the current GMT time.
**Solution:** Provide correct date and time
#
#
#
```sh
HTTP/1.1 401 Unauthorized
WWW-Authenticate: HMAC-SHA256 error="invalid_token" error_description="Invalid access token date"
```
**Reason:** Missing or invalid ```Date``` or ```x-ms-date``` request header
#
#
#
```sh
HTTP/1.1 401 Unauthorized
WWW-Authenticate: HMAC-SHA256 error="invalid_token" error_description="[Credential][SignedHeaders][Signature] is required"
```
**Reason:** Missing a required parameter from ```Authorization``` request header
#
#
#
```sh
HTTP/1.1 401 Unauthorized
WWW-Authenticate: HMAC-SHA256 error="invalid_token" error_description="Invalid Credential"
```
**Reason:** Provided [```Host```]/[Access Key ID] is not found.
**Solution:** Check the ```Credential``` parameter of the ```Authorization``` request header and make sure it is a valid Access Key ID. Make sure the ```Host``` header points to the registered account.
#
#
#
```sh
HTTP/1.1 401 Unauthorized
WWW-Authenticate: HMAC-SHA256 error="invalid_token" error_description="Invalid Signature"
```
**Reason:** The ```Signature``` provided doesn't match what the server expects.
**Solution:** Make sure the ```String-To-Sign``` is correct. Make sure the ```Secret``` is correct and properly used (base64 decoded prior to using). See **Examples** section.
#
#
#
```sh
HTTP/1.1 401 Unauthorized
WWW-Authenticate: HMAC-SHA256 error="invalid_token" error_description="Signed request header 'xxx' is not provided"
```
**Reason:** Missing request header required by ```SignedHeaders``` parameter in ```Authorization``` header.
**Solution:** Provide the required header with correct value.
#
#
#
```sh
HTTP/1.1 401 Unauthorized
WWW-Authenticate: HMAC-SHA256 error="invalid_token" error_description="XXX is required as a signed header"
```
**Reason:** Missing parameter in ```SignedHeaders```.
**Solution:** Check **Signed Headers** minimum requirements.
#
#
#
## Code snippets
### JavaScript
*Prerequisites*: [Crypto-JS](https://code.google.com/archive/p/crypto-js/)
```js
function signRequest(host,
method, // GET, PUT, POST, DELETE
url, // path+query
body, // request body (undefined of none)
credential, // access key id
secret) // access key value (base64 encoded)
{
var verb = method.toUpperCase();
var utcNow = new Date().toUTCString();
var contentHash = CryptoJS.SHA256(body).toString(CryptoJS.enc.Base64);
//
// SignedHeaders
var signedHeaders = "x-ms-date;host;x-ms-content-sha256"; // Semicolon separated header names
//
// String-To-Sign
var stringToSign =
verb + '\n' + // VERB
url + '\n' + // path_and_query
utcNow + ';' + host + ';' + contentHash; // Semicolon separated SignedHeaders values
//
// Signature
var signature = CryptoJS.HmacSHA256(stringToSign, CryptoJS.enc.Base64.parse(secret)).toString(CryptoJS.enc.Base64);
//
// Result request headers
return [
{ name: "x-ms-date", value: utcNow },
{ name: "x-ms-content-sha256", value: contentHash },
{ name: "Authorization", value: "HMAC-SHA256 Credential=" + credential + ", SignedHeaders=" + signedHeaders + ", Signature=" + signature }
];
}
```
### C#
```cs
using (var client = new HttpClient())
{
var request = new HttpRequestMessage()
{
RequestUri = new Uri("http://example.azconfig.io/kv"),
Method = HttpMethod.Get
};
//
// Sign the request
request.Sign(<Credential>, <Secret>);
await client.SendAsync(request);
}
static class HttpRequestMessageExtensions
{
public static HttpRequestMessage Sign(this HttpRequestMessage request, string credential, byte[] secret)
{
string host = request.RequestUri.Authority;
string verb = request.Method.ToString().ToUpper();
DateTimeOffset utcNow = DateTimeOffset.UtcNow;
string contentHash = Convert.ToBase64String(request.Content.ComputeSha256Hash());
//
// SignedHeaders
string signedHeaders = "date;host;x-ms-content-sha256"; // Semicolon separated header names
//
// String-To-Sign
var stringToSign = $"{verb}\n{request.RequestUri.PathAndQuery}\n{utcNow.ToString("r")};{host};{contentHash}";
//
// Signature
string signature;
using (var hmac = new HMACSHA256(secret))
{
signature = Convert.ToBase64String(hmac.ComputeHash(Encoding.ASCII.GetBytes(stringToSign)));
}
//
// Add headers
request.Headers.Date = utcNow;
request.Headers.Add("x-ms-content-sha256", contentHash);
request.Headers.Authorization = new AuthenticationHeaderValue("HMAC-SHA256", $"Credential={credential}, SignedHeaders={signedHeaders}, Signature={signature}");
return request;
}
}
static class HttpContentExtensions
{
public static byte[] ComputeSha256Hash(this HttpContent content)
{
using (var stream = new MemoryStream())
{
if (content != null)
{
content.CopyToAsync(stream).Wait();
stream.Seek(0, SeekOrigin.Begin);
}
using (var alg = SHA256.Create())
{
return alg.ComputeHash(stream.ToArray());
}
}
}
}
```

48
docs/REST/consistency.md Normal file
Просмотреть файл

@ -0,0 +1,48 @@
# Real-time Consistency - REST API Reference
#
**Problem:**
Due to the nature of some distributed systems **real-time** consistency between requests can't (or it's very hard) to be enforced implicitly. A solution is to allow protocol support in the form of mutliple **Synchronization Tokens**. Synchronization tokens are optional.
**Objectives:**
To guarantee **real-time** consistency between different client instances and requests.
**Implementation:**
Uses optional ``Sync-Token`` request/response headers.
Syntax:
```
Sync-Token: <id>=<value>;sn=<sn>
```
|Parameter||
| -- | -- |
| ```<id>``` | Token ID (opaque) |
| ```<value>``` | Token value (opaque). Allows base64 encoded string |
| ```<sn>``` | Token sequence number (version). Higher means newer version of the same token. Allows for better concurrency and client cachability. The client may choose to use only token's last version, since token versions are inclusive. Not required for requests. |
**Response:**
The service provides a ``Sync-Token`` header with each response.
```
Sync-Token: jtqGc1I4=MDoyOA==;sn=28
```
**Request:**
Any subsequent request is guaranteed **real-time** consistent response in relation to the provided ``Sync-Token``.
```
Sync-Token: <id>=<value>
```
If the ``Sync-Token`` header is omitted from the request, then it's possible for the service to respond with cached data during a short period of time (up to a few seconds), before it settles internally. This may cause inconsistent reads if changes have occurred immediately before reading.
**Mutiple Sync-Token**
The server MAY respond with multiple sync-tokens for a single request. To keep **real-time** consistency for the next request, the client MUST respond with all of the received sync-tokens. Per RFC, multiple header values must be comma separated.
```
Sync-Token: <token1-id>=<value>,<token2-id>=<value>
```

37
docs/REST/headers.md Normal file
Просмотреть файл

@ -0,0 +1,37 @@
# Headers - REST API Reference
#
## Request Headers
The following table describes common request headers used in Azure App Configuration.
| Header | Description | Example |
| -- | -- | -- |
| **Authorization** | Used to [authenticate](./authentication) a request to the service. See [section 14.8](https://tools.ietf.org/html/rfc2616#section-14.8) | `Authorization: HMAC-SHA256 Credential=<Credential>, SignedHeaders=Host;x-ms-date;x-ms-content-sha256, Signature=<Signature>` |
| **Accept** | Informs the server what media type the client will accept in an HTTP response. See [section 14.1](https://tools.ietf.org/html/rfc2616#section-14.1) | `Accept: application/vnd.microsoft.appconfig.kv+json;` |
| **Accept-Datetime** | Requests the server to return its content as a representation of its prior state. The value of this header is the requested datetime of that state. See [RFC 7089](https://tools.ietf.org/html/rfc7089#section-2.1.1) | `Accept-Datetime: Sat, 12 May 2018 02:10:00 GMT` |
| **Content-Type** | Contains the media-type of the content within the HTTP request body. See [section 14.17](https://tools.ietf.org/html/rfc2616#section-14.17) | `Content-Type: application/vnd.microsoft.appconfig.kv+json; charset=utf-8;` |
| **Date** | The datetime that the HTTP request was issued. This header is used in [authentication](./authentication). See [section 14.18](https://tools.ietf.org/html/rfc2616#section-14.18) | `Date: Fri, 11 May 2018 18:48:36 GMT` |
| **Host** | Specifies the tenant for which the request has been issued. This header is used in [authentication](./authentication). See [section 14.23](https://tools.ietf.org/html/rfc2616#section-14.23) | `Host: contoso.azconfig.io` |
| **If-Match** | Used to make an HTTP request conditional. This request should only succeed if the targetted resource's etag matches the value of this header. The '*' value matches any etag. See [section 14.24](https://tools.ietf.org/html/rfc2616#section-14.24) | `If-Match: "4f6dd610dd5e4deebc7fbaef685fb903"` |
| **If-None-Match** | Used to make an HTTP request conditional. This request should only succeed if the targetted resource's etag does not match the value of this header. The '*' value matches any etag. See [section 14.26](https://tools.ietf.org/html/rfc2616#section-14.26) | `If-None-Match: "4f6dd610dd5e4deebc7fbaef685fb903"` |
| **Sync-Token** | Used to enable real-time consistency during a sequence of requests. | `Sync-Token: jtqGc1I4=MDoyOA==;sn=28` |
| **x-ms-client-request-id** | A unique id provided by the client used to track a request's round-trip. | `x-ms-client-request-id: 00000000-0000-0000-0000-000000000000` |
| **x-ms-content-sha256** | A sha256 digest of the HTTP request body. This header is used in [authentication](./authentication). | `x-ms-content-sha256: 47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=` |
| **x-ms-date** | This header may be set and used in place of the `Date` header if the date header is unable to be accessed. This header is used in [authentication](./authentication). | `x-ms-date: Fri, 11 May 2018 18:48:36 GMT` |
| **x-ms-return-client-request-id** | Used in conjunction with the `x-ms-client-request-id` header. If the value of this header is 'true' then the server will be instructed to return the value of the `x-ms-client-request-id` request header. | `x-ms-return-client-request-id: true` |
## Response Headers
The server may include the following HTTP headers in its responses.
| Header | Description | Example |
| -- | -- | -- |
| **Content-Type** | Contains the media-type of the content within the HTTP response body. See [section 14.17](https://tools.ietf.org/html/rfc2616#section-14.17) | `Content-Type: application/vnd.microsoft.appconfig.kv+json; charset=utf-8;` |
| **ETag** | An opaque token representing the state of a given resource. Can be used in conditional operations. See [section 14.19](https://tools.ietf.org/html/rfc2616#section-14.19) | `ETag: "4f6dd610dd5e4deebc7fbaef685fb903"` |
| **Last-Modified** | Describes when the requested resource was last modified. Formatted as an [HTTP-Date](https://tools.ietf.org/html/rfc2616#section-3.3.1). See [section 14.29](https://tools.ietf.org/html/rfc2616#section-14.29) | `Last-Modified: Tue, 05 Dec 2017 02:41:26 GMT` |
| **Link** | Provides links to resources that are related to the response. This header is used for paging by using the _next_ link. See [RFC 5988](https://tools.ietf.org/html/rfc5988) | `Link: </kv?after={token}>; rel="next"` |
| **Memento-Datetime** | Indicates that the content contained in a response represents a prior state. The value of this header is the datetime of that state. See [RFC 7089](https://tools.ietf.org/html/rfc7089#section-2.1.1) | `Memento-Datetime: Sat, 12 May 2018 02:10:00 GMT` |
| **x-ms-retry-after** | Provides a suggested period for the client to wait before retrying a failed request. | `x-ms-retry-after: 10` |
| **x-ms-request-id** | A unique id generated by the server that is used to track the request within the service. | `x-ms-request-id: 00000000-0000-0000-0000-000000000000` |
| **WWW-Authenticate** | Used to challenge clients for authentication and provide a reason as to why an authentication attempt has failed. See [section 14.47](https://tools.ietf.org/html/rfc2616#section-14.47) | `WWW-Authenticate: HMAC-SHA256 error="invalid_token" error_description="Invalid Signature"` |

170
docs/REST/keys.md Normal file
Просмотреть файл

@ -0,0 +1,170 @@
# Keys - REST API Reference
#
**Represents Key resource**.
```
{
"name": [string] // Name of the key
}
```
Supports the following operations:
- List
For all operations ``name`` is an optional filter parameter. If ommited it implies **any** key.
#
#
*Prerequisites*:
All HTTP requests must be authenticated. See the [authentication](./authentication) section.
#
#
## List Keys
#
```
GET /keys HTTP/1.1
```
**Responses:**
```
HTTP/1.1 200 OK
Content-Type: application/vnd.microsoft.appconfig.keyset+json; charset=utf-8"
```
```sh
{
"items": [
{
"name": "{key-name}"
},
...
],
"@nextLink": "{relative uri}"
}
```
#
#
#
## Pagination
#
The result is paginated if the number of items returned exceeds the response limit. Follow the optional ``Link`` response headers and use ``rel="next"`` for navigation.
Alternatively the content provides a next link in the form of the ``@nextLink`` property.
```
GET /keys HTTP/1.1
```
**Response:**
```
HTTP/1.1 OK
Content-Type: application/vnd.microsoft.appconfig.keyset+json; charset=utf-8
Link: </keys?after={token}>; rel="next"
```
```
{
"items": [
...
],
"@nextLink": "{relative uri}"
}
```
#
#
#
## Filtering
#
Filtering by ```name``` is supported.
```
GET /keys?name={key-name}
```
**Supported filters**
|Key Name||
|--|--|
|```name``` is omitted or ```name=*```|Matches **any** key|
|```name=abc```|Matches a key named **abc**|
|```name=abc*```|Matches key names that start with **abc**|
|```name=*abc```|Matches key names that end with **abc**|
|```name=*abc*```|Matches key names that contains **abc**|
|```name=abc,xyz```|Matches key names **abc** or **xyz** (limited to 5 CSV)|
***Reserved characters***
```*```, ```\```, ```,```
If a reserved character is part of the value, then it must be escaped using ```\{Reserved Character}```. Non-reserved characters can also be escaped.
***Filter Validation***
In the case of a filter validation error, the response is HTTP ```400``` with error details:
```
HTTP/1.1 400 Bad Request
Content-Type: application/problem+json; charset=utf-8
```
```sh
{
"type": "https://azconfig.io/errors/invalid-argument",
"title": "Invalid request parameter 'name'",
"name": "name",
"detail": "name(2): Invalid character",
"status": 400
}
```
**Examples**
- All
```
GET /keys
```
- Key name starts with **abc**
```
GET /keys?name=**abc***
```
- Key name is either **abc** or **xyz**
```
GET /revisions?name=**abc,xyz**
```
#
#
#
## Request specific fields
#
Use the optional ``$select`` query string parameter and provide comma separated list of requested fields. If the ``$select`` parameter is ommited, the response contains the default set.
```
GET /keys?$select=name HTTP/1.1
```
#
#
#
## Time-Based Access
#
Obtain a representation of the result as it was at a past time. See section [2.1.1](https://tools.ietf.org/html/rfc7089#section-2.1)
```
GET /keys HTTP/1.1
Accept-Datetime: Sat, 12 May 2018 02:10:00 GMT
```
**Response:**
```
HTTP/1.1 200 OK
Content-Type: application/vnd.microsoft.appconfig.keyset+json"
Memento-Datetime: Sat, 12 May 2018 02:10:00 GMT
Link: </keys>; rel="original"
```
```
{
"items": [
....
]
}
```

384
docs/REST/kv.md Normal file
Просмотреть файл

@ -0,0 +1,384 @@
# Key-Value - REST API Reference
#
**Identity:**
Key-Value is a resource identified by unique combination of ``key`` + ``label``.
``label`` is optional. To explicitly reference a key-value without a label use "\0" (url encoded as ``%00``). See details for each operation.
**Operations:**
- Get
- List multiple
- Set
- Delete
#
#
*Prerequisites*:
All HTTP requests must be authenticated. See the [authentication](./authentication) section.
#
#
## Syntax
#
```sh
{
"etag": [string]
"key": [string]
"label": [string, optional]
"content_type": [string, optional]
"value": [string]
"last_modified": [datetime ISO 8601]
"locked": [boolean]
"tags": [object with string properties, optional]
}
```
#
#
## Get Key-Value
#
**Required:** ``{key}``
*Optional:* ``label`` - If ommited it implies a key-value without a label
```
GET /kv/{key}?label={label}
```
**Responses:**
```
HTTP/1.1 200 OK
Content-Type: application/vnd.microsoft.appconfig.kv+json; charset=utf-8;
Last-Modified: Tue, 05 Dec 2017 02:41:26 GMT
ETag: "4f6dd610dd5e4deebc7fbaef685fb903"
```
```sh
{
"etag": "4f6dd610dd5e4deebc7fbaef685fb903",
"key": "{key}",
"label": "{label}",
"content_type": null,
"value": "example value",
"last_modified": "2017-12-05T02:41:26+00:00",
"locked": "false",
"tags": {
"t1": "value1",
"t2": "value2"
}
}
```
#
#
**If it doesn't exist**
```
HTTP/1.1 404 Not Found
```
#
#
## Get (Conditionally)
To improve client caching, use ``If-Match`` or ``If-None-Match`` request headers. The ``etag`` argument is part of the key representation. See [Sec 14.24](https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html)
**Get only if the current representation doesn't match the specified ``etag``**
```
GET /kv/{key} HTTP/1.1
Accept: application/vnd.microsoft.appconfig.kv+json;
If-None-Match: "{etag}"
```
**Responses:**
```
HTTP/1.1 304 NotModified
```
or
```
HTTP/1.1 200 OK
```
#
#
#
## List Key-Values
See **Filtering** for additional options
#
*Optional:* ``key`` - if not specified it implies **any** key.
*Optional:* ``label`` - if not specified it implies **any** label.
```
GET /kv?label=* HTTP/1.1
```
**Response:**
```
HTTP/1.1 200 OK
Content-Type: application/vnd.microsoft.appconfig.kvset+json; charset=utf-8
```
#
#
#
## Pagination
#
The result is paginated if the number of items returned exceeds the response limit. Follow the optional ``Link`` response headers and use ``rel="next"`` for navigation.
Alternatively the content provides a next link in form of the ``@nextLink`` property.
```
GET /kv HTTP/1.1
```
**Response:**
```
HTTP/1.1 200 OK
Content-Type: application/vnd.microsoft.appconfig.kvs+json; charset=utf-8
Link: </kv?after={token}>; rel="next"
```
```
{
"items": [
...
],
"@nextLink": "{relative uri}"
}
```
#
#
#
## Filtering
#
A combination of ```key``` and ```label``` filtering is supported.
Use the optional ```key``` and ```label``` query string parameters.
```
GET /kv?key={key}&label={label}
```
**Supported filters**
|Key||
|--|--|
|```key``` is omitted or ```key=*```|Matches **any** key|
|```key=abc```|Matches a key named **abc**|
|```key=abc*```|Matches keys names that start with **abc**|
|```key=*abc```|Matches keys names that end with **abc**|
|```key=*abc*```|Matches keys names that contain **abc**|
|```key=abc,xyz```|Matche keys names **abc** or **xyz** (limited to 5 CSV)|
|Label||
|--|--|
|```label``` is omitted or ```label=*```|Matches **any** label|
|```label=%00```|Matches KV without label|
|```label=prod```|Matches the label **prod**|
|```label=prod*```|Matches labels that start with **prod**|
|```label=*prod```|Matches labels that end with **prod**|
|```label=*prod*```|Matches labels that contain **prod**|
|```label=prod,test```|Matches labels **prod** or **test** (limited to 5 CSV)|
***Reserved characters***
```*```, ```\```, ```,```
If a reserved character is part of the value, then it must be escaped using ```\{Reserved Character}```. Non-reserved characters can also be escaped.
***Filter Validation***
In the case of a filter validation error, the response is HTTP ```400``` with error details:
```
HTTP/1.1 400 Bad Request
Content-Type: application/problem+json; charset=utf-8
```
```sh
{
"type": "https://azconfig.io/errors/invalid-argument",
"title": "Invalid request parameter '{filter}'",
"name": "{filter}",
"detail": "{filter}(2): Invalid character",
"status": 400
}
```
**Examples**
- All
```
GET /kv
```
- Key name starts with **abc** and include all labels
```
GET /kv?key=**abc***
```
- Key name is either **abc** or **xyz** and include all labels that contain **prod**
```
GET /kv?key=**abc,xyz**&label=\***prod**\*
```
#
#
#
## Request specific fields
#
Use the optional ``$select`` query string parameter and provide comma separated list of requested fields. If the ``$select`` parameter is ommited, the response contains the default set.
```
GET /kv?$select=key,value HTTP/1.1
```
#
#
#
## Time-Based Access
#
Obtain a representation of the result as it was at a past time. See section [2.1.1](https://tools.ietf.org/html/rfc7089#section-2.1). Pagination is still supported as defined above.
```
GET /kv HTTP/1.1
Accept-Datetime: Sat, 12 May 2018 02:10:00 GMT
```
**Response:**
```
HTTP/1.1 200 OK
Content-Type: application/vnd.microsoft.appconfig.kvset+json"
Memento-Datetime: Sat, 12 May 2018 02:10:00 GMT
Link: </kv>; rel="original"
```
```
{
"items": [
....
]
}
```
#
#
#
## Set Key
#
**Required:** ``{key}``
*Optional:* ``label`` - if not specified or label=%00 it implies KV without label.
```
PUT /kv/{key}?label={label} HTTP/1.1
Content-Type: application/vnd.microsoft.appconfig.kv+json
```
```sh
{
"value": "example value", // optional
"content_type": "user defined", // optional
"tags": { // optional
"tag1": "value1",
"tag2": "value2",
}
}
```
**Responses:**
```
HTTP/1.1 200 OK
Content-Type: application/vnd.microsoft.appconfig.kv+json; charset=utf-8
Last-Modified: Tue, 05 Dec 2017 02:41:26 GMT
ETag: "4f6dd610dd5e4deebc7fbaef685fb903"
```
```sh
{
"etag": "4f6dd610dd5e4deebc7fbaef685fb903",
"key": "{key}",
"label": "{label}",
"content_type": "user defined",
"value": "example value",
"last_modified": "2017-12-05T02:41:26.4874615+00:00",
"tags": {
"tag1": "value1",
"tag2": "value2",
}
}
```
#
#
**If the item is locked**
```
HTTP/1.1 409 Conflict
Content-Type: application/problem+json; charset="utf-8"
```
```
{
"type": "https://azconfig.io/errors/key-locked"
"title": "Modifing key '{key}' is not allowed",
"name": "{key}",
"detail": "The key is read-only. To allow modification unlock it first.",
"status": "409"
}
```
#
#
# Set Key (Conditionally)
To prevent race conditions, use ``If-Match`` or ``If-None-Match`` request headers. The ``etag`` argument is part of the key representation.
If ``If-Match`` or ``If-None-Match`` are omitted, the operation will be unconditional.
**Update only if the current representation matches the specified ``etag``**
```
PUT /kv/{key}?label={label} HTTP/1.1
Content-Type: application/vnd.microsoft.appconfig.kv+json
If-Match: "4f6dd610dd5e4deebc7fbaef685fb903"
```
**Update only if the current representation doesn't match the specified ``etag``**
```
PUT /kv/{key}?label={label} HTTP/1.1
Content-Type: application/vnd.microsoft.appconfig.kv+json;
If-None-Match: "4f6dd610dd5e4deebc7fbaef685fb903"
```
**Update if any representation exist**
```
PUT /kv/{key}?label={label} HTTP/1.1
Content-Type: application/vnd.microsoft.appconfig.kv+json;
If-Match: "*"
```
**Add only if representation doesn't exist**
```
PUT /kv/{key}?label={label} HTTP/1.1
Content-Type: application/vnd.microsoft.appconfig.kv+json
If-None-Match: "*"
```
#
#
**Responses**
```
HTTP/1.1 200 OK
Content-Type: application/vnd.microsoft.appconfig.kv+json; charset=utf-8
...
```
or
```
HTTP/1.1 412 PreconditionFailed
```
#
#
#
# Delete
#
**Required:** ``{key}``
*Optional:* ``{label}`` - if not specified or label=%00 it implies KV without label.
```
DELETE /kv/{key}?label={label} HTTP/1.1
```
**Response:**
Return the deleted key-value or none if didn't exist.
```
HTTP/1.1 200 OK
Content-Type: application/vnd.microsoft.appconfig.kv+json; charset=utf-8
...
```
or
```
HTTP/1.1 204 No Content
```
#
#
# Delete Key (Conditionally)
Similar to **Set Key (Conditionally)**

171
docs/REST/labels.md Normal file
Просмотреть файл

@ -0,0 +1,171 @@
# Labels - REST API Reference
#
**Represents Label resource**.
```
{
"name": [string] // Name of the label
}
```
Supports the following operations:
- List
For all operations ``name`` is an optional filter parameter. If ommited it implies **any** label.
#
#
*Prerequisites*:
All HTTP requests must be authenticated. See the [authentication](./authentication) section.
#
#
## List Labels
#
```
GET /labels HTTP/1.1
```
**Responses:**
```
HTTP/1.1 200 OK
Content-Type: application/vnd.microsoft.appconfig.labelset+json; charset=utf-8"
```
```sh
{
"items": [
{
"name": "{label-name}"
},
...
],
"@nextLink": "{relative uri}"
}
```
#
#
#
## Pagination
#
The result is paginated if the number of items returned exceeds the response limit. Follow the optional ``Link`` response headers and use ``rel="next"`` for navigation.
Alternatively the content provides a next link in form of the ``@nextLink`` property.
```
GET /labels HTTP/1.1
```
**Response:**
```
HTTP/1.1 OK
Content-Type: application/vnd.microsoft.appconfig.labelset+json; charset=utf-8
Accept-Ranges: items
Link: </labels?after={token}>; rel="next"
```
```
{
"items": [
...
],
"@nextLink": "{relative uri}"
}
```
#
#
#
## Filtering
#
Filtering by ```name``` is supported.
```
GET /labels?name={label-name}
```
**Supported filters**
|Key Name||
|--|--|
|```name``` is omitted or ```name=*```|Matches **any** label|
|```name=abc```|Matches a label named **abc**|
|```name=abc*```|Matches label names that start with **abc**|
|```name=*abc```|Matches label names that end with **abc**|
|```name=*abc*```|Matches label names that contains **abc**|
|```name=abc,xyz```|Matches label names **abc** or **xyz** (limited to 5 CSV)|
***Reserved characters***
```*```, ```\```, ```,```
If a reserved character is part of the value, then it must be escaped using ```\{Reserved Character}```. Non-reserved characters can also be escaped.
***Filter Validation***
In case of a filter validation error, the response is HTTP ```400``` with error details:
```
HTTP/1.1 400 Bad Request
Content-Type: application/problem+json; charset=utf-8
```
```sh
{
"type": "https://azconfig.io/errors/invalid-argument",
"title": "Invalid request parameter 'name'",
"name": "name",
"detail": "name(2): Invalid character",
"status": 400
}
```
**Examples**
- All
```
GET /labels
```
- Label name starts with **abc**
```
GET /labels?name=**abc***
```
- Label name is either **abc** or **xyz**
```
GET /labels?name=**abc,xyz**
```
#
#
#
## Request specific fields
#
Use the optional ``$select`` query string parameter and provide comma separated list of requested fields. If the ``$select`` parameter is ommited, the response contains the default set.
```
GET /labels?$select=name HTTP/1.1
```
#
#
#
## Time-Based Access
#
Obtain a representation of the result as it was at a past time. See section [2.1.1](https://tools.ietf.org/html/rfc7089#section-2.1)
```
GET /labels HTTP/1.1
Accept-Datetime: Sat, 12 May 2018 02:10:00 GMT
```
**Response:**
```
HTTP/1.1 200 OK
Content-Type: application/vnd.microsoft.appconfig.labelset+json"
Memento-Datetime: Sat, 12 May 2018 02:10:00 GMT
Link: </labels>; rel="original"
```
```
{
"items": [
....
]
}
```

100
docs/REST/locks.md Normal file
Просмотреть файл

@ -0,0 +1,100 @@
# Lock Key-Value - REST API Reference
#
**Provides lock/unlock semantics for the key-value resource.**
Supports the following operations:
- Place lock
- Remove lock
If present, ``label`` must be an explcit label value (**not** a wildcard). For all operations it's an optional parameter. If ommited it implies no label.
#
#
*Prerequisites*:
All HTTP requests must be authenticated. See the [authentication](./authentication) section.
#
#
## Lock Key-Value
#
**Required:** ``{key}``
*Optional:* ``label``
```
PUT /locks/{key}?label={label} HTTP/1.1
```
**Responses:**
```
HTTP/1.1 200 OK
Content-Type: application/vnd.microsoft.appconfig.kv+json; charset=utf-8"
```
```sh
{
"etag": "4f6dd610dd5e4deebc7fbaef685fb903",
"key": "{key}",
"label": "{label}",
"content_type": null,
"value": "example value",
"created": "2017-12-05T02:41:26.4874615+00:00",
"locked": true,
"tags": []
}
```
#
#
**If the key-value doesn't exist**
```
HTTP/1.1 404 Not Found
```
#
#
#
## Unlock Key-Value
#
**Required:** ``{key}``
*Optional:* ``label``
```
DELETE /locks/{key}?label={label} HTTP/1.1
```
**Responses:**
```
HTTP/1.1 200 OK
Content-Type: application/vnd.microsoft.appconfig.kv+json; charset=utf-8"
```
```sh
{
"etag": "4f6dd610dd5e4deebc7fbaef685fb903",
"key": "{key}",
"label": "{label}",
"content_type": null,
"value": "example value",
"created": "2017-12-05T02:41:26.4874615+00:00",
"locked": true,
"tags": []
}
```
#
#
**If the key-value doesn't exist**
```
HTTP/1.1 404 Not Found
```
#
#
# Conditional Lock/Unlock
To prevent race conditions, use ``If-Match`` or ``If-None-Match`` request headers. The ``etag`` argument is part of the key representation.
If ``If-Match`` or ``If-None-Match`` are omitted, the operation will be unconditional.
**Apply operation only if the current key-value representation matches the specified ``etag``**
```
PUT|DELETE /locks/{key}?label={label} HTTP/1.1
If-Match: "4f6dd610dd5e4deebc7fbaef685fb903"
```
**Apply operation only if the current key-value representation exists, but doesn't match the specified ``etag``**
```
PUT|DELETE /kv/{key}?label={label} HTTP/1.1
If-None-Match: "4f6dd610dd5e4deebc7fbaef685fb903"
```

202
docs/REST/revisions.md Normal file
Просмотреть файл

@ -0,0 +1,202 @@
# Key-Value Revisions - REST API Reference
#
**Defines chronological/historical representation of key-value resource(s).**
Revisions eventually expire (default 7 days)
Supports the following operations:
- List
For all operations ``key`` is an optional parameter. If ommited it implies **any** key.
For all operations ``label`` is an optional parameter. If ommited it implies **any** label.
#
#
*Prerequisites*:
All HTTP requests must be authenticated. See the [authentication](./authentication) section.
#
#
## List Revisions
#
```
GET /revisions?label=* HTTP/1.1
```
**Responses:**
```
HTTP/1.1 200 OK
Content-Type: application/vnd.microsoft.appconfig.kvset+json; charset=utf-8"
Accept-Ranges: items
```
```sh
{
"items": [
{
"etag": "4f6dd610dd5e4deebc7fbaef685fb903",
"key": "{key}",
"label": "{label}",
"content_type": null,
"value": "example value",
"last_modified": "2017-12-05T02:41:26.4874615+00:00",
"tags": []
},
...
],
"@nextLink": "{relative uri}"
}
```
#
#
#
## Pagination
#
The result is paginated if the number of items returned exceeds the response limit. Follow the optional ``Link`` response header and use ``rel="next"`` for navigation.
Alternatively the content provides a next link in form of the ``@nextLink`` property.
```
GET /revisions HTTP/1.1
```
**Response:**
```
HTTP/1.1 OK
Content-Type: application/vnd.microsoft.appconfig.kvs+json; charset=utf-8
Accept-Ranges: items
Link: </revisions?after={token}>; rel="next"
```
```
{
"items": [
...
],
"@nextLink": "{relative uri}"
}
```
#
#
#
## List subset of revisions
#
Use ``Range`` request header. The response will contain ``Content-Range`` header.
If the server can't satisfy the requested range it will respond with HTTP ``416`` (RangeNotSatisfiable)
```
GET /revisions HTTP/1.1
Range: items=0-2
```
**Response**
```
HTTP/1.1 206 Partial Content
Content-Type: application/vnd.microsoft.appconfig.revs+json; charset=utf-8
Content-Range: items 0-2/80
```
#
#
#
## Filtering
#
A combination of ```key``` and ```label``` filtering is supported.
Use the optional ```key``` and ```label``` query string parameters.
```
GET /revisions?key={key}&label={label}
```
**Supported filters**
|Key||
|--|--|
|```key``` is omitted or ```key=*```|Matches **any** key|
|```key=abc```|Matches a key named **abc**|
|```key=abc*```|Matches keys names that start with **abc**|
|```key=*abc```|Matches keys names that end with **abc**|
|```key=*abc*```|Matches keys names that contain **abc**|
|```key=abc,xyz```|Matche keys names **abc** or **xyz** (limited to 5 CSV)|
|Label||
|--|--|
|```label``` is omitted or ```label=```|Matches entry without label|
|```label=*```|Matches **any** label|
|```label=prod```|Matches the label **prod**|
|```label=prod*```|Matches labels that start with **prod**|
|```label=*prod```|Matches labels that end with **prod**|
|```label=*prod*```|Matches labels that contain **prod**|
|```label=prod,test```|Matches labels **prod** or **test** (limited to 5 CSV)|
***Reserved characters***
```*```, ```\```, ```,```
If a reserved character is part of the value, then it must be escaped using ```\{Reserved Character}```. Non-reserved characters can also be escaped.
***Filter Validation***
In case of a filter validation error, the response is HTTP ```400``` with error details:
```
HTTP/1.1 400 Bad Request
Content-Type: application/problem+json; charset=utf-8
```
```sh
{
"type": "https://azconfig.io/errors/invalid-argument",
"title": "Invalid request parameter '{filter}'",
"name": "{filter}",
"detail": "{filter}(2): Invalid character",
"status": 400
}
```
**Examples**
- All
```
GET /revisions
```
- Items where key name starts with **abc**
```
GET /revisions?key=**abc***
```
- Items where key name is either **abc** or **xyz** and labels contain **prod**
```
GET /revisions?key=**abc,xyz**&label=\***prod**\*
```
#
#
#
## Request specific fields
#
Use the optional ``$select`` query string parameter and provide comma separated list of requested fields. If the ``$select`` parameter is ommited, the response contains the default set.
```
GET /revisions?$select=value,label,last_modified HTTP/1.1
```
#
#
#
## Time-Based Access
#
Obtain a representation of the result as it was at a past time. See section [2.1.1](https://tools.ietf.org/html/rfc7089#section-2.1)
```
GET /revisions HTTP/1.1
Accept-Datetime: Sat, 12 May 2018 02:10:00 GMT
```
**Response:**
```
HTTP/1.1 200 OK
Content-Type: application/vnd.microsoft.appconfig.revs+json"
Memento-Datetime: Sat, 12 May 2018 02:10:00 GMT
Link: </revisions>; rel="original"
```
```
{
"items": [
....
]
}
```

41
docs/REST/throttling.md Normal file
Просмотреть файл

@ -0,0 +1,41 @@
# Throttling - REST API Reference
#
Configuration stores have limits on the requests that they may serve. Any requests that exceeds an allotted quota for a configuration store will receive an HTTP 429 (Too Many Requests) response.
Throttling is divided into different quota policies:
**TotalRequests** - total amount of requests/sec
**TotalWrites** - total amount of write requests/second
**Bandwidth** - outbound data in bytes
## Handling Throttled Responses
When the rate limit for a given request type has been reached, the configuration store will respond to further requests of that type with a _429_ status code. The _429_ response will contain a _retry-after-ms_ header providing the client with a suggested wait time (in milliseconds) to allow the request quota to replinish.
```
HTTP/1.1 429 (Too Many Requests)
retry-after-ms: 10
Content-Type: application/problem+json; charset=utf-8
```
```sh
{
"type": "https://azconfig.io/errors/too-many-requests",
"title": "The amount of requests sent to the server have surpassed the assigned quota",
"policy": "TotalRequests" | "TotalWrites" | "Bandwidth",
"status": 429
}
```
In the above example, the client has exceeded its allowed requests per second and is advised to slow down and wait 10 milliseconds before attempting any further requests. Clients should consider progressive backoff as well.
# Other Retry
#
The service may identify situations other than throttling that need a client retry (ex: 503 Service Unavailable).
In all such cases, the ``retry-after-ms`` response header will be provided. To increase robustness, the client is advised to follow the suggested interval and perform a retry.
```
HTTP/1.1 503 Service Unavailable
retry-after-ms: 787
```