Skip to content

Should "readOnly" (and "writeOnly") be an array like "required"? #364

Closed
@handrews

Description

@handrews

In the discussions for "deprecated", @awwright brought up that rather than make it a boolean in subschemas, it probably makes more sense to follow the pattern of "required" and make it an array or object alongside of "properties". Similar to #117 ("patternRequired") we would need an analogous "patternReadOnly" (and "additionalReadOnly"?)

Despite the likely need to add separate pattern/additional support, it feels like we should have a consistent design pattern of either specifying these things at the object level, or at the subschema level. Having worked with object level "required" for several years, I feel that it is the better approach.

Activity

added this to the draft-07 (wright-*-02) milestone on Aug 22, 2017
handrews

handrews commented on Aug 31, 2017

@handrews
ContributorAuthor

I just thought of a pretty compelling reason to move "readOnly" to an array keyword at the object levell:

Validation schemas fundamentally describe a type, in the form of an acceptable set of values. "readOnly" not only does not impact that, but is highly context-dependent. It is likely to vary for the same type depending on where and how it is used.

This is part of why "readOnly" is given as a justification for "$use". With "allOf", it's not clear how to turn read-only-ness off. If any branch is of an "allOf" is read-only, then the result would have to be read-only.

Making "readOnly" an array removes that problem, and removes the most substantial justification (for me) when it comes to "$use". Letting applications decide how to handle conflicting titles, descriptions, and even defaults is at least plausible. But there was no other way I could think of to handle "readOnly" and re-use. Except now this.

handrews

handrews commented on Aug 31, 2017

@handrews
ContributorAuthor

@geemus this would affect PRMD if you were to move it to (or add support for) draft-07.

jdesrosiers

jdesrosiers commented on Sep 3, 2017

@jdesrosiers
Member

This exact thing occurred to me recently as well while writing hyper-schemas. I think making readOnly a single array like required would be nice.

However, there is one use case I would loose. I sometimes use readOnly at the top level of a hyper-schema to indicate to a client that the entire resource is managed by the server. The client would know that it shouldn't expect any requests that modifies the resource to be successful. I'm willing to lose this use case in order to make the more general case easier to work with.

handrews

handrews commented on Sep 3, 2017

@handrews
ContributorAuthor

@jdesrosiers

I sometimes use readOnly at the top level of a hyper-schema to indicate to a client that the entire resource is managed by the server.

This use case occurred to me, but I think in most cases it is better handled at the link level (including "self" links) with "targetHints" #383. For HTTP, that would be {"targetHints": {"allow": ["GET"]}} or similar.

Recommending a hyper-schema approach while we're moving readOnly to annotation/validation is a bit odd, so there is a gap still left that a readOnly array would not cover either.

I've also considered the unusual but possible case of making some but not all array elements read-only. This would mostly be fore the tuple form of items. Should the readOnly array allow integers when applied to an array instance? Obviously, to make the entire array read-only, one would apply readOnly to its parent property.

I still like this idea, but there are definitely some odd corner cases to smooth out.

geemus

geemus commented on Sep 5, 2017

@geemus
Collaborator

@handrews sounds reasonable, thanks for the heads up.

handrews

handrews commented on Sep 27, 2017

@handrews
ContributorAuthor

See also PR #424 which delves more into the nature of annotation keywords. It might help us decide which way to go on this (although I'm still waffling back and forth myself for readOnly).

10 remaining items

brabeji

brabeji commented on Jan 15, 2018

@brabeji

I've stumbled upon a rather practical issue. We are trying to do:

{ $ref: '#/definitions/Foo', readOnly: true }

where readOnly will get stripped when the pointer is resolved.

... make both a read-only and a read-write re-usable schemas.

Do you mean this?

{ allOf: [ { $ref: '#/definitions/Foo' }, { readOnly: true } ] }

Thanks!

dlax

dlax commented on Jan 15, 2018

@dlax
Member
handrews

handrews commented on Jan 16, 2018

@handrews
ContributorAuthor

@brabeji this will likely be addressed in draft-08 via #523.

jugaadi

jugaadi commented on Apr 27, 2022

@jugaadi

What would be the recommended way to handle readOnly with allOf?

We would like to make status field in the below given data readOnly for POST requests. Right now, we're creating post specific schemas like given below. A readOnly array can handle it in a better way.

Example:

{
  "user": {
    "type": "object",
    "properties": {
      "name": {
        "type": "string"
      },
      "email": {
        "type": "string",
        "format": "email"
      },
      "status": {
        "type": "string",
        "enum": ["active", "inactive"]
      }
    }
  },
  "user-post-request": {
    "allOf": [{
        "$ref": "#/user"
      },
      {
        "status": false
      }
    ]
  }
}
karenetheridge

karenetheridge commented on Apr 27, 2022

@karenetheridge
Member

@jugaadi I don't see readOnly anywhere in your example schema, so I'm not sure what you are wanting to happen?

readOnly generates an annotation, and recommended semantics for combining them from multiple schema locations is documented in the specification here: https://json-schema.org/draft/2020-12/json-schema-validation.html#rfc.section.9.4

jugaadi

jugaadi commented on Apr 28, 2022

@jugaadi

@karenetheridge Sorry for not being more clear. The example is how Im solving it now i.e by modeling request and response
as two separate schemas and skipping the fields(status: false) directly in the sub-schema. If I had readOnly as an array, I could have simply put the following:

"user-post": {
  "allOf": [{
      "$ref": "#/user"
    },
    {
      "type": "object",
      "readOnly": ["status"]
    }
  ]
}
karenetheridge

karenetheridge commented on Apr 28, 2022

@karenetheridge
Member

Well technically, you could do this:

"user-post": {
  "$ref": "#/user",
  "type": "object",
  "readOnly": ["status"]
}

The problem with moving readOnly up to the object level rather than at the property level is that you are assuming the keyword will only be used for object properties. How will we indicate that a particular array item is to be readOnly, or an individual null, boolean, number or string? Having the keyword right at the position of the target data achieves that, for all data types. Using a property name as the keyword value does not.

gregsdennis

gregsdennis commented on Apr 28, 2022

@gregsdennis
Member

How will we indicate that a particular array item is to be readOnly

Or... how would we differentiate between an array being read-only vs the items within it being read-only?

awwright

awwright commented on Apr 28, 2022

@awwright
Member

(I feel like I commented on this elsewhere but I can't find it...) The array form of "required" was only necessary because it needs to be accessible to the validator when said property does not exist.

For "readOnly", the only time it's going to be accessed is when the property exists: If a user creates the property while preparing it for submission, they would immediately be able to see that it's read-only (from the generated annotation).

I would think this ought to be sufficient:

// ...
"user-post": {
  "$ref": "#/user",
  "type": "object",
  "properties": {
    "status": {"readOnly": true},
  }
}

But maybe this is impractical, or there's another use for "readOnly" where this logic isn't applicable. Is this the case?

gregsdennis

gregsdennis commented on Apr 29, 2022

@gregsdennis
Member

For "readOnly", the only time it's going to be accessed is when the property exists

C# (and likely other languages) have read-only types built in.

https://devblogs.microsoft.com/premier-developer/the-in-modifier-and-the-readonly-structs-in-c/

https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/record

If you're using schema to model types, this can be important to have outside of properties.

awwright

awwright commented on Apr 29, 2022

@awwright
Member

If you're using schema to model types, this can be important to have outside of properties.

What about keywords like "type"? Does the same logic apply?

If you're using this to model types, then what you're doing is a static analysis of the entire schema, so you can still see "X property is going to be a readonly string, max 20 characters".

jugaadi

jugaadi commented on Apr 29, 2022

@jugaadi
"user-post": {
  "$ref": "#/user",
  "type": "object",
  "properties": {
    "status": {"readOnly": true},
  }
}

@awwright In the above case, is it safe to assume that the rest of the constraints/vocabularies that are applicable for status field would be inherited from "$ref": "#/user" and other subschemas in allOf?

awwright

awwright commented on Apr 29, 2022

@awwright
Member

@jugaadi Yes, all the keywords will be used to validate the property. I suggest, if in doubt, run a few experiments to get a feel for how it works.

jugaadi

jugaadi commented on Apr 29, 2022

@jugaadi

Thanks @awwright @gregsdennis @karenetheridge

Skipping the fields instead of depending on annotations seem to be a better solution for my problem since it does not depend on the owning authority's implementation choice to ignore or reject. Any choice would have a bearing on our API versioning strategy.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

      Development

      No branches or pull requests

        Participants

        @geemus@karenetheridge@awwright@jdesrosiers@dlax

        Issue actions

          Should "readOnly" (and "writeOnly") be an array like "required"? · Issue #364 · json-schema-org/json-schema-spec