From 34cd37364da1cef8be67dd6c92a388978674b717 Mon Sep 17 00:00:00 2001 From: Garrett DeBruin <16618938+corranrogue9@users.noreply.github.com> Date: Fri, 22 Sep 2023 10:03:58 -0700 Subject: [PATCH 1/9] Create encoded-ids.md --- graph/patterns/encoded-ids.md | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 graph/patterns/encoded-ids.md diff --git a/graph/patterns/encoded-ids.md b/graph/patterns/encoded-ids.md new file mode 100644 index 00000000..26336e73 --- /dev/null +++ b/graph/patterns/encoded-ids.md @@ -0,0 +1,30 @@ +# Pattern name + +Microsoft Graph API Design Pattern + +*Provide a short description of the pattern.* + + +## Problem + +*Describe the business context relevant for the pattern.* + +*Provide a short description of the problem.* + +## Solution + +*Describe how to implement the solution to solve the problem.* + +*Describe related patterns.* + +## When to use this pattern + +*Describe when and why the solution is applicable and when it might not be.* + +## Issues and considerations + +*Describe tradeoffs of the solution.* + +## Example + +*Provide a short example from real life.* From 84b2d7cbd1325e675d95c75661c8e724dcf00982 Mon Sep 17 00:00:00 2001 From: Garrett DeBruin <16618938+corranrogue9@users.noreply.github.com> Date: Fri, 22 Sep 2023 10:04:41 -0700 Subject: [PATCH 2/9] Update and rename encoded-ids.md to encoded-keys.md --- graph/patterns/{encoded-ids.md => encoded-keys.md} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename graph/patterns/{encoded-ids.md => encoded-keys.md} (95%) diff --git a/graph/patterns/encoded-ids.md b/graph/patterns/encoded-keys.md similarity index 95% rename from graph/patterns/encoded-ids.md rename to graph/patterns/encoded-keys.md index 26336e73..043f7668 100644 --- a/graph/patterns/encoded-ids.md +++ b/graph/patterns/encoded-keys.md @@ -1,4 +1,4 @@ -# Pattern name +# Encoded Key Properties Microsoft Graph API Design Pattern From c5ecbafd81beaf3159ac0e56310091e89fb60b98 Mon Sep 17 00:00:00 2001 From: Garrett DeBruin <16618938+corranrogue9@users.noreply.github.com> Date: Fri, 22 Sep 2023 10:07:58 -0700 Subject: [PATCH 3/9] Update encoded-keys.md --- graph/patterns/encoded-keys.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/graph/patterns/encoded-keys.md b/graph/patterns/encoded-keys.md index 043f7668..20795c20 100644 --- a/graph/patterns/encoded-keys.md +++ b/graph/patterns/encoded-keys.md @@ -2,7 +2,7 @@ Microsoft Graph API Design Pattern -*Provide a short description of the pattern.* +Key properties should be encoded with [base64url encoding](https://datatracker.ietf.org/doc/html/rfc4648#section-5) when their values can include the `/` character. ## Problem From ee9398195f0e9df23e08c3300841002b54550b8c Mon Sep 17 00:00:00 2001 From: Garrett DeBruin <16618938+corranrogue9@users.noreply.github.com> Date: Fri, 22 Sep 2023 10:32:54 -0700 Subject: [PATCH 4/9] Update encoded-keys.md --- graph/patterns/encoded-keys.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/graph/patterns/encoded-keys.md b/graph/patterns/encoded-keys.md index 20795c20..fc054a37 100644 --- a/graph/patterns/encoded-keys.md +++ b/graph/patterns/encoded-keys.md @@ -7,9 +7,9 @@ Key properties should be encoded with [base64url encoding](https://datatracker.i ## Problem -*Describe the business context relevant for the pattern.* - -*Provide a short description of the problem.* +OData URLs that identify an individual entity within a collection will contain the key for that entity. +These keys can sometimes include reserved URL characters, and the [OData standard](https://docs.oasis-open.org/odata/odata/v4.01/odata-v4.01-part2-url-conventions.html#sec_URLParsing) indicates that these characters should be percent-encoded. +Due to a long-standing bug in Microsoft Graph, and one that cannot be fixed in order to maintain backwards compatibility, percent-encoding the `/` character is not possible for Microsoft Graph APIs. ## Solution From 2f5c3c537c6378e89fd171a4fa598c71db36c555 Mon Sep 17 00:00:00 2001 From: Garrett DeBruin <16618938+corranrogue9@users.noreply.github.com> Date: Fri, 22 Sep 2023 10:55:05 -0700 Subject: [PATCH 5/9] Update encoded-keys.md --- graph/patterns/encoded-keys.md | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/graph/patterns/encoded-keys.md b/graph/patterns/encoded-keys.md index fc054a37..dbdd550a 100644 --- a/graph/patterns/encoded-keys.md +++ b/graph/patterns/encoded-keys.md @@ -10,20 +10,23 @@ Key properties should be encoded with [base64url encoding](https://datatracker.i OData URLs that identify an individual entity within a collection will contain the key for that entity. These keys can sometimes include reserved URL characters, and the [OData standard](https://docs.oasis-open.org/odata/odata/v4.01/odata-v4.01-part2-url-conventions.html#sec_URLParsing) indicates that these characters should be percent-encoded. Due to a long-standing bug in Microsoft Graph, and one that cannot be fixed in order to maintain backwards compatibility, percent-encoding the `/` character is not possible for Microsoft Graph APIs. +This means that key properties cannot contain the `/` character, which can be limiting to the API design. ## Solution -*Describe how to implement the solution to solve the problem.* - -*Describe related patterns.* +A key property that may contain the `/` character should be base64url encoded, and each instance of the property should be encoded regardless if that particular value contains the `/` character. +The entity may additionally include a non-key property that contains the plaintext of the key property. +This property should have the same name as the key property with `Plaintext` appended. +The collection may also support filtering on the plaintext property. ## When to use this pattern -*Describe when and why the solution is applicable and when it might not be.* +This pattern should be used whenever the value of a key property may contain a `/` character. ## Issues and considerations -*Describe tradeoffs of the solution.* +Encoding a key property often obfuscates the natural way that a client identifies an entity, particularly entities that are related to extenal services or standards. +A plaintext property that allows filtering can help to reduce this impact, but filtering itself has semantic limitations in OData (for example, if the client wants to navigate to a navigation property of the entity, using a filter does not allow this). ## Example From 35b9a9c3c17fca1de8be0f205fe0f5ac4d0ce543 Mon Sep 17 00:00:00 2001 From: Garrett DeBruin <16618938+corranrogue9@users.noreply.github.com> Date: Fri, 22 Sep 2023 14:33:26 -0700 Subject: [PATCH 6/9] Update encoded-keys.md --- graph/patterns/encoded-keys.md | 47 +++++++++++++++++++++++++++++++++- 1 file changed, 46 insertions(+), 1 deletion(-) diff --git a/graph/patterns/encoded-keys.md b/graph/patterns/encoded-keys.md index dbdd550a..3cb6ce2f 100644 --- a/graph/patterns/encoded-keys.md +++ b/graph/patterns/encoded-keys.md @@ -30,4 +30,49 @@ A plaintext property that allows filtering can help to reduce this impact, but f ## Example -*Provide a short example from real life.* +```xml + + + + + + + + + ... + +``` +```json +GET /foos/dGhpcyBpcyBhbiBpZCB3aXRoIC8 + +200 OK +{ + "id": "dGhpcyBpcyBhbiBpZCB3aXRoIC8", + "idPlaintext": "this is an id with /", + ... +} +``` +```json +GET /foos('dGhpcyBpcyBhbiBpZCB3aXRoIC8') + +200 OK +{ + "id": "dGhpcyBpcyBhbiBpZCB3aXRoIC8", + "idPlaintext": "this is an id with /", + ... +} +``` +```json +GET /foos?$filter=idPlaintext eq 'this is an id with /' + +200 OK +{ + "value": [ + { + "id": "dGhpcyBpcyBhbiBpZCB3aXRoIC8", + "idPlaintext": "this is an id with /", + ... + } + ] +} +``` From 1e3ab8540722085e236d69d19ffca17a5fc539be Mon Sep 17 00:00:00 2001 From: Garrett DeBruin <16618938+corranrogue9@users.noreply.github.com> Date: Fri, 22 Sep 2023 14:35:48 -0700 Subject: [PATCH 7/9] Update encoded-keys.md --- graph/patterns/encoded-keys.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/graph/patterns/encoded-keys.md b/graph/patterns/encoded-keys.md index 3cb6ce2f..a57899f6 100644 --- a/graph/patterns/encoded-keys.md +++ b/graph/patterns/encoded-keys.md @@ -43,7 +43,7 @@ A plaintext property that allows filtering can help to reduce this impact, but f ``` ```json -GET /foos/dGhpcyBpcyBhbiBpZCB3aXRoIC8 +GET https://www.test.com/foos/dGhpcyBpcyBhbiBpZCB3aXRoIC8 200 OK { From aa99e009eaf48c4b0d2a194b2db19ee4ab26de19 Mon Sep 17 00:00:00 2001 From: Garrett DeBruin <16618938+corranrogue9@users.noreply.github.com> Date: Fri, 22 Sep 2023 14:37:23 -0700 Subject: [PATCH 8/9] Update encoded-keys.md --- graph/patterns/encoded-keys.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/graph/patterns/encoded-keys.md b/graph/patterns/encoded-keys.md index a57899f6..eef1f954 100644 --- a/graph/patterns/encoded-keys.md +++ b/graph/patterns/encoded-keys.md @@ -42,7 +42,7 @@ A plaintext property that allows filtering can help to reduce this impact, but f ... ``` -```json +```http GET https://www.test.com/foos/dGhpcyBpcyBhbiBpZCB3aXRoIC8 200 OK @@ -52,7 +52,7 @@ GET https://www.test.com/foos/dGhpcyBpcyBhbiBpZCB3aXRoIC8 ... } ``` -```json +```http GET /foos('dGhpcyBpcyBhbiBpZCB3aXRoIC8') 200 OK @@ -62,7 +62,7 @@ GET /foos('dGhpcyBpcyBhbiBpZCB3aXRoIC8') ... } ``` -```json +```http GET /foos?$filter=idPlaintext eq 'this is an id with /' 200 OK From 5ca2e24d265b4a8d9adac1e07946e6084625a238 Mon Sep 17 00:00:00 2001 From: Garrett DeBruin <16618938+corranrogue9@users.noreply.github.com> Date: Fri, 22 Sep 2023 14:37:54 -0700 Subject: [PATCH 9/9] Update encoded-keys.md --- graph/patterns/encoded-keys.md | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/graph/patterns/encoded-keys.md b/graph/patterns/encoded-keys.md index eef1f954..a18b9c2e 100644 --- a/graph/patterns/encoded-keys.md +++ b/graph/patterns/encoded-keys.md @@ -39,17 +39,15 @@ A plaintext property that allows filtering can help to reduce this impact, but f - ... ``` ```http -GET https://www.test.com/foos/dGhpcyBpcyBhbiBpZCB3aXRoIC8 +GET /foos/dGhpcyBpcyBhbiBpZCB3aXRoIC8 200 OK { "id": "dGhpcyBpcyBhbiBpZCB3aXRoIC8", - "idPlaintext": "this is an id with /", - ... + "idPlaintext": "this is an id with /" } ``` ```http @@ -58,8 +56,7 @@ GET /foos('dGhpcyBpcyBhbiBpZCB3aXRoIC8') 200 OK { "id": "dGhpcyBpcyBhbiBpZCB3aXRoIC8", - "idPlaintext": "this is an id with /", - ... + "idPlaintext": "this is an id with /" } ``` ```http @@ -70,8 +67,7 @@ GET /foos?$filter=idPlaintext eq 'this is an id with /' "value": [ { "id": "dGhpcyBpcyBhbiBpZCB3aXRoIC8", - "idPlaintext": "this is an id with /", - ... + "idPlaintext": "this is an id with /" } ] }