Skip to content
This repository has been archived by the owner on Nov 8, 2024. It is now read-only.

Added draft RFC for Read/Write Attributes #15

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open

Added draft RFC for Read/Write Attributes #15

wants to merge 1 commit into from

Conversation

philsturgeon
Copy link

@philsturgeon philsturgeon commented Jun 7, 2016

This RFC proposes the addition of keywords read-only and write-only similar to required, to mark if a particular attribute is read only, write only, or by default: both.

+ created: 1415203908 (number, read-only) - Time stamp

@kylef
Copy link
Member

kylef commented Jun 7, 2016

That's an interesting idea @philsturgeon, would you be able to flesh out the rationale section from the RFC template and add a bit more information regarding how this would work. I'm mostly wondering what read-only actually implies. Does this mean it's set by the server and cannot be sent from a client, or that a client may only send it while creating a resource (read-only)?

For example, I could see a use case where you may want to provide a username for creation, but not for updating. However the created_at and updated_at are completely server side properties which may not be set from the server.

## User [/user]

+ Attributes
    + username: kyle (read-only)
    + `created_at`: `2016-06-07T01:25:22+00:00` (read-only)
    + `updated_at`: `2016-06-07T01:25:22+00:00` (read-only)
    + email

### Update User [PATCH]

+ Request (application/json)
    + Attributes (User)
+ Response 200 (application/json)
    + Attributes (User)

## Create a User [POST /users]

+ Request (application/json)
    + Attributes (User)
+ Response 200 (application/json)
    + Attributes (User)

Did you put any though on how this could evolve with the authentication framework outline in RFC2? I'm thinking it might be nice to express somehow how an read/write attribute may apply differently to different permission scopes for example from RFC5: OAuth2 Scheme.


Currently you can express this in API Blueprint as follows:

## User [/user]

+ Attributes
    + username: kyle (read-only)
    + `created_at`: `2016-06-07T01:25:22+00:00` (read-only)
    + `updated_at`: `2016-06-07T01:25:22+00:00` (read-only)
    + email

### Update User [PATCH]

+ Request (application/json)
    + Attributes
        + email
+ Response 200 (application/json)
    + Attributes (User)

## Create a User [POST /users]

+ Request (application/json)
    + Attributes
        + username
        + email
+ Response 200 (application/json)
    + Attributes (User)

@kylef kylef added the draft label Jun 7, 2016
@kylef
Copy link
Member

kylef commented Jun 7, 2016

One more though I had, did you consider calling it readable and writable to be aligned with optional and nullable attributes?

@philsturgeon
Copy link
Author

philsturgeon commented Jun 7, 2016

Hey @kylef! I like the idea of readable / writable as it is more consistent.

I would like to avoid "username can be edited by certain people", or "only writable on create and not on update" stuff as it's a bit out of scope and getting into the real of domain/business logic and validation.

I'm just trying to outline that some fields can be seen but not provided, which is any server generated value.

People could start overriding these attribute definitions in their action-specific MSON lists if that becomes important to them.

@pksunkara
Copy link
Contributor

pksunkara commented Jun 8, 2016

I'm just trying to outline that some fields can be seen but not provided, which is any server generated value.

@philsturgeon So, what you are saying is that if I define the following:

# User
+ created: 20160601 (readable)

It means, no request body containing the above data structure should provide the created key and the API Blueprint wants to document that. Right?

@philsturgeon
Copy link
Author

Yes indeed. Thinking about it I do wonder if readable is better than read-only, because whilst it is more consistent, it doesn't portray the meaning quite as effectively.

@pksunkara
Copy link
Contributor

I agree. If that is your intention, readable doesn't sound that good.

@philsturgeon
Copy link
Author

@kylef could you help me out here, with a bit of direction?

@zdne
Copy link
Contributor

zdne commented Jul 12, 2016

Thanks @philsturgeon for your RFC proposal!

Here are my thoughts on it. Given following message of the day data structure:

## MotD (object)
- message: `Hello World!` (string)
- updated: `2016-07-12 11:28:26.744662` (string)

And the following resource Message of the Day at /message that affords user with the retrieve and edit actions

# Message of the Day [/message]

## Retrieve [GET]
- Response 200 (application/json)
    - Attributes
        ...

## Edit [PUT]
- Request (application/json)
    - Attributes
        ...

- Response 200 (application/json)
    - Attributes
        ...

You want to introduce a new type attribute that denotes a field that is immutable by an API consumer. Is this correct?

I suspect the motivation is not current MSON inability to achieve this but convenience. Is this correct?

MSON Designer Note

MSON initial release was designed with the minimum possible set of type attributes and keywords. Where we didn't have to we haven't introduced convenience attributes or keywords. While it might not look like, every keyword and attribute has its reason and as such is irreplaceable. I am afraid this is not the case with the readable attribute here. The desired functionality can be achieved use the existing MSON syntax.

For the same reason, I do see the introduction of writeable only as an addition of syntactic sugar.

If introduced, the readable won't be, most likely, used within the Attributes section directly, as in:

## Edit [PUT]
- Request (application/json)
    - Attributes
        - updated (string, readable)

- Response 200 (application/json)
    - Attributes
        - updated (string, readable)

but only in general data structures description. Furthermore the way you have designed it you imply that the readable type modifier has the same semantic meaning in the scope of every action. The proposed solution couldn't work in scenarios where in one actions-context an attribute is readable while in another action-context it isn't.

These are the reasons why I do not feel this proposal should make it into the MSON specification. Furthermore I'd suggest to separate concerns when designing API data structures. Some data structures are truly resources while others could be API/implementation-specific decorators (timestamps, pages etc.)

How to deal with immutable fields

Where needed, I'd suggest to actually split a data structure in mutable and immutable parts. This should be considered especially where the media type of an HTTP request is different to the one of HTTP response and / or the data structure representation. Consider an API that is producing application/hal+json, it most likely does not take it on its input but instead it consumes an other, probably custom, media type.

# Message of the Day [/message]

## Retrieve [GET]
- Response 200 (application/json)
    - Attributes (Message)
        - Include API Resource Decorator


## Edit [PUT]
- Request (appliction/json)
    - Attributes (Message)

- Response 200 (application/json)
    - Attributes (Message)
        - Include API Resource Decorator

# Data Structures

## Message (object)
- message: `Hello World!` (string)

## API Resource Decorator (object)
- updated: `2016-07-12 11:28:26.744662` (string)

OSS

Note this is an open source project, and us such I leave this subject to the judgement of its maintainers. I can see how introducing readonly attribute (but no other) makes writing MSONs easier in scenarios where you do not want to bother with splitting the data structure or rewriting a subset of its attributes. I am naturally afraid of the consequences and misuses of new features (especially when it is about convenience) but that shouldn't prevent introduction of those that community really wants.

Hope that makes sense.

@pksunkara
Copy link
Contributor

According to this comment and the one after that, I agree with @zdne that these attributes will be used only in data structures and will only affect the rendering of these data structures depending on whether they are used in Response or Request. So, basically this would not be an MSON feature because it needs the context of sections from API Blueprint.

@philsturgeon
Copy link
Author

philsturgeon commented Jul 20, 2016 via email

@zdne
Copy link
Contributor

zdne commented Jul 26, 2016

@philsturgeon

Ok, so if they’re not MSON in general, is this still a useful feature? I’d say so.

Per my previous comment, this is a data-model abstraction vs. convenience question:


To split an MSON structure in two structures (what is received from a server vs. what is sent in a request)

-- OR --

Or to have one MSON structure and only flag fields that are mutable in a request.


Do I understand your motives correctly or is there something else I'm overlooking?

@philsturgeon
Copy link
Author

Sorry for big delays, there was a bit of a disconnect and I really did not understand the discussion. I re-read a few times to no avail, but I had a go and today it makes sense. No idea why it didn't before but hey.

If introduced, the readable won't be, most likely, used within the Attributes section directly, as in [snip] but only in general data structures description.

Yes, totally. This was the intent. You certainly would not need to use readable/writable inline for req/resp because you would just omit the field. Easy.

This is drastically more useful in two scenarios:

At my previous employer we used to playce Attributes in the group, because we had JSON-API and you folks had not got the nested attribute displays done yet. So we had:

# Group Message

+ Attributes (MotD)

# Message of the Day [/message]

## Retrieve [GET]
- Response 200 (application/json)
    - Attributes (object)
        - messages (MotD)

# Data Structures

## MotD (object)
- message: `Hello World!` (string)
- updated: `2016-07-12 11:28:26.744662` (string)

Having that list of attributes there was great for a quick reference to what actual fields were going to be involved inside the JSON-API top level element, as I said at the time it was just showing messages in the Attributes table.

Now nesting attributes are a thing, we have two different objects, Message Create and Message Full and no longer place Attributes under the Group. That approach basically renders this proposed feature useless, but comes with its own set of problems.

You can Include Message Create inside the data structure of Message Full, but when you have fields that can be on a create but are not updatable you end up just copying and pasting stuff. Composition of fields is an option but just starts to become a bit of a headache with larger data structures.

This convenience feature would potentially help simplify that process, and would allow for Group Attributes to clearly set out "here are all the fields and here are the ones you can update".

Furthermore the way you have designed it you imply that the readable type modifier has the same semantic meaning in the scope of every action. The proposed solution couldn't work in scenarios where in one actions-context an attribute is readable while in another action-context it isn't.

Yeah perfect! I don't know of a use case where this would be a thing, but in those scenarios the answer would be "dont use this". By the same token you could say required is restrictive because its required in one action and optional in another.

This idea is not entirely fleshed out and I almost talked myself out of it writing this, but I feel like there is something here, unless I just start using composition for everything. Good thing I'm using Hercule! 😅

@pksunkara
Copy link
Contributor

pksunkara commented Mar 24, 2017

@philsturgeon I have a given a bit of thought on this recently. I am thinking of something like the following:

  • non-creatable - This denotes that a property will never be accepted from the API Consumer
  • non-patchable - This denotes that the property will be accepted from the API Consumer only when the resource is being created.

By default, everything is patchable and creatable.

I think this captures the intent of this RFC. And yes, these are convenience type attributes for API Blueprint and not an MSON feature. But, we do need to allow arbitrary type attributes in MSON.

@philsturgeon
Copy link
Author

philsturgeon commented Mar 24, 2017 via email

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants