From 42bf48c3f73855a9913091978429b10f32358f35 Mon Sep 17 00:00:00 2001 From: Garrett DeBruin <16618938+corranrogue9@users.noreply.github.com> Date: Thu, 16 Nov 2023 16:11:50 -0800 Subject: [PATCH 01/34] Create entity-template.md --- graph/patterns/entity-template.md | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 graph/patterns/entity-template.md diff --git a/graph/patterns/entity-template.md b/graph/patterns/entity-template.md new file mode 100644 index 00000000..8e9b73d7 --- /dev/null +++ b/graph/patterns/entity-template.md @@ -0,0 +1,30 @@ +# Entity template + +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 12d87d44382471f93bafdf7b27c67b3afff6bb4e Mon Sep 17 00:00:00 2001 From: Garrett DeBruin <16618938+corranrogue9@users.noreply.github.com> Date: Thu, 16 Nov 2023 16:22:50 -0800 Subject: [PATCH 02/34] Update entity-template.md --- graph/patterns/entity-template.md | 53 +++++++++++++++++++++++++++---- 1 file changed, 47 insertions(+), 6 deletions(-) diff --git a/graph/patterns/entity-template.md b/graph/patterns/entity-template.md index 8e9b73d7..0cbc8d72 100644 --- a/graph/patterns/entity-template.md +++ b/graph/patterns/entity-template.md @@ -2,20 +2,61 @@ Microsoft Graph API Design Pattern -*Provide a short description of the pattern.* +*An entity template is a template which can be used to create a new instance of an entity. * ## Problem -*Describe the business context relevant for the pattern.* - -*Provide a short description of the problem.* +A customer wants to create instances of an entity that all start from the same basic data, and this data needs to be shared across clients over time. ## Solution -*Describe how to implement the solution to solve the problem.* +For an existing `foo` entity: +``` + + + + + + + + +//// TODO entity set +``` +a "template" entity is defined for `foo`: +``` + + + + + + + + +//// TODO entity set +``` +`foo` is then updated to have a navigation property to a `fooTemplate`: +``` + + + + + + + + //// TODO create-only + +``` +In order to create a `foo` from the `fooTemplate` with ID `{templateId}`, the client can call: +``` +POST .../foos //// TODO full URL +{ + "template@odata.bind": ".../fooTemplates/{templateId}" //// TODO full URL +} +``` -*Describe related patterns.* +//// TODO managing templates +//// TODO do you want to talk about "non-provided" properties? if `fizz` isn't in the template creation, it becomes `null`; do we need a way to say "don't use `fizz` when creating the instance from the template"? ## When to use this pattern From ccc022006ef4e2b6fb7ab357cceab610c738a8f4 Mon Sep 17 00:00:00 2001 From: Garrett DeBruin <16618938+corranrogue9@users.noreply.github.com> Date: Thu, 16 Nov 2023 16:23:00 -0800 Subject: [PATCH 03/34] Update entity-template.md --- graph/patterns/entity-template.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/graph/patterns/entity-template.md b/graph/patterns/entity-template.md index 0cbc8d72..5344da04 100644 --- a/graph/patterns/entity-template.md +++ b/graph/patterns/entity-template.md @@ -2,7 +2,7 @@ Microsoft Graph API Design Pattern -*An entity template is a template which can be used to create a new instance of an entity. * +*An entity template is a template which can be used to create a new instance of an entity.* ## Problem From 9ea2260997ae840012b47af1a1add97cbf15aece Mon Sep 17 00:00:00 2001 From: Garrett DeBruin <16618938+corranrogue9@users.noreply.github.com> Date: Thu, 16 Nov 2023 16:26:36 -0800 Subject: [PATCH 04/34] Update entity-template.md --- graph/patterns/entity-template.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/graph/patterns/entity-template.md b/graph/patterns/entity-template.md index 5344da04..d474cb52 100644 --- a/graph/patterns/entity-template.md +++ b/graph/patterns/entity-template.md @@ -64,7 +64,7 @@ POST .../foos //// TODO full URL ## Issues and considerations -*Describe tradeoffs of the solution.* +TODO if managing templates is more consuming that managing the entities ## Example From 33abb4a2436a3d8ef878575c55bd0fc59386d3fa Mon Sep 17 00:00:00 2001 From: Garrett DeBruin <16618938+corranrogue9@users.noreply.github.com> Date: Fri, 17 Nov 2023 09:20:20 -0800 Subject: [PATCH 05/34] Update entity-template.md --- graph/patterns/entity-template.md | 1 + 1 file changed, 1 insertion(+) diff --git a/graph/patterns/entity-template.md b/graph/patterns/entity-template.md index d474cb52..4da7c018 100644 --- a/graph/patterns/entity-template.md +++ b/graph/patterns/entity-template.md @@ -52,6 +52,7 @@ In order to create a `foo` from the `fooTemplate` with ID `{templateId}`, the cl POST .../foos //// TODO full URL { "template@odata.bind": ".../fooTemplates/{templateId}" //// TODO full URL +//// TODO this has the same problem as the "draft" antipattern where foos now can't be properly validated } ``` From 2c50645fe4ad59bfdb805b0b2b1572bb4e52dc47 Mon Sep 17 00:00:00 2001 From: Garrett DeBruin <16618938+corranrogue9@users.noreply.github.com> Date: Fri, 17 Nov 2023 18:36:15 -0800 Subject: [PATCH 06/34] Update entity-template.md --- graph/patterns/entity-template.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/graph/patterns/entity-template.md b/graph/patterns/entity-template.md index 4da7c018..9c71c851 100644 --- a/graph/patterns/entity-template.md +++ b/graph/patterns/entity-template.md @@ -11,6 +11,9 @@ A customer wants to create instances of an entity that all start from the same b ## Solution +//// TODO establish a general pattern for actions bound to an entity collection where the actions are different constructor overloads; the "original" overload is still just a post to the collection +//// TODO templates are just a new constructor overload + For an existing `foo` entity: ``` From 1cfaf93b747883a86feb672b87079c6db8a69758 Mon Sep 17 00:00:00 2001 From: Garrett DeBruin <16618938+corranrogue9@users.noreply.github.com> Date: Mon, 18 Dec 2023 16:24:55 -0800 Subject: [PATCH 07/34] Update entity-template.md --- graph/patterns/entity-template.md | 59 ++++++++++++++++++++++++++----- 1 file changed, 51 insertions(+), 8 deletions(-) diff --git a/graph/patterns/entity-template.md b/graph/patterns/entity-template.md index 9c71c851..a3b849c3 100644 --- a/graph/patterns/entity-template.md +++ b/graph/patterns/entity-template.md @@ -4,18 +4,18 @@ Microsoft Graph API Design Pattern *An entity template is a template which can be used to create a new instance of an entity.* - ## Problem A customer wants to create instances of an entity that all start from the same basic data, and this data needs to be shared across clients over time. ## Solution -//// TODO establish a general pattern for actions bound to an entity collection where the actions are different constructor overloads; the "original" overload is still just a post to the collection -//// TODO templates are just a new constructor overload - +Introduce a new entity type that is a template for the entity that the customer is trying to create. For an existing `foo` entity: -``` +```xml + + + @@ -24,10 +24,9 @@ For an existing `foo` entity: -//// TODO entity set ``` a "template" entity is defined for `foo`: -``` +```xml @@ -36,8 +35,47 @@ a "template" entity is defined for `foo`: -//// TODO entity set + + + ``` +An action should also be introduced that will create the `foo` based on the `fooTemplate`: +```xml + + + + +``` +A client can then create a `foo` from a `fooTemplate` by calling: +```http +POST /foos/create +{ + "template@odata.bind": "/templates/{templateId}" +} + +HTTP/1.1 201 Created +Location: /foos/{fooId} + +{ + "id": "{fooId}", + "fizz": { + ... + }, + "buzz": { + ... + } +} +``` + + + + + + + + + + `foo` is then updated to have a navigation property to a `fooTemplate`: ``` @@ -59,6 +97,11 @@ POST .../foos //// TODO full URL } ``` + + + +//// TODO establish a general pattern for actions bound to an entity collection where the actions are different constructor overloads; the "original" overload is still just a post to the collection +//// TODO templates are just a new constructor overload //// TODO managing templates //// TODO do you want to talk about "non-provided" properties? if `fizz` isn't in the template creation, it becomes `null`; do we need a way to say "don't use `fizz` when creating the instance from the template"? From f5189b614159e286bb0612892eb7fd02a5ded07f Mon Sep 17 00:00:00 2001 From: Garrett DeBruin <16618938+corranrogue9@users.noreply.github.com> Date: Mon, 18 Dec 2023 16:26:06 -0800 Subject: [PATCH 08/34] Update entity-template.md --- graph/patterns/entity-template.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/graph/patterns/entity-template.md b/graph/patterns/entity-template.md index a3b849c3..7eec53c6 100644 --- a/graph/patterns/entity-template.md +++ b/graph/patterns/entity-template.md @@ -10,7 +10,7 @@ A customer wants to create instances of an entity that all start from the same b ## Solution -Introduce a new entity type that is a template for the entity that the customer is trying to create. +### Introduce a new entity type that is a template for the entity that the customer is trying to create. For an existing `foo` entity: ```xml @@ -67,6 +67,7 @@ Location: /foos/{fooId} } ``` +### Add a new property to an existing entity and update its associated template entity From 7f485cfe64b97d0d7f05e4e4142feed2e421a952 Mon Sep 17 00:00:00 2001 From: Garrett DeBruin <16618938+corranrogue9@users.noreply.github.com> Date: Mon, 18 Dec 2023 16:30:34 -0800 Subject: [PATCH 09/34] Update entity-template.md --- graph/patterns/entity-template.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/graph/patterns/entity-template.md b/graph/patterns/entity-template.md index 7eec53c6..3e75bf35 100644 --- a/graph/patterns/entity-template.md +++ b/graph/patterns/entity-template.md @@ -69,6 +69,20 @@ Location: /foos/{fooId} ### Add a new property to an existing entity and update its associated template entity +If a property `frob` is added to the `foo` entity: +```xml + + ... + + +``` +then the associated `fooTemplate` type should be updated to accommodate `frob`. +It is tempting to just add `frob` to `fooTemplate`. +There are 3 important cases to consider with the `frob` property: +1. If `frob` is provided as `null`, then `frob` is assigned a default value by the service that is dynamic based on the service state and the customer configuration +2. If `frob` is provided as `null`, then `frob` is assigned the value of `null` +3. If `frob` is not provided, then `frob` is assigned a default value by the service that is dynamic based on the service state and the customer configuration +4. If `frob` is not provided, then `frob` is assigned the value of `null` From af8eaecb38f6d96dfb12f775351ddc1e3aae0ce1 Mon Sep 17 00:00:00 2001 From: Garrett DeBruin <16618938+corranrogue9@users.noreply.github.com> Date: Mon, 18 Dec 2023 16:35:05 -0800 Subject: [PATCH 10/34] Update entity-template.md --- graph/patterns/entity-template.md | 31 ++++++------------------------- 1 file changed, 6 insertions(+), 25 deletions(-) diff --git a/graph/patterns/entity-template.md b/graph/patterns/entity-template.md index 3e75bf35..986bd025 100644 --- a/graph/patterns/entity-template.md +++ b/graph/patterns/entity-template.md @@ -78,12 +78,16 @@ If a property `frob` is added to the `foo` entity: ``` then the associated `fooTemplate` type should be updated to accommodate `frob`. It is tempting to just add `frob` to `fooTemplate`. -There are 3 important cases to consider with the `frob` property: +There are 4 important cases to consider with the `frob` property: 1. If `frob` is provided as `null`, then `frob` is assigned a default value by the service that is dynamic based on the service state and the customer configuration 2. If `frob` is provided as `null`, then `frob` is assigned the value of `null` 3. If `frob` is not provided, then `frob` is assigned a default value by the service that is dynamic based on the service state and the customer configuration 4. If `frob` is not provided, then `frob` is assigned the value of `null` +Because these cases can be used in combination with each other (for example, 3 and 4 can coexist), templates need to accommodate these situations. +As a result, if 3 and 4 coexist, adding a `frob` property to the `fooTemplate` changes the semantics of existing instances of the `fooTemplate`; any existing template now needs to have the `frob` property backfilled to some concrete default value, or `null`, but `null` is different from the value not being provided. +This means that we cannot just add a `frob` property to the `fooTemplate`. +//// TODO is the conclusion then that we should have "not provided" types for templates? @@ -91,34 +95,11 @@ There are 3 important cases to consider with the `frob` property: -`foo` is then updated to have a navigation property to a `fooTemplate`: -``` - - - - - - - - //// TODO create-only - -``` -In order to create a `foo` from the `fooTemplate` with ID `{templateId}`, the client can call: -``` -POST .../foos //// TODO full URL -{ - "template@odata.bind": ".../fooTemplates/{templateId}" //// TODO full URL -//// TODO this has the same problem as the "draft" antipattern where foos now can't be properly validated -} -``` - - - +//// TODO do you want to talk about "non-provided" properties? if `fizz` isn't in the template creation, it becomes `null`; do we need a way to say "don't use `fizz` when creating the instance from the template"? //// TODO establish a general pattern for actions bound to an entity collection where the actions are different constructor overloads; the "original" overload is still just a post to the collection //// TODO templates are just a new constructor overload //// TODO managing templates -//// TODO do you want to talk about "non-provided" properties? if `fizz` isn't in the template creation, it becomes `null`; do we need a way to say "don't use `fizz` when creating the instance from the template"? ## When to use this pattern From 2d9ad3bd4671ec8a65e2a3da128e33d83a87bd6f Mon Sep 17 00:00:00 2001 From: Garrett DeBruin <16618938+corranrogue9@users.noreply.github.com> Date: Mon, 18 Dec 2023 16:49:31 -0800 Subject: [PATCH 11/34] Update entity-template.md --- graph/patterns/entity-template.md | 1 + 1 file changed, 1 insertion(+) diff --git a/graph/patterns/entity-template.md b/graph/patterns/entity-template.md index 986bd025..138b052b 100644 --- a/graph/patterns/entity-template.md +++ b/graph/patterns/entity-template.md @@ -44,6 +44,7 @@ An action should also be introduced that will create the `foo` based on the `foo + ``` A client can then create a `foo` from a `fooTemplate` by calling: From 7bc33a04d7ca8b4b8c5c1b62d5a00b62cababaa9 Mon Sep 17 00:00:00 2001 From: Garrett DeBruin <16618938+corranrogue9@users.noreply.github.com> Date: Mon, 18 Dec 2023 16:53:19 -0800 Subject: [PATCH 12/34] Update entity-template.md --- graph/patterns/entity-template.md | 87 +++++++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) diff --git a/graph/patterns/entity-template.md b/graph/patterns/entity-template.md index 138b052b..c9f31ed2 100644 --- a/graph/patterns/entity-template.md +++ b/graph/patterns/entity-template.md @@ -91,7 +91,94 @@ This means that we cannot just add a `frob` property to the `fooTemplate`. //// TODO is the conclusion then that we should have "not provided" types for templates? +### TODO start of scratch pad +```xml + + + + + + + + + + + + + + + + + + +``` + + +```http +POST /fooTemplates +{ + "fizz": { + "@odata.type": "#self.fizzTemplateProperty", + "value": { + // fizz properties here + } + } +} + +HTTP/1.1 201 Created +Location: /fooTemplates/{templateId} + +{ + "id": "{templateId}", + "fizz": { + "@odata.type": "#self.fizzTemplateProperty", + "value": { + // fizz properties here + } + }, + "buzz": { + "@odata.type": "#self.notProvidedTemplateProperty" + } +} +``` + +```xml + + + + + +``` + +```http +POST /fooTemplates/create +{ + "foo": { + "fizz": { + // fizz properties here + } + } +} + +HTTP/1.1 201 Created +Location: /fooTemplates/{templateId} + +{ + "id": "{templateId}", + "fizz": { + "@odata.type": "#self.fizzTemplateProperty", + "value": { + // fizz properties here + } + }, + "buzz": { + "@odata.type": "#self.notProvidedTemplateProperty" + } +} +``` + +### TODO end of scratch pad From e08ca1951763626307c838556f6eb6ad2ba5882c Mon Sep 17 00:00:00 2001 From: Garrett DeBruin <16618938+corranrogue9@users.noreply.github.com> Date: Wed, 20 Dec 2023 10:03:36 -0800 Subject: [PATCH 13/34] Update entity-template.md --- graph/patterns/entity-template.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/graph/patterns/entity-template.md b/graph/patterns/entity-template.md index c9f31ed2..7a670445 100644 --- a/graph/patterns/entity-template.md +++ b/graph/patterns/entity-template.md @@ -47,11 +47,12 @@ An action should also be introduced that will create the `foo` based on the `foo ``` +//// TODO show the template before this sample A client can then create a `foo` from a `fooTemplate` by calling: ```http POST /foos/create { - "template@odata.bind": "/templates/{templateId}" + "template@odata.bind": "/fooTemplates/{templateId}" } HTTP/1.1 201 Created From 6a8a7d2824ab95a20c44258f517bb87d94653b50 Mon Sep 17 00:00:00 2001 From: Garrett DeBruin <16618938+corranrogue9@users.noreply.github.com> Date: Wed, 20 Dec 2023 10:39:24 -0800 Subject: [PATCH 14/34] Update entity-template.md --- graph/patterns/entity-template.md | 1 + 1 file changed, 1 insertion(+) diff --git a/graph/patterns/entity-template.md b/graph/patterns/entity-template.md index 7a670445..2f36b14d 100644 --- a/graph/patterns/entity-template.md +++ b/graph/patterns/entity-template.md @@ -90,6 +90,7 @@ Because these cases can be used in combination with each other (for example, 3 a As a result, if 3 and 4 coexist, adding a `frob` property to the `fooTemplate` changes the semantics of existing instances of the `fooTemplate`; any existing template now needs to have the `frob` property backfilled to some concrete default value, or `null`, but `null` is different from the value not being provided. This means that we cannot just add a `frob` property to the `fooTemplate`. //// TODO is the conclusion then that we should have "not provided" types for templates? +//// TODO use a not provided instance annotation ### TODO start of scratch pad From 2c0ab5d139e77f9119dc8587e665aa9758b1281a Mon Sep 17 00:00:00 2001 From: Garrett DeBruin <16618938+corranrogue9@users.noreply.github.com> Date: Thu, 21 Dec 2023 09:03:19 -0800 Subject: [PATCH 15/34] Update entity-template.md --- graph/patterns/entity-template.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/graph/patterns/entity-template.md b/graph/patterns/entity-template.md index 2f36b14d..320418b3 100644 --- a/graph/patterns/entity-template.md +++ b/graph/patterns/entity-template.md @@ -35,7 +35,7 @@ a "template" entity is defined for `foo`: - + ``` From 5d800f3785590740a8f094cd5a7ccb8024de80ba Mon Sep 17 00:00:00 2001 From: Garrett DeBruin <16618938+corranrogue9@users.noreply.github.com> Date: Thu, 21 Dec 2023 09:06:29 -0800 Subject: [PATCH 16/34] Update entity-template.md --- graph/patterns/entity-template.md | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/graph/patterns/entity-template.md b/graph/patterns/entity-template.md index 320418b3..a71e0119 100644 --- a/graph/patterns/entity-template.md +++ b/graph/patterns/entity-template.md @@ -25,6 +25,7 @@ For an existing `foo` entity: ``` + a "template" entity is defined for `foo`: ```xml @@ -39,6 +40,7 @@ a "template" entity is defined for `foo`: ``` + An action should also be introduced that will create the `foo` based on the `fooTemplate`: ```xml @@ -47,12 +49,34 @@ An action should also be introduced that will create the `foo` based on the `foo ``` -//// TODO show the template before this sample -A client can then create a `foo` from a `fooTemplate` by calling: + +A client can now create a `fooTemplate`, something like: +```http +POST /fooTemplates +{ + "fizz": { + // fizz properties here + }, + "buzz": null +} + +HTTP/1.1 201 Created +Location: /fooTemplates/{templateId} + +{ + "id": "{templateId}", + "fizz": { + // fizz properties here + }, + "buzz": null +} +``` + +This template can then be used to create a `foo`: ```http POST /foos/create { - "template@odata.bind": "/fooTemplates/{templateId}" + "template@odata.bind": "/fooTemplates/{templateId}" //// TODO get this syntax correct } HTTP/1.1 201 Created From d9cbce6a8df008a4299bec0c4b9ed01362c1ca3b Mon Sep 17 00:00:00 2001 From: Garrett DeBruin <16618938+corranrogue9@users.noreply.github.com> Date: Thu, 21 Dec 2023 09:09:14 -0800 Subject: [PATCH 17/34] Update entity-template.md --- graph/patterns/entity-template.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/graph/patterns/entity-template.md b/graph/patterns/entity-template.md index a71e0119..6e61f350 100644 --- a/graph/patterns/entity-template.md +++ b/graph/patterns/entity-template.md @@ -76,7 +76,7 @@ This template can then be used to create a `foo`: ```http POST /foos/create { - "template@odata.bind": "/fooTemplates/{templateId}" //// TODO get this syntax correct + "template@odata.bind": "/fooTemplates/{templateId}" } HTTP/1.1 201 Created From a14d88258d332183a81fc6415515a4adb6b96e40 Mon Sep 17 00:00:00 2001 From: Garrett DeBruin <16618938+corranrogue9@users.noreply.github.com> Date: Thu, 21 Dec 2023 09:18:36 -0800 Subject: [PATCH 18/34] Update entity-template.md --- graph/patterns/entity-template.md | 80 ++++++++++++++++++++++++++++--- 1 file changed, 73 insertions(+), 7 deletions(-) diff --git a/graph/patterns/entity-template.md b/graph/patterns/entity-template.md index 6e61f350..4e588751 100644 --- a/graph/patterns/entity-template.md +++ b/graph/patterns/entity-template.md @@ -61,10 +61,10 @@ POST /fooTemplates } HTTP/1.1 201 Created -Location: /fooTemplates/{templateId} +Location: /fooTemplates/{templateId1} { - "id": "{templateId}", + "id": "{templateId1}", "fizz": { // fizz properties here }, @@ -76,7 +76,7 @@ This template can then be used to create a `foo`: ```http POST /foos/create { - "template@odata.bind": "/fooTemplates/{templateId}" + "template@odata.bind": "/fooTemplates/{templateId1}" } HTTP/1.1 201 Created @@ -95,13 +95,79 @@ Location: /foos/{fooId} ### Add a new property to an existing entity and update its associated template entity -If a property `frob` is added to the `foo` entity: +A property `frob` may be added to the `foo` entity: ```xml ... ``` + +Likely, clients will want an analogous property on the `fooTemplate`. +Because the default value of such a property on `foo` is ambiguous (the default may be `null`, some static value, or a service-generated value only known based on the overall state at runtime), the `fooTemplate` needs a clear way to indicate whether a value was specified for the `frob` property. +This is done with the use of the `notProvided` instance annotation. //// TODO link to docs about instance annotations, and figure out the correct name for "notProvided" +`frob` will be defined on `fooTemplate` as usual: +```xml + + ... + + +``` + +Now, existing templates will return the `notProvided` instance annotation for `frob`: +```http +GET /fooTemplates/{templateId1} + +HTTP/1.1 200 OK +{ + "id": "{templateId1}", + "fizz": { + // fizz properties here + }, + "buzz": null, + "frob@notProvided": true +} +``` + +A new template can be created by specifying `frob`: +``` +POST /fooTemplates +{ + "fizz": { + // fizz properties here + }, + "buzz": { + // buzz properties here + }, + "frob": { + // frob properties here + } +} + +HTTP/1.1 201 Created +Location: /fooTemplates/{templateId2} + +{ + "id": "{templateId2}", + "fizz": { + // fizz properties here + }, + "buzz": { + // buzz properties here + }, + "frob": { + // frob properties here + } +} +``` + + + + + + + + then the associated `fooTemplate` type should be updated to accommodate `frob`. It is tempting to just add `frob` to `fooTemplate`. There are 4 important cases to consider with the `frob` property: @@ -153,10 +219,10 @@ POST /fooTemplates } HTTP/1.1 201 Created -Location: /fooTemplates/{templateId} +Location: /fooTemplates/{templateId1} { - "id": "{templateId}", + "id": "{templateId1}", "fizz": { "@odata.type": "#self.fizzTemplateProperty", "value": { @@ -188,7 +254,7 @@ POST /fooTemplates/create } HTTP/1.1 201 Created -Location: /fooTemplates/{templateId} +Location: /fooTemplates/{templateId1} { "id": "{templateId}", From 1df6976333eca34a919d4bea58cea05ca6964bfb Mon Sep 17 00:00:00 2001 From: Garrett DeBruin <16618938+corranrogue9@users.noreply.github.com> Date: Thu, 21 Dec 2023 09:21:06 -0800 Subject: [PATCH 19/34] Update entity-template.md --- graph/patterns/entity-template.md | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/graph/patterns/entity-template.md b/graph/patterns/entity-template.md index 4e588751..79c16adc 100644 --- a/graph/patterns/entity-template.md +++ b/graph/patterns/entity-template.md @@ -129,7 +129,9 @@ HTTP/1.1 200 OK } ``` -A new template can be created by specifying `frob`: +A new template can be created in the following ways + +#### a value for `frob` is specified by the client ``` POST /fooTemplates { @@ -161,6 +163,13 @@ Location: /fooTemplates/{templateId2} } ``` +### `null` is explicitly specified for `frob` + +//// TODO + +### no value is specified for `frob` + +//// TODO From 460d9ace92feff9631a9a433d7d12425ffb55371 Mon Sep 17 00:00:00 2001 From: Garrett DeBruin <16618938+corranrogue9@users.noreply.github.com> Date: Thu, 21 Dec 2023 09:21:40 -0800 Subject: [PATCH 20/34] Update entity-template.md --- graph/patterns/entity-template.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/graph/patterns/entity-template.md b/graph/patterns/entity-template.md index 79c16adc..f915bf49 100644 --- a/graph/patterns/entity-template.md +++ b/graph/patterns/entity-template.md @@ -163,6 +163,8 @@ Location: /fooTemplates/{templateId2} } ``` +//// TODO show a foo created from this template + ### `null` is explicitly specified for `frob` //// TODO @@ -174,6 +176,7 @@ Location: /fooTemplates/{templateId2} +//// TODO make sure you know how to implement this in webapi From 746b2c7dce5db2f5eeedbbbc01608ef10b27b31e Mon Sep 17 00:00:00 2001 From: Garrett DeBruin <16618938+corranrogue9@users.noreply.github.com> Date: Thu, 21 Dec 2023 09:22:30 -0800 Subject: [PATCH 21/34] Update entity-template.md --- graph/patterns/entity-template.md | 102 ------------------------------ 1 file changed, 102 deletions(-) diff --git a/graph/patterns/entity-template.md b/graph/patterns/entity-template.md index f915bf49..00b75076 100644 --- a/graph/patterns/entity-template.md +++ b/graph/patterns/entity-template.md @@ -180,118 +180,16 @@ Location: /fooTemplates/{templateId2} -then the associated `fooTemplate` type should be updated to accommodate `frob`. -It is tempting to just add `frob` to `fooTemplate`. -There are 4 important cases to consider with the `frob` property: -1. If `frob` is provided as `null`, then `frob` is assigned a default value by the service that is dynamic based on the service state and the customer configuration -2. If `frob` is provided as `null`, then `frob` is assigned the value of `null` -3. If `frob` is not provided, then `frob` is assigned a default value by the service that is dynamic based on the service state and the customer configuration -4. If `frob` is not provided, then `frob` is assigned the value of `null` -Because these cases can be used in combination with each other (for example, 3 and 4 can coexist), templates need to accommodate these situations. -As a result, if 3 and 4 coexist, adding a `frob` property to the `fooTemplate` changes the semantics of existing instances of the `fooTemplate`; any existing template now needs to have the `frob` property backfilled to some concrete default value, or `null`, but `null` is different from the value not being provided. -This means that we cannot just add a `frob` property to the `fooTemplate`. -//// TODO is the conclusion then that we should have "not provided" types for templates? -//// TODO use a not provided instance annotation -### TODO start of scratch pad - -```xml - - - - - - - - - - - - - - - - - - -``` - - -```http -POST /fooTemplates -{ - "fizz": { - "@odata.type": "#self.fizzTemplateProperty", - "value": { - // fizz properties here - } - } -} - -HTTP/1.1 201 Created -Location: /fooTemplates/{templateId1} - -{ - "id": "{templateId1}", - "fizz": { - "@odata.type": "#self.fizzTemplateProperty", - "value": { - // fizz properties here - } - }, - "buzz": { - "@odata.type": "#self.notProvidedTemplateProperty" - } -} -``` - -```xml - - - - - -``` - -```http -POST /fooTemplates/create -{ - "foo": { - "fizz": { - // fizz properties here - } - } -} - -HTTP/1.1 201 Created -Location: /fooTemplates/{templateId1} - -{ - "id": "{templateId}", - "fizz": { - "@odata.type": "#self.fizzTemplateProperty", - "value": { - // fizz properties here - } - }, - "buzz": { - "@odata.type": "#self.notProvidedTemplateProperty" - } -} -``` - -### TODO end of scratch pad -//// TODO do you want to talk about "non-provided" properties? if `fizz` isn't in the template creation, it becomes `null`; do we need a way to say "don't use `fizz` when creating the instance from the template"? //// TODO establish a general pattern for actions bound to an entity collection where the actions are different constructor overloads; the "original" overload is still just a post to the collection //// TODO templates are just a new constructor overload -//// TODO managing templates ## When to use this pattern From 5c98aeeb8b659cf20939c7482f44b7d33249b948 Mon Sep 17 00:00:00 2001 From: Garrett DeBruin <16618938+corranrogue9@users.noreply.github.com> Date: Thu, 21 Dec 2023 09:26:02 -0800 Subject: [PATCH 22/34] Update entity-template.md --- graph/patterns/entity-template.md | 82 +++++++++++++++++++++++++++++-- 1 file changed, 77 insertions(+), 5 deletions(-) diff --git a/graph/patterns/entity-template.md b/graph/patterns/entity-template.md index 00b75076..69c4231a 100644 --- a/graph/patterns/entity-template.md +++ b/graph/patterns/entity-template.md @@ -80,10 +80,10 @@ POST /foos/create } HTTP/1.1 201 Created -Location: /foos/{fooId} +Location: /foos/{fooId1} { - "id": "{fooId}", + "id": "{fooId1}", "fizz": { ... }, @@ -132,7 +132,9 @@ HTTP/1.1 200 OK A new template can be created in the following ways #### a value for `frob` is specified by the client -``` + +The client creates a new template with a value for `frob`: +```http POST /fooTemplates { "fizz": { @@ -163,11 +165,81 @@ Location: /fooTemplates/{templateId2} } ``` -//// TODO show a foo created from this template +The client then uses that template to create a `foo`: +```http +POST /foos/create +{ + "template@odata.bind": "/fooTemplates/{templateId2}" +} + +HTTP/1.1 201 Created +Location: /foos/{fooId2} + +{ + "id": "{fooId2}", + "fizz": { + // fizz properties here + }, + "buzz": { + // buzz properties here + }, + "frob": { + // frob properties here + } +} +``` ### `null` is explicitly specified for `frob` -//// TODO +The client creates a new template specifying `null` for `frob`: +```http +POST /fooTemplates +{ + "fizz": { + // fizz properties here + }, + "buzz": { + // buzz properties here + }, + "frob": null +} + +HTTP/1.1 201 Created +Location: /fooTemplates/{templateId3} + +{ + "id": "{templateId3}", + "fizz": { + // fizz properties here + }, + "buzz": { + // buzz properties here + }, + "frob": null +} +``` + +The client then uses that template to create a `foo`: +```http +POST /foos/create +{ + "template@odata.bind": "/fooTemplates/{templateId3}" +} + +HTTP/1.1 201 Created +Location: /foos/{fooId3} + +{ + "id": "{fooId3}", + "fizz": { + // fizz properties here + }, + "buzz": { + // buzz properties here + }, + "frob": null +} +``` ### no value is specified for `frob` From 86291d9f0ec42871cb7e37a8e235d4d06c3ea326 Mon Sep 17 00:00:00 2001 From: Garrett DeBruin <16618938+corranrogue9@users.noreply.github.com> Date: Thu, 21 Dec 2023 09:27:17 -0800 Subject: [PATCH 23/34] Update entity-template.md --- graph/patterns/entity-template.md | 48 ++++++++++++++++++++++++++++++- 1 file changed, 47 insertions(+), 1 deletion(-) diff --git a/graph/patterns/entity-template.md b/graph/patterns/entity-template.md index 69c4231a..78160d63 100644 --- a/graph/patterns/entity-template.md +++ b/graph/patterns/entity-template.md @@ -243,8 +243,54 @@ Location: /foos/{fooId3} ### no value is specified for `frob` -//// TODO +The client creates a new template without specifying any value for `frob`: +```http +POST /fooTemplates +{ + "fizz": { + // fizz properties here + }, + "buzz": { + // buzz properties here + } +} +HTTP/1.1 201 Created +Location: /fooTemplates/{templateId4} + +{ + "id": "{templateId4}", + "fizz": { + // fizz properties here + }, + "buzz": { + // buzz properties here + }, + "frob@notProvided": true +} +``` + +The client then uses that template to create a `foo`: +```http +POST /foos/create +{ + "template@odata.bind": "/fooTemplates/{templateId4}" +} + +HTTP/1.1 201 Created +Location: /foos/{fooId4} + +{ + "id": "{fooId3}", + "fizz": { + // fizz properties here + }, + "buzz": { + // buzz properties here + }, + "frob": // server-generated default value for frob here +} +``` From 3d73f0f0d012ce6f79f25136d0e119f0af5af889 Mon Sep 17 00:00:00 2001 From: Garrett DeBruin <16618938+corranrogue9@users.noreply.github.com> Date: Thu, 21 Dec 2023 09:27:43 -0800 Subject: [PATCH 24/34] Update entity-template.md --- graph/patterns/entity-template.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/graph/patterns/entity-template.md b/graph/patterns/entity-template.md index 78160d63..83ccf010 100644 --- a/graph/patterns/entity-template.md +++ b/graph/patterns/entity-template.md @@ -189,7 +189,7 @@ Location: /foos/{fooId2} } ``` -### `null` is explicitly specified for `frob` +#### `null` is explicitly specified for `frob` The client creates a new template specifying `null` for `frob`: ```http @@ -241,7 +241,7 @@ Location: /foos/{fooId3} } ``` -### no value is specified for `frob` +#### no value is specified for `frob` The client creates a new template without specifying any value for `frob`: ```http From cd6d35881006d44b86be7c87cefdf762a75b3637 Mon Sep 17 00:00:00 2001 From: Garrett DeBruin <16618938+corranrogue9@users.noreply.github.com> Date: Thu, 21 Dec 2023 09:30:14 -0800 Subject: [PATCH 25/34] Update entity-template.md --- graph/patterns/entity-template.md | 20 +++----------------- 1 file changed, 3 insertions(+), 17 deletions(-) diff --git a/graph/patterns/entity-template.md b/graph/patterns/entity-template.md index 83ccf010..807e37d3 100644 --- a/graph/patterns/entity-template.md +++ b/graph/patterns/entity-template.md @@ -295,28 +295,14 @@ Location: /foos/{fooId4} //// TODO make sure you know how to implement this in webapi - - - - - - - - - - - //// TODO establish a general pattern for actions bound to an entity collection where the actions are different constructor overloads; the "original" overload is still just a post to the collection //// TODO templates are just a new constructor overload ## 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 customers need to create instances of an entity using the same basic outline, but where those instances have their own, individual lifecycle. ## Issues and considerations -TODO if managing templates is more consuming that managing the entities - -## Example - -*Provide a short example from real life.* +Templates for relatively small entities should be avoided. +Generally speaking, managing templates should not be more costly for clients than directly managing the entities themselves. From a2c6e2a33a5370f290d4c96c7465da956e97efc8 Mon Sep 17 00:00:00 2001 From: Garrett DeBruin <16618938+corranrogue9@users.noreply.github.com> Date: Fri, 22 Dec 2023 09:55:02 -0800 Subject: [PATCH 26/34] Update entity-template.md --- graph/patterns/entity-template.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/graph/patterns/entity-template.md b/graph/patterns/entity-template.md index 807e37d3..d70581e3 100644 --- a/graph/patterns/entity-template.md +++ b/graph/patterns/entity-template.md @@ -294,7 +294,7 @@ Location: /foos/{fooId4} -//// TODO make sure you know how to implement this in webapi +//// TODO make sure you know how to implement this in webapi - https://github.com/OData/AspNetCoreOData/tree/corranrogue9/instanceannotation //// TODO establish a general pattern for actions bound to an entity collection where the actions are different constructor overloads; the "original" overload is still just a post to the collection //// TODO templates are just a new constructor overload From 0ed355340fea0d88d993c5d79960df046432837c Mon Sep 17 00:00:00 2001 From: Garrett DeBruin <16618938+corranrogue9@users.noreply.github.com> Date: Mon, 22 Jan 2024 16:05:04 -0800 Subject: [PATCH 27/34] Update entity-template.md --- graph/patterns/entity-template.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/graph/patterns/entity-template.md b/graph/patterns/entity-template.md index d70581e3..9e6ab346 100644 --- a/graph/patterns/entity-template.md +++ b/graph/patterns/entity-template.md @@ -76,7 +76,9 @@ This template can then be used to create a `foo`: ```http POST /foos/create { - "template@odata.bind": "/fooTemplates/{templateId1}" + "template": { + "@id": "/fooTemplates/{templateId1}" + } } HTTP/1.1 201 Created From 9f048ca5f81927e6ce7677b132cff0a4523ae028 Mon Sep 17 00:00:00 2001 From: Garrett DeBruin <16618938+corranrogue9@users.noreply.github.com> Date: Mon, 22 Jan 2024 16:15:04 -0800 Subject: [PATCH 28/34] Update entity-template.md --- graph/patterns/entity-template.md | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/graph/patterns/entity-template.md b/graph/patterns/entity-template.md index 9e6ab346..8046dd1b 100644 --- a/graph/patterns/entity-template.md +++ b/graph/patterns/entity-template.md @@ -95,6 +95,8 @@ Location: /foos/{fooId1} } ``` +You can find an example of how to implement this using OData WebApi [here](https://github.com/OData/AspNetCoreOData/commit/e9422d6a520112c1f1467828bf0eb0c7e46ccff1). + ### Add a new property to an existing entity and update its associated template entity A property `frob` may be added to the `foo` entity: @@ -107,7 +109,7 @@ A property `frob` may be added to the `foo` entity: Likely, clients will want an analogous property on the `fooTemplate`. Because the default value of such a property on `foo` is ambiguous (the default may be `null`, some static value, or a service-generated value only known based on the overall state at runtime), the `fooTemplate` needs a clear way to indicate whether a value was specified for the `frob` property. -This is done with the use of the `notProvided` instance annotation. //// TODO link to docs about instance annotations, and figure out the correct name for "notProvided" +This is done with the use of the `notProvided` instance annotation. `frob` will be defined on `fooTemplate` as usual: ```xml @@ -294,11 +296,7 @@ Location: /foos/{fooId4} } ``` - - -//// TODO make sure you know how to implement this in webapi - https://github.com/OData/AspNetCoreOData/tree/corranrogue9/instanceannotation -//// TODO establish a general pattern for actions bound to an entity collection where the actions are different constructor overloads; the "original" overload is still just a post to the collection -//// TODO templates are just a new constructor overload +You can find an example of how to implement this using OData WebApi [here](https://github.com/OData/AspNetCoreOData/commit/84b23c5f81fecd90b0d8f5ae74292896d22663d0). ## When to use this pattern From bf9212b239f08e4adf9d73f8b0fb0aedee4b75d1 Mon Sep 17 00:00:00 2001 From: Garrett DeBruin <16618938+corranrogue9@users.noreply.github.com> Date: Mon, 22 Jan 2024 16:15:55 -0800 Subject: [PATCH 29/34] Update entity-template.md --- graph/patterns/entity-template.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/graph/patterns/entity-template.md b/graph/patterns/entity-template.md index 8046dd1b..bd7da329 100644 --- a/graph/patterns/entity-template.md +++ b/graph/patterns/entity-template.md @@ -1,3 +1,5 @@ +TODO go through the code TODOs + # Entity template Microsoft Graph API Design Pattern From 6211839ff212facff24e2ba94c085c569575ad81 Mon Sep 17 00:00:00 2001 From: Garrett DeBruin <16618938+corranrogue9@users.noreply.github.com> Date: Mon, 22 Jan 2024 19:14:08 -0800 Subject: [PATCH 30/34] Update entity-template.md --- graph/patterns/entity-template.md | 1 + 1 file changed, 1 insertion(+) diff --git a/graph/patterns/entity-template.md b/graph/patterns/entity-template.md index bd7da329..40ed5609 100644 --- a/graph/patterns/entity-template.md +++ b/graph/patterns/entity-template.md @@ -1,4 +1,5 @@ TODO go through the code TODOs +TODO double check any updates to the CSDL with this branch: https://msazure.visualstudio.com/One/_git/AD-AggregatorService-Workloads/pullrequest/9262077 # Entity template From b08dd4c491f7a3c088e802cbfb8fc6a8357373c3 Mon Sep 17 00:00:00 2001 From: Garrett DeBruin <16618938+corranrogue9@users.noreply.github.com> Date: Mon, 22 Jan 2024 19:14:29 -0800 Subject: [PATCH 31/34] Update entity-template.md --- graph/patterns/entity-template.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/graph/patterns/entity-template.md b/graph/patterns/entity-template.md index 40ed5609..addbac8f 100644 --- a/graph/patterns/entity-template.md +++ b/graph/patterns/entity-template.md @@ -1,5 +1,5 @@ TODO go through the code TODOs -TODO double check any updates to the CSDL with this branch: https://msazure.visualstudio.com/One/_git/AD-AggregatorService-Workloads/pullrequest/9262077 +TODO double check any updates to the CSDL with this branch, then delete the branch: https://msazure.visualstudio.com/One/_git/AD-AggregatorService-Workloads/pullrequest/9262077 # Entity template From 5361919c3a6b8c9e402bb9d22bb73e694ebab0bb Mon Sep 17 00:00:00 2001 From: Garrett DeBruin <16618938+corranrogue9@users.noreply.github.com> Date: Tue, 23 Jan 2024 18:30:16 -0800 Subject: [PATCH 32/34] Update entity-template.md --- graph/patterns/entity-template.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/graph/patterns/entity-template.md b/graph/patterns/entity-template.md index addbac8f..e12bb770 100644 --- a/graph/patterns/entity-template.md +++ b/graph/patterns/entity-template.md @@ -98,7 +98,7 @@ Location: /foos/{fooId1} } ``` -You can find an example of how to implement this using OData WebApi [here](https://github.com/OData/AspNetCoreOData/commit/e9422d6a520112c1f1467828bf0eb0c7e46ccff1). +You can find an example of how to implement this using OData WebApi [here](https://github.com/OData/AspNetCoreOData/commit/d9fa5db0177e1ee8e71a87641ad097dae3ee5e5d). ### Add a new property to an existing entity and update its associated template entity @@ -299,7 +299,7 @@ Location: /foos/{fooId4} } ``` -You can find an example of how to implement this using OData WebApi [here](https://github.com/OData/AspNetCoreOData/commit/84b23c5f81fecd90b0d8f5ae74292896d22663d0). +You can find an example of how to implement this using OData WebApi [here](https://github.com/OData/AspNetCoreOData/commit/cf5583a5fd2c8acedf178df90d6dd6cab9820e62). ## When to use this pattern From d9bfca36b0b75d433035b1c3f8dc3546cbfc0396 Mon Sep 17 00:00:00 2001 From: Garrett DeBruin <16618938+corranrogue9@users.noreply.github.com> Date: Wed, 20 Mar 2024 17:18:08 -0700 Subject: [PATCH 33/34] Update entity-template.md --- graph/patterns/entity-template.md | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/graph/patterns/entity-template.md b/graph/patterns/entity-template.md index e12bb770..4513fc63 100644 --- a/graph/patterns/entity-template.md +++ b/graph/patterns/entity-template.md @@ -46,7 +46,8 @@ a "template" entity is defined for `foo`: An action should also be introduced that will create the `foo` based on the `fooTemplate`: ```xml - + + @@ -77,7 +78,7 @@ Location: /fooTemplates/{templateId1} This template can then be used to create a `foo`: ```http -POST /foos/create +POST /foos/createFromTemplate { "template": { "@id": "/fooTemplates/{templateId1}" @@ -106,7 +107,7 @@ A property `frob` may be added to the `foo` entity: ```xml ... - + ``` @@ -117,7 +118,7 @@ This is done with the use of the `notProvided` instance annotation. ```xml ... - + ``` @@ -174,7 +175,7 @@ Location: /fooTemplates/{templateId2} The client then uses that template to create a `foo`: ```http -POST /foos/create +POST /foos/createFromTemplate { "template@odata.bind": "/fooTemplates/{templateId2}" } @@ -228,7 +229,7 @@ Location: /fooTemplates/{templateId3} The client then uses that template to create a `foo`: ```http -POST /foos/create +POST /foos/createFromTemplate { "template@odata.bind": "/fooTemplates/{templateId3}" } @@ -279,7 +280,7 @@ Location: /fooTemplates/{templateId4} The client then uses that template to create a `foo`: ```http -POST /foos/create +POST /foos/createFromTemplate { "template@odata.bind": "/fooTemplates/{templateId4}" } From 55524cba2f201c7884a4cb99e9f8eb1db7d37e45 Mon Sep 17 00:00:00 2001 From: Garrett DeBruin <16618938+corranrogue9@users.noreply.github.com> Date: Wed, 20 Mar 2024 17:19:55 -0700 Subject: [PATCH 34/34] Update entity-template.md --- graph/patterns/entity-template.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/graph/patterns/entity-template.md b/graph/patterns/entity-template.md index 4513fc63..72d1b14e 100644 --- a/graph/patterns/entity-template.md +++ b/graph/patterns/entity-template.md @@ -1,6 +1,3 @@ -TODO go through the code TODOs -TODO double check any updates to the CSDL with this branch, then delete the branch: https://msazure.visualstudio.com/One/_git/AD-AggregatorService-Workloads/pullrequest/9262077 - # Entity template Microsoft Graph API Design Pattern