Skip to content

Commit

Permalink
Add Capabilities to RSDL (#441)
Browse files Browse the repository at this point in the history
* Initial commit
-add capabilities to abnf
-add new section on rsdl-capabilities

* -add section on paging
-add capabilities to abnf

* Add support for data modification capabilities
Add support for operation capabilities
Misc clean-up

* fixed ABNF syntax errors

* Update rsdl-testcases.yaml

* Add tools/rsdl/abnf to workspaces

* Allow "paths" anywhere multiple times

- add first test case for paths
-  VS Code tasks for ABNF in mono-repo

* Add initial set of test cases

* update prettier in settings.json.

* Merge Ralf's changes

* Extract ABNF: ignore CR characters in Markdown source

* Use LF as default line ending in repo to enable non-windows users to participate

See https://prettier.io/docs/en/options.html#end-of-line for explanation

* Fixed rule collectionRefProperty

* Fixed paths rule

* No CRLF

* Update .editorconfig

* Only contains default values after removing crlf

* Remove .prettierrc as it only contained default values

* Update docs/rsdl/rapid-rsdl-intro.md

* Update docs/rsdl/rapid-rsdl-paths.md

* Update rapid-rsdl-paths.md

* Update docs/rsdl/rapid-rsdl-paths.md

* Formatting

* Update docs/rsdl/rapid-rsdl-capabilities.md

Co-authored-by: Ralf Handl <[email protected]>

* Change Reference to Navigation
Fix Paths
Simplify Nullable types in grammar
Address other comments

* Improve abnf; add test cases.

* Apply fixes from 2023-7-26 TC discussion:
-Replace use of parens with curly braces for filter, expand, orderby
-Support appending cast segment to a single valued property segment

* Updated prose to use curly braces rather than parens (thanks for the catch ralf!)
Also, removed ability to mark a collection property as a key.

---------

Co-authored-by: Ralf Handl <[email protected]>
  • Loading branch information
mikepizzo and ralfhandl authored Jul 27, 2023
1 parent 5fe5038 commit bf9a8e4
Show file tree
Hide file tree
Showing 13 changed files with 2,487 additions and 504 deletions.
1 change: 1 addition & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
* text=auto eol=lf
*.abnf text eol=crlf
3 changes: 3 additions & 0 deletions docs/rapid-pro-operations.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,14 @@ sidebar_label: Actions and Functions

Although a pure REST service would perform operations through manipulating the state of resources,
we have found that many services require the ability to encapsulate complex processing logic into atomic operations.

Rather than requiring services to expose a separate endpoint for such business logic,
RAPID allows services to support Operations.

Operations are exposed as resources at the root of the service or "bound" to the resource on which they operate.

Operations bound to a resource are invoked by appending a segment containing the name of the operation to the URL of the resource.

The name of the operation must not conflict with the name of any properties or other operations bound to that
resource.

Expand Down
4 changes: 2 additions & 2 deletions docs/rapid-pro.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,12 @@ import Request from '../website/src/components/documentation-queries/Request.js'
-->

RAPID is a simple profile for building well-designed APIs that can scale to the level of functionality required for any situation.

By following RAPID conventions, services are able to leverage common libraries and tools,
and can share their information in a discoverable and interoperable way.

Because the RAPID profile is based on, and compatible with, the industry standard OData protocol,
services following RAPID conventions know that, as their needs grow,
there are well defined conventions and semantics that allow them to seamlessly and incrementally grow without having to rewrite as their needs evolve.
services following RAPID conventions know that, as their needs grow, there are well defined conventions and semantics that allow them to seamlessly and incrementally grow without having to rewrite as their needs evolve.

## What makes a RAPID service?

Expand Down
162 changes: 149 additions & 13 deletions docs/rsdl/rapid-rsdl-abnf.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,7 @@ id: rsdl-abnf
title: RSDL ABNF
---

# RAPID Pro Syntax

> DRAFT
> March 2021
# RAPID Schema Definition Language (RSDL) Syntax

## Overview

Expand All @@ -16,7 +13,7 @@ Note: to increase readability of the grammar, whitespace is not reflected

## Syntax rules

- [RAPID Pro Syntax](#rapid-pro-syntax)
- [RAPID Schema Definition Language (RSDL) Syntax](<#rapid-schema-definition-language-(RSDL)-Syntax>)
- [Overview](#overview)
- [Syntax rules](#syntax-rules)
- [Model](#model)
Expand All @@ -25,18 +22,22 @@ Note: to increase readability of the grammar, whitespace is not reflected
- [Type Definition](#type-definition)
- [Service](#service)
- [Annotations](#annotations)
- [Model Capabilities](#model-capabilities)
- [Paths](#paths)
- [Path Capabilities](#path-capabilities)
- [Capability Elements](#capability-elements)
- [Core Syntax Elements](#core-syntax-elements)

### Model

```ABNF
model = OWS [ namespace RWS ] *include [ modelElement *( RWS modelElement ) ] OWS
model = OWS [ namespace RWS ] *include [ modelElement *( RWS modelElement ) ] [ OWS service ] [ OWS paths ] OWS
namespace = %s"namespace" RWS qualifiedName
include = %s"include" RWS DQUOTE 1*CHAR DQUOTE RWS %s"as" RWS identifier RWS
modelElement = ( structuredType / enumType / typeDefinition / service )
modelElement = ( structuredType / enumType / typeDefinition )
```

### Structured Type
Expand All @@ -46,11 +47,20 @@ structuredType = annotations [ %s"abstract" RWS ] %s"type" RWS identifier
structuredTypeMember = property / operation ; property, action, or function
property = annotations [propertyModifier RWS] identifier OWS ":" OWS typeReference
property = singlePropertyDefinition [ OWS (primitivePropertyCapabilities / singleNavigationCapabilities) ]
/ collectionPropertyDefinition [ OWS ( collectionCapabilities / collectionNavigationCapabilities) ]
singlePropertyDefinition = annotations [propertyModifier RWS] identifier OWS ":" OWS singleTypeReference
collectionPropertyDefinition = annotations identifier OWS ":" OWS collectionTypeReference
propertyModifier = %s"key"
typeReference = typeName [ "?" ] / "[" typeName [ "?" ] "]"
singleTypeReference = typeName [ "?" ]
collectionTypeReference = "[" typeName [ "?" ] "]"
typeReference = singleTypeReference / collectionTypeReference
typeName = builtInType / edmType / qualifiedName
Expand All @@ -69,6 +79,7 @@ edmType = %s"Edm" "." identifier
operation = annotations operationKind RWS identifier OWS
"(" OWS [ parameter *( OWS "," OWS parameter) OWS ] ")"
[ OWS ":" OWS annotations typeReference ]
[ separator collectionNavCapabilities ]
operationKind = %s"action" / %s"function"
Expand Down Expand Up @@ -96,9 +107,9 @@ service = annotations %s"service" [ RWS identifier ] OWS "{" OWS se
serviceMember = annotations ( entitySet / singleton / serviceOperation )
entitySet = identifier OWS ":" OWS "[" qualifiedName "]"
entitySet = identifier OWS ":" OWS "[" qualifiedName "]" [ OWS collectionNavigationCapabilities ]
singleton = identifier OWS ":" OWS qualifiedName
singleton = identifier OWS ":" OWS qualifiedName [ OWS singleNavigationCapabilities ]
serviceOperation = operationKind RWS identifier
OWS "(" OWS [ parameter *(OWS "," OWS parameter) OWS ] ")"
Expand All @@ -117,18 +128,139 @@ annotationValue = %s"true"
/ %s"null"
/ number
/ DQUOTE *CHAR DQUOTE
/ "[" OWS [ annotationValue *( ( OWS "," OWS / RWS ) annotationValue ) OWS [ "," OWS ] ] "]"
/ "{" OWS [ annotationProperty *( ( OWS "," OWS /RWS ) annotationProperty ) OWS [ "," OWS ] ] "}"
/ "[" OWS [ annotationValue *( separator annotationValue ) OWS [ "," OWS ] ] "]"
/ "{" OWS [ annotationProperty *( separator annotationProperty ) OWS [ "," OWS ] ] "}"
/ "." *( "/" identifier )
annotationProperty = propertyName OWS ":" OWS annotationValue
propertyName = identifier / DQUOTE 1*CHAR DQUOTE / "@" qualifiedName [ "#" identifier ]
```

### Model Capabilities

```ABNF
primitivePropertyCapability = "filterable" [ OWS filterOptions ] / "orderable" [ OWS orderByDirection ]
primitivePropertyCapabilities = "{" OWS [ primitivePropertyCapability *( separator primitivePropertyCapability )] OWS "}"
singleNavigationCapability = ("READ" / "UPDATE" / "REPLACE") [ OWS navCapabilities ] / "DELETE" noOptions
singleNavigationCapabilities = "{" OWS [ singleNavigationCapability *( separator singleNavigationCapability )] OWS "}"
collectionNavigationCapability = "DELETE" OWS noOptions
/ "LIST" [ OWS collectionNavCapabilities ]
/ ("READ" / "CREATE" / "REPLACE" / "UPDATE") [ OWS navCapabilities ]
collectionNavigationCapabilities = "{" OWS [ collectionNavigationCapability *( separator collectionNavigationCapability )] OWS "}"
```

### Paths

```ABNF
paths = %s"paths" OWS "{" *( OWS "/" path ) OWS "}"
path = propertySegment "/" keySegment [ pathSegment / ( RWS singleNavPathCapabilities ) ]
/ serviceOperationSegment "/" keySegment [ pathSegment / ( RWS singleNavPathCapabilities ) ]
/ serviceOperationSegment [ pathSegment / ( RWS capabilities ) ]
/ castSegment [ pathSegment / ( RWS capabilities ) ]
/ propertySegment [ pathSegment / ( RWS capabilities ) ]
propertySegment = identifier; structural or navigation property
pathSegment = "/" path
castSegment = identifier 1*( "." identifier ) ; qualified type name
keySegment = "{" keyProperty "}"
keyProperty = identifier ; name of the key property
serviceOperationSegment = identifier parameters [ "/" castSegment ] [ "/" keySegment ]
parameters = "(" OWS [ parameterSpecification *( "," OWS parameterSpecification ) OWS ] ")"
parameterSpecification = identifier OWS "=" OWS "{" identifier "}"
capabilities = singlePathCapabilities / collectionPathCapabilities / singleNavPathCapabilities / collectionNavPathCapabilities
```

### Path Capabilities

```ABNF
singlePathCapability = ("GET" / "PUT" / "PATCH" / "DELETE") [noOptions]
singlePathCapabilities = "{" OWS [singlePathCapability *( separator singlePathCapability) OWS] "}"
collectionPathCapability = "GET" [ collectionCapabilities ] / "POST" [noOptions]
collectionPathCapabilities = "{" OWS [ collectionPathCapability *( separator collectionPathCapability ) OWS ] "}"
singleNavPathCapability = ("GET" / "PATCH" / "PUT") [ OWS navCapabilities ] / "DELETE" noOptions
singleNavPathCapabilities = "{" OWS [singleNavPathCapability *( separator singleNavPathCapability ) OWS ] "}"
collectionNavPathCapability = "GET" [ OWS collectionNavCapabilities ] / "POST" [ OWS navCapabilities ]
collectionNavPathCapabilities = "{" OWS [ collectionNavPathCapability *( separator collectionNavPathCapability ) OWS ] "}"
```

### Capability Elements

```ABNF
collectionCapability = filterCapability / orderByCapability / "top" / "skip" / "count"
collectionCapabilities = "{" OWS [ collectionCapability *( separator collectionCapability ) OWS ] "}"
collectionNavCapability = collectionCapability / navCapability
collectionNavCapabilities = "{" OWS [ collectionNavCapability *( separator collectionNavCapability ) OWS ] "}"
navCapability = "expand" [ OWS "{" OWS [ expandProperty *( OWS "," OWS expandProperty OWS ) ] OWS "}" ]
navCapabilities = "{" OWS [ navCapability OWS ] "}"
expandProperty = star / [ castSegment "/" ] navigationProperty ( [ OWS collectionNavCapabilities ] / [ OWS navCapabilities ] )
navigationProperty = identifier ; single or collection valued navigation property
filterCapability = "filter" [ "{" [ OWS filterProperty *( "," OWS filterProperty OWS ) ] "}" ]
filterProperty = ( ( [ typeName "/" ] propertyName ) / allProperties) [ OWS filterOptions ]
allProperties = star [ "/" typeName ] ; all properties, optionally of a given type
filterOptions = "{" OWS [ filterOperations OWS ] "}"
filterOperations = "none" ; not filterable
/ "eq" ; eq
/ "comp" ; eq, gt, ge, lt, le
/ "stringComp" ; eq, gt, ge, lt, le, startswith, endswith, contains
/ "string" ; eq, startswith, endswith, contains
orderByCapability = "orderby" [ OWS orderByProperties ]
orderByProperties = "{" OWS [ orderByProperty *( "," OWS orderByProperty OWS ) ] "}"
orderByProperty = allProperties / propertyName [ OWS orderByDirection ]
orderByDirection ="{" [ OWS ascOrDesc [ "," OWS ascOrDesc OWS ] ] "}"
ascOrDesc = "asc" / "desc"
noOptions = OWS "{" OWS "}"
```

### Core Syntax Elements

```ABNF
qualifiedName = identifier *( "." identifier )
identifier = identInitial *identSubsequent
Expand All @@ -137,6 +269,10 @@ identInitial = ALPHA / "_" ; Note: actually all Unicode letters
identSubsequent = identInitial / DIGIT
separator = OWS "," OWS / RWS
star = "*"
number = integer [ "." 1*DIGIT ] [ "e" integer ]
integer = [ "+" / "-" ] ( %x30 / %x31-39 *DIGIT )
Expand Down
Loading

0 comments on commit bf9a8e4

Please sign in to comment.