Join GitHub today
writeOnly field #425
@adamaltman @slavcodev The idea mentioned by @casualjim (and @webron) is to have two schemas, one for the "write" use case, the other one for the read one, which are referenced by the operations (in parameter or response definition). In order to duplicate less code, you can have a third one with the fields which are common for both read and write, and then refer to this with an allOf reference. Using
definitions: CommonExample: type: object properties: readAndWrite: type: string ReadExample: allOf: - $ref: '#/definitions/CommonExample' - type: object properties: readOnlyProperty: type: string WriteExample: allOf: - $ref: '#/definitions/CommonExample' - type: object properties: writeOnlyProperty: type: string paths: /example put: parameters: - in: body required: true schema: $ref: '#/definitions/WriteExample' ... get: ... responses: '200': schema: $ref: '#/definitions/ReadExample'
referenced this issue
May 9, 2016
I'm curious what the guidance would be if you have a PUT that has slightly different semantics between create and update. I've described a scenarios we are running into here: Azure/azure-rest-api-specs#307.
tldr; On create (PUT to URI x), a body parameter can be set, but on an update (PUT to URI x) the same body parameter can't be changed. Basically, we'd need have a slightly different schema for the update semantics than the create, but URIs must be unique.
Sigh. Standard is use POST for create and PATCH/PUT for update.
Really depends on the schema that should get returned in the GET. If the schema object doesn't need that field, just exclude it from the PUT call. If that field is part of the schema, don't use PUT, use PATCH and specify which fields are required.
@wparad Could you point me to the standard you are referring? My reading of RFC 7231, which defines HTTP semantics, is that both POST and PUT are valid ways of creating resources. The difference being whether you know the URL of the new resource in advance and whether you wish to make the creation idempotent.
@devigned Faced with your scenario I would be tempted to keep the same schema for both scenarios. Conceptually it is the same resource you are dealing with, just with different constraints based on its state. The same happens with resources that have status fields where only certain transitions are allowed. JSON Schema can only describe so much. Trying to return different schemas based on the current state is a slippery slope to a whole whackload of complexity. If you really, really wanted to have two different schemas then I would recommend creating two distinct resources, one for creating and one for updating, but that's a bit weird too.
With PUT operations there are many challenging scenarios when it comes to data elements that are impacted by server logic. Sometimes properties of a resource are generated by the server e.g. LastModifiedDate, links. It is a common question as to whether these should be included in a PUT request as they are not modifiable by the client. As I understand it, the "complete replacement" semantics of PUT can be interpreted fairly liberally and I tend to use the mantra of "completely replace everything that makes sense".
If a client were to try and change the "location" of resource, when that characteristic is something that can only be changed at the point of creation, I think you have two choices. You can 401 the request and say that you can't change that value, or you can just ignore invalid property, and process the rest of the changes. You could even do something crazy like return a Warning header to indicate that the change to location was ignored. Using the Prefer header with the strict/lenient property, you can even allow the client to choose which behaviour to allow.
If you had the luxury of changing the URL structure you could make the location part of the URL which would prevent this scenario from ever occurring because there is no concept of renaming a resource. You would be forced to delete and recreate it to move it to a new location, which is consistent with the actual implementation behaviour.
@darrelmiller (from RFC 7231)
But even applied to the same resource, different outcomes with the same resource is ridiculous.
4.2.2 Paragraph 4
In your case since the subsequent calls are required to have different representations depending on the already known existence of the resource.
I can see headers being different between requests of the nature which use
I think you figured out the jist of all of this in your response to Microsoft asinine api you mentioned in the Azure link.
An alternative approach I would take would be to create a
@wparad I'm not exactly sure what you are trying to say here, because, by definition, resources vary over time, so different outcomes from the same resource is the natural behaviour. Resources are not stateless.
Fielding's dissertation says:
Being conceptually equivalent allows for a fairly wide variation of the representations.
I think the desire to have different schemas is a strong indication that there should really be two different resources, as you suggested with
I don't think we need to resort to making derogatory comments about APIs that people are building. I think the specific API is struggling with a fairly common problem, but MSFT have the challenge of trying to define metadata to drive tooling for a very large API surface area that is built by a large number of teams.
Personally, I haven't seen any violation of REST constraints or spec violation.
@darrelmiller, the response in the associated issue in our REST specs was greatly helpful. I wish we had the URI structure you described. It would have made things much easier.
Unfortunately, the ship has sailed on the versions of the APIs affected by this behavior. We may change future versions, but I still need to model these versions. I'd like to do that in the most community accepted way possible. If that is simply describing the schema and adding more information to the description, then that is what we will do.
We'd also like to provided generated clients with the best possible experience, thus we may need to introduce an extension to allow us to generate a create and an update method using the same verb / uri combination. As mentioned above, we should also incorporate some ETAG values as well to better describe / ensure this behavior of the client / API, but without the separated schema, the generated client will still push the consumer down the path of failure. If we make the extension, then I think we'd need to incorporate a way to specify the two schemas.
Thanks all - perhaps a bit more context would be helpful. In the Azure API sets, we see that attributes generally follow one of four patterns:
In the case of #1, let's take the case of a VM password. We need the user to set it, but don't want to return the password back to the client. It would seem peculiar to model the password as a separate resource, since the password is of no standalone utility - its benefit is only in the context of that particular resource.