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

Schema Difference Between Create and Update in Put Operations #307

Closed
devigned opened this issue May 20, 2016 · 8 comments
Closed

Schema Difference Between Create and Update in Put Operations #307

devigned opened this issue May 20, 2016 · 8 comments

Comments

@devigned
Copy link
Member

This issue is related to issue #275.

Azure resource creates and updates are accomplished through HTTP PUTs. HTTP PUTs should function the same way in create as they do in update. Unfortunately, create operations don't always have the same semantics as an update.

I will use Azure Resource Group creation and update for an example. If I create a Resource Group with a location of westus, the resource group will be created with that location. If I then try to update the Resource Group to a location of eastus, I will receive a 409 status code. The location can only be set on create, but can't be updated. Clearly, this leads consumers of our generated code down a path of failure. We should have two different methods here, one for create and one for update.

The main issue with describing this in the spec is that create and update are both PUTs to the same URI. Thus, there is no way in Swagger to specify this type of behavior for parameters through separating this into a create and update operation with two separate schema.

Possible solutions:

  1. We add any PUT which requires different schema for Create and Update for the same URI / Verb combination to x-ms-paths so that we can define two different operations for the same URI / Verb combination.
  2. We add an extension to the original put that would specify the keys of the schema we'd like to omit from the update. My supposition here is that the update will always have a subset of the create schema.
  3. Something else. Please suggest.

request for comment: @Azure/adx-sdk-team, @selvasingh

@darrelmiller
Copy link
Member

darrelmiller commented May 21, 2016

One solution to the problem of having a resource with characteristics that you don't want to change after it has been created is to make the characteristic part of the resource's identify. For the case of location this would seem very natural.

 .../eastus/resourcegroups/mygroup

With the location in the resource identity it becomes obvious that the location cannot be changed with out deleting and re-creating a new resource in the new location.
I don't know how feasible it is for you to make URI structure changes. I get the impression that the client libraries have a fair amount of dependency on URI structure and therefore this idea may be a complete non-starter for you. Opaque URLs FTW ;-)

Not all properties that are write-once make sense to be part of the resource identity. Another way of modelling this could be with a builder/factory resource. It is common in HTTP to POST to a factory resource to create a 'child' resource. However, as I understand it, you want to the idempotency benefits of PUT, which is cool. So, perhaps you could create the notion of a builder resource whose sole purpose is to create another resource. It can be completely transient so that one you PUT to the builder resource, all it does is create the actual resource, return 201 and a Location header to the actual created resource. This would allow you to define a different schema for the builder resource than the actual created resource.

PUT .../VirtualMachines/my-machine/builder HTTP/1.1

{
    "some-initialize-only-prop" : "xyz",
    "read-write-prop" : "abc"
}

=> 
201 Created
Location: .../VirtualMachines/my-machine

This would allow the schema for the builder resource be different than the created resource. There would be no need to define the GET method for the builder resource and could be mapped to a CreateResource method in the client library. Calling CreateResource twice for the same resource name would need to return either a 400 or 409.

Caveat! I've never actually implemented this pattern before, but it sounds feasible :-)

@devigned
Copy link
Member Author

@darrelmiller I think the ship has sailed on the URIs, though I really like having location as part of the URI.

I think we may end up needing to solve this through an extension which will allow us to generate the client with an update and a create having two different schemas for the PUT. Basically, this will give us a create and an update operation on the generated client which maps to put.

We brought the conversation up for v3 b/c I'd rather do this in a more community accepted way.

/cc @rjmax for review and possibly to standardize in the future.

@rjmax
Copy link

rjmax commented May 23, 2016

I don't think we can place any immutable property into the URI - let's take another example of an immutable property - a VM's osType. It would seem peculiar to place such an attribute in the URI, wouldn't you think? When you combine this with several immutable attributes for each resource type, you'd end up with pretty unwieldy URIs.

@devigned - while we probably have properties which are write once, they should still be accepted in subsequent PUTs as long as they haven't changed. If this isn't the case, we should triage those issues on a case-by-case basis.

@devigned
Copy link
Member Author

@rjmax you are correct. It doesn't scale out as we have additional immutable properties.

I don't think the immutable properties are necessarily wrong for the API, it just makes it difficult to push consumers down the path of success in our generated clients if we expose immutable properties without any warning of their behavior.

Having the immutable properties will likely lead us to having a create method and an update method. I would much prefer to have a simple PUT (create_or_update) so the client doesn't need to worry about the state on the server rather than separate create and update methods. I think I'd rather see separate create and update methods with strong typing (update request parameters type doesn't contain immutable properties) rather than a single create_or_update that exposes every parameter regardless of it's PUT semantics.

@darrelmiller
Copy link
Member

darrelmiller commented May 23, 2016

@rjmax Completely agree, not all write-once properties make sense to be part of resource identity.

Would it be feasible to create a secondary builder resource to accept write-once properties during the creation of the primary resource?

@fearthecowboy
Copy link
Member

@devigned I've been thinking about this a bit..

Are you thinking that we should generate two methods for a given method/URI -- ie, separate create and update methods that actually end up calling the same target? .. AFAICS, that'd be a stretch when interpreting the swagger spec. (I don't see how to have multiple operations with the same ,method/URI).

Otherwise, we'd have to change something ... (either URI or method)...

@devigned
Copy link
Member Author

@fearthecowboy I'm suggesting that we should differentiate the update and the create for users if they have different behaviors. Perhaps, that could be done by having an extension that marks properties as write-once. Perhaps, that could be done by using x-ms-paths to define overlapping URI / Verb combinations.

@kirthik
Copy link
Contributor

kirthik commented Feb 10, 2017

Closing due to inactivity

@kirthik kirthik closed this as completed Feb 10, 2017
blueww pushed a commit to blueww/azure-rest-api-specs that referenced this issue Dec 8, 2017
Adding Managed Server Security Alert Policies API
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants