How to reference another scope and also describe its usage in context?

184 views
Skip to first unread message

Tadhg Pearson

unread,
Jul 8, 2016, 11:41:38 AM7/8/16
to JSON Schema
I'm using JSON Schema to document the response for a hotel availability search.

There are various prices and rates in the response. For example - to help the developer display the output, each hotel result provides the lowest total price for the dates requested, as well as the minimum daily rate.

The JSON response looks something like this
      "property_name": "Winthrop Beach Inn And Suites Boston Logan",
     
"total_price": {
       
"amount": "129.00",
       
"currency": "USD"
     
},
     
"min_daily_rate": {
       
"amount": "115.00",
       
"currency": "USD"
     
},
      "location": {
       
"latitude": 42.37655,
       
"longitude": -70.97375
     
},


Both of these elements are amount objects, and they are described by an amount schema, which reads like this

  Amount:
     required
:
       
- currency
       
- amount
     description
: "A monetary amount with a price and a currency"
     properties
:
      currency
:
        type
: string
        description
: "ISO 4217 currency code applicable to this amount. For example: EUR."
      amount
:
        type
: string
        description
: "Total amount in the given currency, formatted appropriately. For example: 194.99"

You can see the swagger specification here and a sample response here for a more complete picture.


The amount object is quite self-explanatory, but each of these amounts have different meanings depending on their context which is not obvious. What's the difference between the total_price and the minimum_daily_rate, for example?
I'd like to be able to document this context for the user. Instinctively I wrote this:

      total_price:
        description
: The lowest price of a stay, from the given check in date to the given check out date.
        $ref
: "#/definitions/Amount"
      min_daily_rate
:
        description
: The lowest price per day that the hotel offers between the given check-in and check-out dates. Extra taxes may apply to this rate.
        $ref
: "#/definitions/Amount"  

... but, of course, this doesn't work, because the $ref changes the scope, so the description - and all other elements - are ignored. There doesn't seem to be a way to refer to the object and also describe the way in which it is used.

How can I document the context of each amount, without having to repeating all the other fields of the amount object?

Tadhg Pearson

unread,
Jul 12, 2016, 2:40:38 PM7/12/16
to JSON Schema
Hmm... the more I read the schema specification, the more I come to the conclusion is that this simply isn't, and can't, be supported :(

http://json-schema.org/latest/json-schema-core.html#anchor25

Clearly $ref just dereferences the whole block

hha1%cor...@gtempaccount.com

unread,
Sep 6, 2016, 4:12:40 AM9/6/16
to JSON Schema
I brought up this use case in the GitHub issue on $merge and $patch a few days ago:

The most clear and concise way to do this is to merge (or patch) your $ref with a schema fragment that is just the description field.  Then you can re-use the type with varying descriptions matching each local purpose.

Of course $merge and $patch are not part of v4, and there is a good discussion going on in that GitHub issue about how they should or shouldn't fit with v5 or json-schema in general.

It looks like ($merge uses json-merge-patch and $patch uses json-patch):


    total_price
:
        $merge:
            source
: {$ref: "#/definitions/Amount"}
           
with:

                description
: The lowest price of a stay, from the given check in date to the given check outdate.

    min_daily_rate
:
        $merge
:
            source
{$ref: "#/definitions/Amount"}
            with:

                description
: The lowest price per day that the hotel offers between the given check-in and check-out dates. Extra taxes may apply to this rate.

Tadhg Pearson

unread,
Sep 6, 2016, 2:15:48 PM9/6/16
to JSON Schema
Thanks for the info Henry.

I like the concept of this, and I also like the fact that you took the existing element and aggregated it, rather than building some some unclear hidden precedence into the specification.

The only change I would suggest is: to me the words merge and patch imply that the user gets a choice in how the two elements are merged together to create an output. But in fact, this is not the case. The specification provides a precedence, and you're overwriting or replacing some element of the source reference with your provided value. So I would choose a word like replace or substitute instead.

A minor detail for, what I think, is a great suggestion :)

Henry Andrews

unread,
Sep 7, 2016, 1:07:06 AM9/7/16
to JSON Schema
[Moderators- I replied earlier from the wrong email address so it went into moderation- feel free to delete.  Or, I apologize for the double post]

Hi Tadhg,

The "merge" and "patch" keywords indicate that the "with" value is conforms to the JSON Merge Patch RFC or the JSON Patch RFC, respectively.  So it actually does indicate a choice- JSON Merge Patch pretty much just splats the "with" JSON document on top of the source, while a JSON Patch "with" is a series of instructions describing how to modify the source.

I should also give credit where credit is due:  This is not my proposal, but one that was made several years ago (I think by Francois?) that we then used extensively at my last job.

thanks,
-henry

he...@cloudflare.com

unread,
Sep 7, 2016, 4:07:03 AM9/7/16
to JSON Schema
Thanks, Tadhg.  The "merge" and "patch" words actually *do* indicate a choice in how the combination occurs.  When you say "merge" it does as close to an intuitive merge of the two JSON fragments, in the object property sense, that it can.  When you say "patch" it takes a different (still JSON-based) format that is interpreted as a series of instructions on how to modify the resource.

"merge" (using JSON Merge Patch ) is more intuitive but has significant limits (although I've not yet found a case that hits them).
"patch" (using JSON Patch ) can perform any operation, including asserting preconditions, but is a little less intuitive to read.

The "merge" vs "patch" terms were chosen to match those two JSON patching RFCs.  The "with" of a $merge should be a valid "application/merge-patch+json" instance, while the "with" of a $patch should be a valid "application/patch+json" instance.

    To give credit where credit is due, these are not my proposals :-)  Someone (Francois?) came up with them several years ago and I used $merge extensively at my last job.

thanks,
-henry
Reply all
Reply to author
Forward
0 new messages