apiaryio / api-blueprint

API Blueprint
https://apiblueprint.org
MIT License
8.65k stars 2.14k forks source link

Decimal (float) type for attributes and parameters #297

Open alexpanov opened 8 years ago

alexpanov commented 8 years ago

Hi all,

I tried looking for a duplicate but wasn't able to find it. If there is a duplicate issue, please point me to it.

Now, to the issue matter. I think it would be very useful to be able to specify that some of the parameters are not just a number but a decimal like so:

    + Attributes
    + id (number)
    + price `100.01` (decimal) - Item price

Since we already have a schema definition capabilities with numbers, strings, etc. having a decimal type would be extremely useful for documenting monetary values, coordinates and so on.

Having an option to specify decimal precision would be a great option too.

    + price `100.01` (decimal(10,2), required) - Item price. Max length of 10 digits with a scale of 2
zdne commented 8 years ago

@alexpanov

We are thinking about extending MSON with additional types.

Meanwhile, would defining your own type and inheriting from number help?

Something along these lines:

# Data Structures

## My Decimal (number)
Max length of 10 digits with a scale of 2. 

## My Data (object)
- id (number)
- price `100.01` (My Decimal) - Item price

Sure it wont have support in the parser / JSON Schema renderer but it will at least express the intent .

pksunkara commented 8 years ago

@zdne Can we tag this as an Idea for now?

alexpanov commented 8 years ago

@zdne Thanks for the response. Yes that would help. Thank you.

I do think however that extending the types is would be great.

Perni1984 commented 8 years ago

+1 - we have the same use case here.

honzajavorek commented 8 years ago

If we had validations in place, any custom type could define clear constraints in them and there would be no need for extending MSON's built-in types.

nfisher commented 8 years ago

@honzajavorek disagree with validations beyond what's required for serialisation (e.g. type). In my opinion this would bloat the specification, increase the complexity of support tooling, and spread validation across multiple layers in an application.

In terms of number representation I'm running into this as an issue with https://github.com/nfisher/apib2go. It automatically generates the data structures and currently targets Go but I'll be adapting it to generate C#, Groovy, Java and Python (and anything else others want to submit). For most languages there are many types that can represent a number but for the most part they are limited to a common set that either the CPU supports or are common standards (e.g. Decimal). I think maintaining the number type as the base is perhaps the most backwards compatible approach. Instead of introducing new types you can enhance it with type hints. In theory I would expect this to be mostly backwards compatible. An example of the format would be:

+ existing (number) - maintains current behaviour
+ id (number,int64) - integer value
+ price (number,decimal) - decimal value
+ lat (number,double) - floating-point value

As a reference I think that protobuf3's specification is a good basis for the types I'd like to see in API Blueprint.

zdne commented 8 years ago

Hey @nfisher, thanks for chiming in!

So your suggestion would be to add "type hints" as type attributes? If I count correctly, proto3 has 12 types of numbers.

I am not sure what is the benefit of using type attributes for this. How about if we would introduce a "standard" MSON library that would extend the base number type as follows:

# Math Data Types
This blueprint extends the MSON `number` type. 

## Data Structures

### int32 (number)

### int64 (number)

### uint32 (number)

...

Would that work?


Also, one unrelated question: While I love that you are working on this MSON to language convertor wouldn't it be feasible to build MSON to proto3 instead and then piggy back on protobufs? Just curious what are your thoughts on this.

nfisher commented 8 years ago

Hey @zdne,

My suggestion is a tangential concern to the primary audience of the APIB standard as it selfishly benefits me. :) I can make what you suggest work and is probably the most pragmatic approach which also minimises warnings.

My aim in raising the concern is that I feel primitives should be first class and not require an include/import in each file where they are used. There's a part of me that rails against the "batteries not included" for primitives. It's an incredibly minor niggle but I feel like its a foundational decision that incremental bloat stems from, death by 1000 cuts if you will. I also see it as something that could cause (very minor) issues for newbies where discrete snippets are posted that miss the import for brevity (e.g. blogs, gists, etc).

Or have I misunderstood what you mean? Did you imply it as a default inclusion that requires no effort from the user?

Regarding MSON to protobuf3 I can add new languages fairly quickly now. As a reference this is the what it takes to generates the data structures for Go. Generating protobuf IDL's wouldn't be much more code: https://github.com/nfisher/apib2go/blob/master/golang.go

Having it generate protobuf IDL files, avro, thrift, etc wouldn't be a problem. The problem I foresee is that they're serialisation techniques targeting RPC end-points. In it's current incarnation APIB appears to more specifically target HTTP. The implication being that you lose some of the benefits/functionality that the current ecosystem provides (e.g. dredd, aglio, etc).

Perhaps I should raise this as another issue but I could see the introduction of a meta-data tag such as PROTOCOL to indicate the end-points protocol:

FORMAT: 2B0R!2B
PROTOCOL: rpc

# Math API

## Add a collection of numbers together and return the result [Math.Add({terms}) {sum}]

Everything else would more or less be the same where it makes sense.

Long-term I would like to generate client libraries and server stubs with apib2go but for now the struct generation is scratching my itch.

I guess the next steps I'm thinking is:

  1. address my immediate need using your suggested approach.
  2. flush out the benefits/drawbacks to elevate primitives as being part of the standard. Might want to refer to Avro, CapnProto, Protobuf, and Thrift to decide on what should be a primitive.
  3. assess appetite/desire to introduce RPC interfaces to the standard.
zdne commented 8 years ago

Hi @nfisher,

My suggestion is a tangential concern to the primary audience of the APIB standard as it selfishly benefits me. :) I can make what you suggest work and is probably the most pragmatic approach which also minimises warnings.

👌

There's a part of me that rails against the "batteries not included" for primitives.

Fair point. The question is, how many batteries to include by default (all twelve sizes?)

Or have I misunderstood what you mean? Did you imply it as a default inclusion that requires no effort from the user?

This is open question. Both is possible. Probably baking it into a standard library that is always "included" is what I'd do (versus adding it into language spec itself).

https://github.com/nfisher/apib2go/blob/master/golang.go

/jaws dropped/

I mean, how much of the MSON complexity it can handle (one of, include etc)

APIB appears to more specifically target HTTP.

APIB yes, MSON should be agnostic to all of that and JSON in particular (that is why I am defending it against null and things like read-only

PROTOCOL to indicate the end-points protocol

You can add any custom metadata to any blueprint file. In the future, I'd love to abstract this away: https://github.com/apiaryio/api-blueprint/issues/289

Long-term I would like to generate client libraries and server stubs with apib2go but for now the struct generation is scratching my itch.

I would love to hear about how would you deal with updates...

zdne commented 8 years ago

FORMAT: 2B0R!2B

🍭

nfisher commented 8 years ago

If it's available via the stdlib then that works for me. I would opt for all the types in that lib as there's benefits and trade offs to each in terms of range, performance, memory, etc.

I've only started using API blueprint maybe a week or two prior to developing api2go. Right now it's limited to generating data structures from the data structures section. Currently it generates the 3 static primitives defaulting to optional which is pointers in go and will be guava Optional in Java.

For Collections it only addresses arrays at the moment. Maps are easy for dynamically typed languages but I haven't needed/used them in my project yet. What will be problematic for the object type is strictly typed languages. JSON maps are kind of incompatible with strict types unless I assume all values are strings. As an example:

{ "k1": "string", "k2": true, "k3": 12345 }

Would be valid as a JSON map/object type but I would need to think about a reasonable way to handle the representation and not impose undue burden on the user for type conversions. One thing that I don't like about avro is that type overrides for collections seem to be very Java centric. I'd probably opt for a mapping file for custom overrides.

Regarding updates for JSON I'd overwrite the generated source files. For protobuf I'd likely use a state file that is committed with the repository and a format like:

$class,$prop,$type,$serialId

Any change to the first three elements in the tuple would result in a new entry with an auto incremented serialId relative to the class. An alternative would be an additional attribute in the property definition but it kind of feels like it's polluting the abstraction level. :/

On Fri, 15 Jul 2016 at 15:12, Z notifications@github.com wrote:

Hi @nfisher https://github.com/nfisher,

My suggestion is a tangential concern to the primary audience of the APIB standard as it selfishly benefits me. :) I can make what you suggest work and is probably the most pragmatic approach which also minimises warnings.

👌

There's a part of me that rails against the "batteries not included" for primitives.

Fair point. The question is, how many batteries to include by default (all twelve sizes?)

Or have I misunderstood what you mean? Did you imply it as a default inclusion that requires no effort from the user?

This is open question. Both is possible. Probably baking it into a standard library that is always "included" is what I'd do (versus adding it into language spec itself).

https://github.com/nfisher/apib2go/blob/master/golang.go

/jaws dropped/

I mean, how much of the MSON complexity it can handle (one of, include etc)

APIB appears to more specifically target HTTP.

APIB yes, MSON should be agnostic to all of that and JSON in particular (that is why I am defending it against null and things like read-only https://github.com/apiaryio/api-blueprint-rfcs/pull/15

PROTOCOL to indicate the end-points protocol

You can add any custom metadata to any blueprint file. In the future, I'd love to abstract this away: #289 https://github.com/apiaryio/api-blueprint/issues/289

Long-term I would like to generate client libraries and server stubs with apib2go but for now the struct generation is scratching my itch.

I would love to hear about how would you deal with updates...

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/apiaryio/api-blueprint/issues/297#issuecomment-232947115, or mute the thread https://github.com/notifications/unsubscribe-auth/AABIuPeWG8Mv6iKavr5WCtLWxB0vYyK0ks5qV4dFgaJpZM4G6vgO .

  • from my thumbs to yours
nfisher commented 8 years ago

@zdne feel like maybe I should open a new issue so as not to pollute this one any further?

dhstewart commented 7 years ago

In order to help future readers from having to read through this whole thread, can someone close this with a link to the resolution or update the thread? Trying to figure out where this left off was a little time consuming and it would be great to save time for others. I arrived here after googling "apiary specify decimal." Thank you!