Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

capabilities documentation #296

Draft
wants to merge 54 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
54 commits
Select commit Hold shift + click to select a range
f46db94
Editorial Corrections in Getting Started
lisicase Jun 29, 2021
d90509a
Editorial Corrections in Batch Operations
lisicase Jun 29, 2021
e9b13d5
Editorial Changes to Intro to RSDL
lisicase Jun 29, 2021
5092166
Editorial Corrections to RSDL Semantics
lisicase Jun 29, 2021
613f935
Editorial Corrections to RAPID Pro Syntax
lisicase Jun 29, 2021
c5aeba4
Editorial Corrections to Features > Overview
lisicase Jun 29, 2021
11ed37c
Editorial Corrections to Features > Runtime Service Description
lisicase Jun 29, 2021
295f308
Editorial Corrections to Features > Actions and Functions
lisicase Jun 29, 2021
84d3b80
Adjusted capitalization
lisicase Jul 6, 2021
2f2c3df
Merge branch 'oasis-open:master' into master
lisicase Jul 12, 2021
71455b3
Drafted component to interactively make queries within documentation
lisicase Jul 21, 2021
97a98a9
Styled results to be a scrollable box
lisicase Jul 22, 2021
547025b
Created function to format queries so they work regardless of includi…
lisicase Jul 22, 2021
7d2a8f0
addressed bugs/errors related to requests on unmounted components and…
lisicase Jul 23, 2021
97e3833
added interactive querying for all examples
lisicase Jul 23, 2021
d11c005
improved accuracy and efficiency of reformatting queries
lisicase Jul 23, 2021
d7561a7
cleaned up code and added method comment
lisicase Jul 23, 2021
988b759
reformatted query and results
lisicase Jul 23, 2021
669b159
Merge branch 'main' into integrate-uri-builder
habbes Aug 4, 2021
cdff501
Configure odata uri tools for building as local npm packages
habbes Aug 9, 2021
5160f5c
Interactive Querying in Documentation (#275)
lisicase Aug 26, 2021
7576143
1st draft
chrisspre Sep 1, 2021
83d568d
updates to capabilitites document
chrisspre Sep 2, 2021
5b78109
Update rapid-pro-capabilities.md
ralfhandl Sep 2, 2021
0888c64
Update rapid-pro-capabilities.md
ralfhandl Sep 2, 2021
4532baf
Update rapid-pro-capabilities.md
ralfhandl Sep 2, 2021
c6d60d8
Update rapid-pro-capabilities.md
ralfhandl Sep 2, 2021
d4a106e
include syntax highlighting
chrisspre Sep 3, 2021
552d52f
update filter abnf
chrisspre Sep 3, 2021
094f74c
Merge branch 'main' into chrispre-capabilities
chrisspre Sep 8, 2021
be9a9bc
adding more detail to expand/paging/count and extensipility
chrisspre Sep 8, 2021
49789c7
small formatting fixes
chrisspre Sep 9, 2021
b6f1431
Create capability-mapping.md
chrisspre Dec 9, 2021
bf0b894
Update and rename capability-mapping.md to rapid-capability-mapping.md
chrisspre Dec 9, 2021
dcad7a7
Update and rename rapid-capability-mapping.md to rapid-rsdl-capabilit…
chrisspre Dec 9, 2021
3deaedb
adding minimal expand capability
chrisspre Dec 9, 2021
e552401
Update rapid-rsdl-capability-mapping.md
chrisspre Dec 9, 2021
68ad6db
Rename rapid-rsdl-capability-mapping.md to mapping.md
chrisspre Dec 9, 2021
471331d
adding capability semantics
chrisspre Dec 9, 2021
8a29dcf
Merge branch 'main' into chrispre-capabilities
chrisspre Dec 9, 2021
068e905
fix browser only setting
chrisspre Dec 9, 2021
230b808
fix build
chrisspre Dec 10, 2021
d0bc868
deleted obsolete files from branch
chrisspre Dec 10, 2021
1fd839c
fix markdown rendering for json
chrisspre Dec 10, 2021
f7db280
Update docs/rsdl/rapid-rsdl-capabilities.md
chrisspre Dec 13, 2021
21363c0
Update docs/rsdl/rapid-rsdl-capabilities.md
chrisspre Dec 13, 2021
2d99e34
Update docs/rsdl/rapid-rsdl-capabilities.md
chrisspre Dec 13, 2021
fe93376
Update docs/rsdl/rapid-rsdl-capabilities.md
chrisspre Dec 13, 2021
cf7d345
Update docs/rsdl/rapid-rsdl-capabilities.md
chrisspre Dec 13, 2021
24cc57f
Update docs/rsdl/rapid-rsdl-capabilities.md
chrisspre Dec 13, 2021
2d00eb6
Update docs/rsdl/rapid-rsdl-capabilities.md
chrisspre Dec 13, 2021
d8ec19e
Update docs/rsdl/rapid-rsdl-capability-mapping.mdx
chrisspre Dec 13, 2021
2c163d5
Merge branch 'main' into chrispre-capabilities
ralfhandl Jun 30, 2022
ee52f47
Fixed broken links
ralfhandl Jun 30, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,17 +1,24 @@
{
"cSpell.words": [
"abnf",
"capability",
"CSDL",
"dotnet",
"endswith",
"eset",
"Insertable",
"jetsons",
"nuget",
"nupkg",
"odata",
"rapid",
"rsdl",
"sku",
"Spacely",
"startswith",
"svel",
"tools",
"writeonly",
"xunit"
],
"dotnet-test-explorer.testProjectPath": "**/*tests.@(csproj|vbproj|fsproj)"
Expand Down
337 changes: 337 additions & 0 deletions docs/rsdl/rapid-rsdl-capabilities.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,337 @@
---
id: rsdl-capabilities
title: Capabilities
sidebar_label: RSDL API Capabilities
---

# Path Centric Service Capabilities

The previous sections described how to define the format of the request and response bodies based on types and their relationships. These structures also imply which URL paths are valid in the service: starting with the service properties and following properties of the structured types. For example in the service below, `orders` is a service property which allows access via the `/orders` URL. Since an order has multiple order items via the `items` property, the URL `/orders/<order id>/items` and `/orders/<order id>/items/<item id>` are also a valid URLs.

Without further constraints this would allow a huge number of URLs that a service would need to support. And it is important not just to specify which paths are allowed, but also to specify different functionality and behaviors supported for different paths.

The following sections introduce the notion of paths and capabilities that the service provides per path.

## Example service

For the examples in the section of this document, we assume the following type definitions. This is a simplified service that provides a top level orders collection together with their (contained) order items. Each item references a SKU, that can be accessed via the top level entity set.

```rsdl
type Order {
key id: String
created: DateTime
status: OrderStatus
items: [OrderItem]
}

enum OrderStatus {
Open
Archived
Canceled
}

type OrderItem {
key id: String
sku: SKU
amount: Integer
}

type SKU {
key id: String
name: String
description: String
unitPrice: Decimal
}

service {
orders: [Order]
skus: [SKU]
}
```

The amount of potential URLs that the service may support is large - in larger services potentially unbounded. Just to name a few of the more important ones:

``` http
/skus, /skus/{id}, /orders, /orders/{id}, /orders/{id}/items, /orders/{id}/items/{id},
/orders/{id}/items/{id}/skus, /orders/{id}/items/{id}/skus/{id}, ...
```

The path-centric view in RSDL allows to enumerate the allowed requests and specify which query options are supported for these requests.

## HTTP capabilities
The first level of the above mentioned capabilities is to specify the path of the URL and the HTTP method, Here is a partial RSDL to demonstrate this.

``` rsdl
path /orders {
GET { ... }
POST { ... }
}

path /orders/{id} {
GET { ... }
PATCH { ... }
DELETE { ... }
}

path /orders/{id}/items {
GET { ... }
POST { ... }
}

path /orders/{id}/items/{id} {
GET { ... }
DELETE { ... }
}

path /skus {
GET { ... }
}

```
The effect of this is that for each declared `path` and HTTP method the service is expected to return data, in the form specified by the corresponding type. The service is free to respond with success messages for other combinations but the service guarantees to work for the ones listed.

Important to notice is that the paths after the `path` keyword are not literal paths but sort of templates. Many of the interesting paths in a REST service have path segments that are entity ids. This is indicated via the `{id}` syntax: the `id` in there is exactly the name of the key property.

The placeholders `...` are used to declare which query options are supported by the service. For example a GET capability lists that certain $filter options are allowed or that paging is supported via the $top, $skip options. More details in the next sections.

The specific capabilities that can be used in the HTTP capabilities section instead of the `...` in the example above can vary by HTTP method. Here is an overview

| | filter | expand | paging | count |
|--------|:--------------------:|:--------------------:|:--------------------:|:--------------------:|
| GET | &#x2713; | &#x2713; | &#x2713; | &#x2713; |
| POST | &#x2713;<sup>1</sup> | &#x2713;<sup>1</sup> | &#x2713;<sup>1</sup> | &#x2713;<sup>1</sup> |
| PATCH | &#x2713;<sup>1</sup> | &#x2713;<sup>1</sup> | &#x2713;<sup>1</sup> | &#x2713;<sup>1</sup> |
| PUT | &#x2713;<sup>1</sup> | &#x2713;<sup>1</sup> | &#x2713;<sup>1</sup> | &#x2713;<sup>1</sup> |
| DELETE | | | | |

[1] to shape the POST/PATCH/PUT response. Rarely used but supported<br/>
[2] deleting multiple items. Rarely used but supported<br/>
[!!TODO: check if filter segment on delete is allowed in RAPID ]

## Individual Query capabilities

### Filter capabilities

The filter capability allows to specify which property can be used in which filter expression. There is a vast amount of possible filter expressions (see [OData System Query Option `$filter`](https://docs.oasis-open.org/odata/odata/v4.01/odata-v4.01-part1-protocol.html#sec_SystemQueryOptionfilter)). Therefore, the filter capabilities allow to specify a few well-known but restrictive expressions or allow any expression.

The format for filter capabilities is a sequence of pairs of a so called operator group and a list of property names. An operator group is constraining the form of the expression allowed in the $filter system query option.

| operator group | comment |
|----------------|-----------------------------------------------------------------------------------------------------------------------|
| eq | `<property> eq <literal>` or <br/> `<property> in (<literal1>, <literal2>, ... ) ` |
| range | `<literal> le <property> and <property> le <literal>` <br/> or equivalent expressions with operators `ge`, `gt`, `lt` |
| ranges | a disjunction of `range` expressions |
| prefix | `startswith(<property>, <literal>)` |
| text | `<string op>(<property>, <literal>)`,<br/>where `<string op>` is one of `startswith`, `endswith`, `contains` |
| any | any expression including expressions combined with `not`, `and`, and `or` |

In RSDL this
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sentence looks incomplete


```rsdl
path /orders {
GET {
filter {
eq { id name description createdDate fulfillmentDate }
ranges { createdDate description }
prefix { name }
text { description }
}

filter {
eq except { description }
ranges { createdDate description }
prefix { name }
text { description }
}
Comment on lines +133 to +145
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Really two occurrences of filter {...}? Or should these be two separate examples?

}
}
```

### Expand capabilities

The expand capability allows to specify which properties can be used in `$expand` query parameter.

The format is a sequence of properties that can be expanded.

```rsdl
path /orders {
GET {
expand {
items
}
}
}
```

The expand capability introduces a nesting of capabilities since the type of the expandable property can itself be used in select, filter, and expand.

```rsdl


type Order {

}

capability Order defaultOrder {
filter {
eq { id name }
prefix { nam description }
range { createdDateTime }
}
expand {
items {
filter {
eq { id name }
prefix { name }
}
expand {
sku
}
}
}
paging
count
}

capability Order limitedOrder {
filter {
eq { id name }
}
}

path /orders {
GET {
defaultOrder
}
}

path /customers/{id}/orders {
GET {
limitedOrder
}
}
```

- `/order?$expand=items`
- `/order?$expand=items(expand=sku)`
- `/order?$expand=items(expand=sku; filter=id eq '100')`
- `/order?$expand=items(select=id; expand=sku; filter=id eq '100')`


### Paging capabilities

The paging capability allows to specify if a request returning a collection can specify $top and $skip query parameters.

```rsdl
path /orders {
GET {
paging
}
}
```

The paging capability has no parameters itself. If a service uses a different way to implement paging, please refer to the [extensibility](#extensibility) section below

The paging capability is typically seen in a GET capability but can also be nested in an expand capability.

### Count capabilities

The count capability allows to specify if a request returning a collection can specify $count query parameter.

```rsdl
path /orders {
GET {
count
}
}
```

## Extensibility

The RSDL API capabilities allow to specify custom capabilities, so called traits, for the service to implement that are outside the scope of the patterns known by the RSDL specification.

One example for these could be the handling of requests when throttling is needed, where the service responds with certain headers for requests that cross a throttling threshold. There are multiple established pattern (protocol) to implement this but it is not covered in RSDL directly. But it can be specified in RSDL as an extension and the service implementation can read it and configure the right behavior based on the traits in RSDL.

The individual trait is treated as simple opaque (meta-) data that is passed on the service in the form of a trait name and a list of key-value pairs. The implementation is then free to interpret the presence of the trait and the parameters as it sees fit.

```rsdl
path /orders {
GET {
traits {
longRunningOperation
topWithoutSkip
throttling { level: "premium\u12a4" }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are the values always strings, or can they also be arrays, objects, numbers, booleans, i.e. "embedded JSON"?

}
}
}
```


## Other path based characteristics

```rsdl
path /user/{id}/recentOrders {
# references an Order contained in /orders
targets: /orders
targets: unbound
# 'targets' ':' ( path / 'unbound' )
Comment on lines +275 to +277
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

targets sounds like plural: better use target?


GET { }
}

path /orders {
# top level entity set
GET { }

}

path /orders/{id}/items {
# containment navigation (informally an entity set)
GET { }

}
```




## Syntax

!! NOTE: incomplete

``` abnf
path-capability = "path" path "{"
[ get-capabilities ]
[ post-capabilities ]
[ patch-capabilities ]
[ delete-capabilities ]
"}"

query-capabilities = [ expand-capabilities ] /
[ filter-capabilities ] / [ select-capabilities ] /
[ paging-capabilities ] / [ count-capabilities ] /
Comment on lines +310 to +312
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Better move after delete-capabilities for "hierarchical reading".


get-capabilities = "GET" "{" [ query-capabilities ] "}"

post-capabilities = "POST" "{" "}"

patch-capabilities = "PATCH" "{" "}"

delete-capabilities = "DELETE" "{" "}"

expand-capabilities = "expand" ["{"
*( property-name "{" query-capabilities "}" )
"}"]

filter-capabilities = "filter" ["{" operator-filter "}"]
operator-filter = operator-group "{" *property-name "}"
operator-group = "eq" / "range" / "ranges" / "prefix" / "strings" / "any"

paging-capabilities = "paging" ["{" "}"]
count-capabilities = "count" ["{" "}"]

property-name = identifier
path = "`" *( "/" identifier ) "`"

```

Loading