raml-spec
raml-spec copied to clipboard
Define 'readonly', 'writeonly' attributes for DataType parameters
Is It any way how define readonly writeonly parameters in Models?
Basic life example is Model that have id field that included it instance representation, but should excluded from PUT and PATCH requests.
I have the same. Want to indicate
- attributes which should be excluded from PUT and PATCH (readonly)
- attributes which should be excluded from GET (writeonly)
Ideally I can also indicate readoptional, writeoptional, createoptional
I also would like to see a readonly facet for a property declaration.
I already return to Swagger, so it is not very important for me more. Issues in RAML closing so "fast", so, thank you, no need more.
@Skorpyon I am sorry that you feel that way! I hope you understand that these issues can't be closed fast. There is an entire life cycle in between. As an example, between Swagger 2.0 and OAS 3.0 was a very long time as well.
But I understand your decision.
Is there any workaround for this by now?
I have the same question, I've posted a question on the RAML forum this is a bit wider in scope, but stems from this issue: https://forum.raml.org/t/the-state-of-raml/2149
I am not sure if this will ever be part of the RAML spec but to be clear, the spec already provides for a distinction between properties that are readable and properties that are writable.
This is a blog post that explains how it works: https://medium.com/raml-api/using-raml-inheritance-to-design-better-schemas-9ce75155df7c
The bottom line is that RAML has a powerful type system that can be leveraged to re-use schemas or pieces of schemas across requests and responses. IMHO, this makes for a far more readable API definition because as a human, I can tell at first glance which properties any given request or response takes or returns. And this, without having to think whether I am in a "read" or "write" context.
Although I tend to agree with Jonathan that through inheritance you are able to reflect those needs, I think inlining properties might not work for every case and will probably introduce a lot of repetitive code. RAML was designed to minimize that.
For example, assume you have more than just the id field that needs to be put for every GET method. Inlining would mean that you need to put these properties in each, like that:
#%RAML 1.0
title: Invoice API
mediaType: application/json
types:
Invoice:
properties:
amount:
type: number
minimum: 0
billTo:
/invoices:
get:
responses:
200:
body:
type: Invoice
properties:
id: number
bla: string
blabla: string
post:
body:
type: Invoice
/x:
get:
responses:
200:
body:
type: Invoice
properties:
id: number
bla: string
blabla: string
/y:
get:
responses:
200:
body:
type: Invoice
properties:
id: number
bla: string
blabla: string
This is very common.
Now, assume you need to add a new property. Furthermore, how can you make sure to have this really added to all GET methods in your entire API document?
One option might be to move out stuff that is different in a specific method into its own type and inherit from a base type. But I am not sure if that's the best solution either.
Only my 2 cents on this topic. :)
Otherwise, Jonathan is right of course.
@sichvoge Did you know you can inherit from multiple types in RAML?
Using your example, you could do this:
#%RAML 1.0
title: Invoice API
mediaType: application/json
types:
BlaObject:
properties:
id: number
bla: string
blabla: string
Invoice:
properties:
amount:
type: number
minimum: 0
billTo:
/invoices:
get:
responses:
200:
body:
type: [ Invoice, BlaObject ]
post:
body:
type: Invoice
/x:
get:
responses:
200:
body:
type: [ Invoice, BlaObject ]
/y:
get:
responses:
200:
body:
type: [ Invoice, BlaObject ]
Note that I placed BlaObject after Invoice because I want the fields of BlaObject to appear before the fields of Invoice. I don't know why it's reversed like this, but it was (at least using raml2html).
Read more about multiple inheritance in the docs.
Hi @Dschee, thanks for the note and yes I know that very well. Have been in the team writing the spec ;)
The above serve as workarounds, but there's an added complexity here. If you go down the path of in-lining additions to the types in the endpoints, you end up with garbage when you generate code, as there is no name associated with the type you are dynamically creating on the fly. The end result is poor usability for your end users. Additionally, the fields only show up in the API Endpoint, not in the type, if you are just viewing the type. Given the above example, if I look at the Invoice type, I don't see all properties that are associated with an invoice, as some are type specific.
On the other hand, if I create types for all of these possible combinations, you end up with "type pollution". There are too many types that are too similar to each other and become difficult to ensure you are using the proper ones.
Finally, if you are a provider of APIs, then you run in to the problem that you may be creating APIs for users to extend, in which case, defining a read only property at the base type level a) gives you the ability to ensure it is added in all appropriate end points and b) gives you an opportunity to validate customer extensions of your API.
FWIW: a better possible implementation would be to have additional properties on a property, similar to min/max, that would restrict the HTTP methods it would be allowed under, or the ability to override and mask a set of properties in an endpoint.
Actually, another use case for this requirement. Having properties that are defined as immutable and computed. Immutable properties are properties that, once set, cannot be modified. An example of this might be a type enum, where a type would be incompatible with other types so once set, the resouce cannot be changed to a different type of resource. We have this for coupon codes in our system. We have two variants: one where the user supplies the coupon codes, and another where the supply a prefix and a number and the system generates the codes. When the coupon resource is created, the user specifies the type, but due to the different properties and configurations for each type, the user is not permitted to change it.
A computed property is essentially the same as read only one. It would never be allowed in a body, but can always show up in a response. An example of this might be a computed total, or metadata information recorded onto to the resource by the endpoint to identify who made a change and when