Subject: [netmod] YANG unions in JSON

From: Martin Bjorklund <[email-masked]>
Date: Wed, 27 Aug 2014 22:19:30 +0200 (CEST)

Hi,

In the current json draft, a value of type 'union' is encoded in the
same way as the "active" member type.  For example, with:

   leaf foo {
     type union {
       type int32;
       type string;
     }
   }

the leaf might be encoded as:

   "foo": 42

Now, suppose we use json to set this leaf like this:

   "foo": "4668"

If we the read the value back, what do we get?  Probably "4668".

But if we instead set the value over xml:

  <foo>4668</foo>

we will then get back:

   "foo": 4668

over json.

What happens if leaf foo is the key in a list - can we create two list
instances with key:

   "foo": 4668

and:

   "foo": "4668"

at the same time?

It seems the simplest solution would be to say that unions are encoded
as strings in json.

/martin

---

From: Ladislav Lhotka <[email-masked]>
Date: Thu, 28 Aug 2014 16:47:32 +0200

> same way as the "active" member type.  For example, with:

First of all, I think it is a general problem of the union type that it is impossible
(or at least not straightforward) to indicate which of the member types
a given instance is supposed to have. For a leaf with the type
inet:host, it can happen that an IPv4 address with a typo will be accepted
and interpreted as domain-name. This might be another use case for a
metadata annotation. 

> If we the read the value back, what do we get?  Probably "4668".

It depends, I would say it is more a question for the protocol what the server does
with the values it receives. yang-json is about the mapping of XML to
JSON and back. What it tells is that

- <foo>4668</foo> maps to "foo": 4668, and
- both "foo": 4668 and "foo": "4668" map to <foo>4668</foo>.

Hmm, but then the JSON -> XML mapping is not 1-1 as the draft claims. I
have to think about it.  

> over json.

Yes, that's for sure.

> What happens if leaf foo is the key in a list - can we create two list

I posted exactly the same question to the yang-doctors mailing list after
the tutorial in Toronto.

It can be even more fun:

    key foo;
    leaf foo {
      type union {
        type decimal64 {
          fraction-digits 2;
        }
        type string;
      }
    }

Assume the client wants to edit list entry with key 1.00 but sends a key
1.000, and a new list entry with the string key "1.000" is created
instead. This is really quite brittle.

> It seems the simplest solution would be to say that unions are encoded

This would be another step in making JSON more XML-like and gradually
losing the main point of using JSON - simplicity. For unions that have
no string members it really makes no sense.

I would prefer if RESTCONF specifies the behaviour of the receiving side
in such cases.

Lada

>
>
> /martin
>
>    
>
> _______________________________________________
> netmod mailing list
> [email-masked]
> https://www.ietf.org/mailman/listinfo/netmod

-- 
Ladislav Lhotka, CZ.NIC Labs
PGP Key ID: E74E8C0C

---

From: Andy Bierman <[email-masked]>
Date: Thu, 28 Aug 2014 08:05:58 -0700

Hi,

I realize that the standard text is important and needs to be correct, but
when writing
the code for this, I followed the Postel Principle. The YANG schema wins
any conflict.
The tools will try to figure out how to get the content to fit the YANG
schema, even if
the peer did not follow every detail in Lada's draft.

Re, these examples: the 42 vs "42" would be treated as a duplicate-entry
error.
The "1.000" is a perfectly valid key by the (strange) YANG typedef rules, so
it would be accepted.

Andy

---

From: David Reid <[email-masked]>
Date: Thu, 28 Aug 2014 11:58:36 -0400

How do you handle Martin's example where you use json to set "foo": "4668"
and then read foo back. Do you return "foo": "4668" or "foo": 4668?

Or to ask the same question from a different angle: Do you store the
value of foo internally in C as an int or char *? 

-David Reid

---

From: Ladislav Lhotka <[email-masked]>
Date: Thu, 28 Aug 2014 18:32:27 +0200

On 28 Aug 2014, at 17:05, Andy Bierman <[email-masked]> wrote:

> Hi,
> 
> I realize that the standard text is important and needs to be correct, but when writing
> the code for this, I followed the Postel Principle. The YANG schema wins any conflict.
> The tools will try to figure out how to get the content to fit the YANG schema, even if
> Re, these examples: the 42 vs "42" would be treated as a duplicate-entry error.

Hmm, pyangs flags an error on this module:

module jtest {
  namespace "http://example.com/jtest";
  prefix jt;

  leaf foo {
    type decimal64 {
      fraction-digits 1;
    }
    default "1.00";
  }
}

$ pyang jtest.yang 
jtest.yang:9: error: the value "1.00" does not match its base type - too many fraction digits

But maybe it shouldn’t …

Lada

---

From: Andy Bierman <[email-masked]>
Date: Thu, 28 Aug 2014 09:39:50 -0700

> value of foo internally in C as an int or char *?
It is treated as a string because it is part of 'anyxml y';
Complex nodes are treated as containers. Simple nodes are
treated as string leafs.  Arrays are not used if the data is streamed
(and the next sibling to be sent is unknown). (I know this is wrong).

The IETF can write all the complex standards it wants, but developers are
not going to bother spending massive $$$ to design for the pathological
corner cases
that serve no use-cases.  Customers only complain about broken features
they actually use ;-)

We could add "docroot" to YANG 1.1 and deprecate anyxml if we really are
that
concerned about interoperability. Or we can say that you get limited
interoperability
when you abandon all schema and use anyxml.  I can't think of anything more
antithetical
to the practice of data modeling than "anyxml", so maybe Martin is right.
(get rid of it).

Andy

---

From: Martin Bjorklund <[email-masked]>
Date: Thu, 28 Aug 2014 19:10:52 +0200 (CEST)

> > The "1.000" is a perfectly valid key by the (strange) YANG typedef rules, so

Agreed.

> jtest.yang:9: error: the value "1.00" does not match its base type - too many

Remember that the original type was a union, so if you change your
leaf to:

  leaf foo {
    type union {
      type decimal64 {
        fraction-digits 1;
      }
      type string;
    }
    default "1.00";
  }

pyang doesn't complain, just as Andy say.

/martin

---

From: Ladislav Lhotka <[email-masked]>
Date: Fri, 29 Aug 2014 10:57:19 +0200

> pyang doesn't complain, just as Andy say.

It doesn’t complain because it treats “1.00” as a string and not as decimal64. And that was my point: if it is a list key, then we could have one entry with 1.0 (decimal64) and another with “1.00" (string).

I understood that Andy said 1.00 would be classified as decimal64 with 1 fractional digit, too, and it would therefore be equal to 1.0.

Lada

---

From: Andy Bierman <[email-masked]>
Date: Fri, 29 Aug 2014 03:01:18 -0700

On Fri, Aug 29, 2014 at 1:57 AM, Ladislav Lhotka <[email-masked]> wrote:

> >>> the code for this, I followed the Postel Principle. The YANG schema
> wins any
> >>> conflict.
> >> jtest.yang:9: error: the value "1.00" does not match its base type -
> too many
> >> fraction digits
> >>
> >> But maybe it shouldn't ...
> >
> It doesn't complain because it treats "1.00" as a string and not as
> decimal64. And that was my point: if it is a list key, then we could have
> one entry with 1.0 (decimal64) and another with "1.00" (string).
>
> I understood that Andy said 1.00 would be classified as decimal64 with 1
> fractional digit, too, and it would therefore be equal to 1.0.
>
>
no - I said it would be treated as a string, not a number.
The test for decimal64 will fail and "1.00" will match the
next (string) type instead. 1.0 and "1.00" are both valid values
for the union typedef for leaf 'foo'.

Andy

---

From: Ladislav Lhotka <[email-masked]>
Date: Fri, 29 Aug 2014 12:06:40 +0200

On 29 Aug 2014, at 12:01, Andy Bierman <[email-masked]> wrote:

> for the union typedef for leaf 'foo’.

OK, but then these two values aren’t equal in terms of list key uniqueness. I apparently misunderstood what you said.

Lada