asyncapi / shape-up-process

This repo contains pitches and the current cycle bets. More info about the Shape Up process: https://basecamp.com/shapeup
https://shapeup.asyncapi.io
11 stars 8 forks source link

Define Parser(s) API #90

Closed smoya closed 3 years ago

smoya commented 3 years ago

We want to start defining the new Intent-Driven API for the parser(s). Based on the current API Intents, define an API style having in mind the following (at least) requirements:

Note: please do not use examples to bias your design. They are just that, examples.

1. Intent-driven

Focus always on the final user intention rather than on a particular need on the code. Examples:

2 Versioned

Introducing API versioning lets users stick to a version and ensuring their code will keep working.

3. Resilient to breaking changes

API breaking changes are gonna happen. However, we want to let users embrace those smoothly. API methods should be written using signatures that can ensure compatibility within 2 versions or more.

Example:

Accessing the payload of a message in a subscribe channel looks like the following today:

asyncapi.channel('mychannel').subscribe().message().payload()

Let's imagine we want to rename the operations publish/subscribe to pub/sub.
As this is tied to the nature of the data structure behind it. It is completely coupled to the structure of the AsyncAPI document. Any change on such structure (changing deep, order...) will introduce a breaking change on the API.

-- asyncapi.channel('mychannel').subscribe().message().payload()
++ asyncapi.channel('mychannel').sub().message().payload()

In case we want to support the old method for a while (as deprecated), will mean we would maintain two methods on our API:

Resilient version

asyncapi.getMessageFor('mychannel', 'subscribe').payload()

Will turn into

asyncapi.getMessageFor('mychannel', 'sub').payload()

This introduces two pros:

4. User-friendly means simple

Examples:

asyncapi.servers(...servernames)

As a variadic function, this one would support:

[More examples to come]

asyncapi-bot commented 3 years ago

Hey! You've labeled this issue as a Scope. Remember you can use the following command to inform about its progress:

/progress <percentage> [message]

or

/progress <percentage>

A mutiline message.
It supports **Markdown**.
Example:
/progress 40 We're still figuring out how to implement this. We have an idea but it is not yet confirmed it will work.
/progress 50

A few notes:

* We got this figured out :tada:
* We're going to use [this library](#link-to-website) to avoid losing time implementing this algorithm.
* We decided to go for the quickest solution and will improve it if we got time at the end of the cycle.

:weight_lifting_woman: See the progress on the Shape Up Dashboard.

jonaslagoni commented 3 years ago

Well, this is quite a hard nut to crack...

Since this is the end of the workday I am just posting my initial thoughts on the task and potential solutions.

Different kind of signatures that we could implement, this should be followed throughout the API to ensure consistency:

i.e. doc.getMessageFor('mychannel', 'sub').payload() This is still too close to the actual document -> channel -> operation -> message[0] -> payload. And what if we remove the message completely? Also, an operation can contain 0 to many messages, render this signature a bit weird.

i.e. doc.payload('mychannel', 'operation') or doc.payload('mychannel', 'operation') and doc.description('mychannel', 'operation').

We also know that the intent will most likely always be present.

Thoughts:

  1. We need to be careful which objects we use as intents such as asyncapi.getChannelsByOperation('publish')
  2. Problem with variadic functions that we might encounter, especially in the implementation phase, what if a channel has the same name as an operation keyword such as publish. In some use-cases, it might be difficult to use since you have to make your own check whether you get 1 or more results.
  3. Even though we don't really need to think implementation wise, if we include that concept, some of the ideas might be very difficult to implement πŸ€”
smoya commented 3 years ago

an operation can contain 0 to many messages

I was not aware of it. What is the use case for having no messages for an operation?

<intent>(... <nested object names>)

I'm not fully convinced of this approach. I know it was mentioned by @fmvilas in https://github.com/asyncapi/shape-up-process/issues/82, However, I think it will carry on with the same issues the current API has. I suggest we define functions that map to intents but asking the minimum args as possible. For example, for getting a message payload you just need to know the operationID plus the "index" of the message (unfortunately we don't force to have a unique id per message that we could use instead). Also you could get all the messages for an operation.

asyncapi.message('operationID')       // returns all messages for a given operation
asyncapi.message('operationID', 0)    // returns the first message for a given operation
asyncapi.message('operationID', 0, 3) // returns the first and the third message for a given operation

Problem with variadic functions that we might encounter, especially in the implementation phase, what if a channel has the same name as an operation keyword such as publish. In some use-cases, it might be difficult to use since you have to make your own check whether you get 1 or more results.

Variadic functions (spread syntax in >=ES6) would not cause that issue if combined with rest parameters In that case a function can look like function message(operation_id, ...indexes).

jonaslagoni commented 3 years ago

I was not aware of it. What is the use case for having no messages for an operation?

Because oneOf is allowed to specify messages I assumed that it was 0 ... n but playground gives an error πŸ€”

    publish:
      message:
        oneOf: []

I'm not fully convinced of this approach. I know it was mentioned by @fmvilas in #82, However, I think it will carry on with the same issues the current API has. I suggest we define functions that map to intents but asking the minimum args as possible.

Hehe, I am not fully convinced about this approach either, I just wrote down my thoughts from yesterday, and I agree that we should use the minimum args as possible for all functions throughout the API. The only reason why I like the second approach more in general, if the intent is to get the payload, is this:

If your intent is to get the payload of the message, getting it by using asyncapi.payload('operationID', ...) is better then asyncapi.message('operationID', ...) and then .payload() since you cut out another step which might be removed (the message object).

That being said, we do have intents which wants to get the message object itself (https://github.com/asyncapi/shape-up-process/issues/84#issuecomment-800935961) therefore we they must be able to go through that as well. It is just more prune to being obsolete. And this I think will probably be one the hardest tasks to figure out where that boundary is with intents πŸ˜„ Since some of them are really, really close to the actual setup of the AsyncAPI spec.

Variadic functions (spread syntax in >=ES6) would not cause that issue if combined with rest parameters In that case a function can look like function message(operation_id, ...indexes).

What I mean is that if we have a function which takes multiple arguments of same type it can be a problem distinguish them from one another. But maybe we wont have that problem, lets see πŸ˜„

smoya commented 3 years ago

From Slack thread, it seems there are some valid use cases for having zero messages.

smoya commented 3 years ago

That being said, we do have intents which wants to get the message object itself (#84 (comment)) therefore we they must be able to go through that as well. It is just more prune to being obsolete. And this I think will probably be one the hardest tasks to figure out where that boundary is with intents πŸ˜„ Since some of them are really, really close to the actual setup of the AsyncAPI spec.

We do not aim for having the silver bullet API but rather something simpler and more resilient than what we have. IMHO it is already a win moving from asyncapi.channel('mychannel').subscribe().message() to asyncapi.message('operationID', ...) or similar as you are not tied to the data structure but to the concepts declared in the spec.

jonaslagoni commented 3 years ago

I have a kind of different approach which is somewhat the same structure as we have now. I don't think we can make the API without agreeing on the underlying structure of the calls. For example asyncapi.message('operationID', ...) is not resilient in it self, only If the structure behind the parser API does not change (that there will always be an operation id for example).

We need to make assumptions, assumptions that never change, if they do, a new major version of a parser is required. These assumptions are that regardless of how the specification declares the structure, the parser API will contain the same underlying structure.

I tried to keep the API structure as close to the current API (parser-js) as possible and are actually able to do so. I did this since the current structure makes sense from a tooling perspective and can be altered to support changes to the specification.

Descriptions for the API structure:

Suggested API structure

I have not included all intent functions in this suggestion, many can be thought of such as asyncapi.messages(<channel name>, <operation type>) and asyncapi.messages(<channel name>, <operation type>, <message index>). But we have to start somewhere.

I am not 100% sure all changes to the underlying specification will be possible to "safe guard" here. But that is yet to be determined.

But Jonas, that is the same structure as we have now, what changed? Yes it is (somewhat) the same structure that we have now, the only difference is that you have to change the way you think about it. The API structure is now completely detached from the underlying specification structure, and remains the same regardless of changes to the specification.

Any thoughts or doubts about this underlying structure? Does it make sense? :thinking:

WaleedAshraf commented 3 years ago

Just to mention, there is a request to add messageId to spec. https://github.com/asyncapi/spec/issues/458 And then asyncapi.message('messageId') would be possible.

smoya commented 3 years ago

Thanks, @jonaslagoni for your great work on that suggestion. You made a really great point:

We need to make assumptions, assumptions that never change

If we stick with that as our main goal, we could reach an API that will be (quite) resilient to breaking changes. You mentioned going with an approach similar to what we have today but with some light changes. That made me think a bit on it more deeply, and discovered this won't represent the real user intentions and will keep breaking easily as well.

I'm gonna try to throw some ideas about what I think the approach can be (based partially on what Fran mentioned).

We have to first find who are the potential users of the parser. Some examples:

As you can see, those intents could be transformed into actual API methods and they will be valid (almost) forever. For example:

From the application point of view:

asyncapi.messagesTheApplicationPublishes()

From the client point of view:

asyncapi.messagesAClientCanSubscribe()

The interface is gonna stay unbreakable between versions, unless a really big refactor happens on the spec, such as a completely redefinition or renaming. The implementation, however, could change. But that's not an issue. A new version of the parser will be released adding the needed changes inside the functions. Users will just need to update to the new version without changing their code.

I can't ellaborate a more detailed suggestion right now as I'm reaching my EOD here. Will keep iterating next Monday.

smoya commented 3 years ago

/progress 10 We have been looking for different API approaches and added a couple of suggestions. We are looking for setting the API foundation based on intents.

jonaslagoni commented 3 years ago

Thanks for the feedback @smoya!

That made me think a bit on it more deeply, and discovered this won't represent the real user intentions and will keep breaking easily as well.

How come πŸ€”? For the intents asyncapi.messagesTheApplicationPublishes and asyncapi.messagesAClientCanSubscribe it works perfectly, since it does not need information about the underlying structure. But now you have received an array of message objects. Now what, if we have not declared the structure of that object what would it return? Is that depending on the spec version that is passed along? πŸ€”

This is what I mean by the underlying structure of the API, we still need structure behind the scenes regardless of what intents we have. Therefore I suggest that we decouple the parser API from the spec in a way that makes sense and is resilient to changes (i.e. we iteratively use your suggestive changes to the spec as validating it wont break the API, if it does we then have to revise it and see if we can make it more resilient).

smoya commented 3 years ago

But now you have received an array of message objects. Now what, if we have not declared the structure of that object what would it return? Is that depending on the spec version that is passed along?

Yes, we would need to keep the getters for each field. For example, message.payload(). However, in case of child objects, perhaps we would need to think on intents again. It may happen that it does not fit as intent either and becomes another getter. That's ok. A note on those getters: Those are needed due to the nature of the language we are using as first implementation (JS) but this could be gone in another implementation such as the Go parser one. However, intents will always be there no matters what language we use. That's the key point of all of this.

Does it make sense? WDYT?

jonaslagoni commented 3 years ago

Yes, we would need to keep the getters for each field. For example, message.payload(). However, in the case of child objects, perhaps we would need to think on intents again. It may happen that it does not fit as intent either and becomes another getter. That's ok.

I think we are beating around the bush and talking about the same thing πŸ˜†

When we talk implementation it means that we need a file for message which contains all the message properties we have (accessed through getters). We need an operator class that contains all properties for operators.

The link from the root object asyncapi to message is our intent right? I.e. how we go from point A to point B.

Also However, in case of child objects, perhaps we would need to think on intents again this infers that we know which objects are a child of message. i.e. we imply an underlying structure. One of those structures is what I proposed, i.e. we acknowledge that channels are under asyncapi, operations are under channels and messages are under operations.

This still means that we can have intents such as asyncapi.messagesTheApplicationPublishes or asyncapi.operationsTheApplicationPublishes or whatever we figure out we need πŸ˜„

Does this make sense or? πŸ€”

derberg commented 3 years ago

this thread is getting long πŸ˜„ and I have to be honest I didn't read all. My question to proposal based on example:

why do I have to do message.bindings('kafka') (before that, I have to access channels and operations) and can't have getBindings('server', 'kafka') or getServerBindings('kafka')

also small comment to proposal that it would be useful to see in what arguments of the function are optional

jonaslagoni commented 3 years ago

@derberg yea, sorry πŸ˜…

why do I have to do message.bindings('kafka') (before that, I have to access channels and operations) and can't have getBindings('server', 'kafka') or getServerBindings('kafka')

You won't "have to", what I proposed is the basic structure that needs to be in place for you to iterate messages, servers, channels, etc. And then what getter methods you will have access to from those objects.

Intents are as I said a pathway to how you come from A to B. In order for getServerBinding('<specific server>', 'kafka') to make sense, you imply that the server object contains a binding property. This also means that it should be possible to access those bindings when you are iterating servers.

We can after the basics are down add better intent functions such as those you describe there to better access the underlying properties.

smoya commented 3 years ago

you imply that the server object contains a binding property

That's not true. You are not implying the structure behind but just the intention. This is a clear example of thinking out of the box. We need to focus on the real user intention which is: "I need that Kafka binding". The user should not case about the data structure behind, it does not matter if the binding lives under server or whatever.

smoya commented 3 years ago

why do I have to do message.bindings('kafka') (before that, I have to access channels and operations) and can't have getBindings('server', 'kafka') or getServerBindings('kafka')

You are basically declaring your intent in there. This will totally fit within the suggestion I made. πŸ‘

smoya commented 3 years ago

I'm gonna try to come up with a set of clear examples on the approach I suggested.

derberg commented 3 years ago

you imply that the server object contains a binding property

I'm not implying anything here πŸ˜› I just want to know what are bindings for my server. I simplified it as of course I can have more than 1 server so I should be able to specify the server name, etc. It would not change my point though

API just implies that I have access to 3 different bindings getBindingsServer, getBindingsMessage, getBindingsOperation, but if those operations are under bindings or bindings are under operations 🀷🏼 I don't know and I don't have to know. My IDE should be the source of truth, if I have getBindings, API docs jus tell me what options I have. I should even have hasBindings('kafka') so I can easily check if document has 'kafka' bindings that I do not support and can easily prompt user, like with hasCircular.

This is my understanding of intend. Like here https://github.com/asyncapi/nodejs-ws-template/blob/master/template/src/api/services/%24%24channel%24%24.js#L31, I just want the payload type, getPayloadType(), I don't care where it is in the document, but I know what message is it related too

smoya commented 3 years ago

@magicmatatjahu @jonaslagoni and @smoya (me) had an open meeting where we discussed the following topics:

The recordings of the meetings can be downloaded here:

smoya commented 3 years ago

Next steps on this would be:

smoya commented 3 years ago

/progress 25

We have been sharing different approaches and it seems we have one that can be used as base:

However, several good points were made on https://github.com/asyncapi/shape-up-process/issues/90#issuecomment-804845905 and we are waiting for another pass by @jonaslagoni based on the intents we recap in https://github.com/asyncapi/shape-up-process/issues/84. This will be useful for validating the suggestion.

jonaslagoni commented 3 years ago

I have gathered all the intents from https://github.com/asyncapi/shape-up-process/issues/84 and tried to structure different intents we can start out with. These are just a starting point and are no way near final. So look at the example with the thought about whether this can be adapted as our general approach to any intents.

All intents will have a has<intent> function attached to them which returns a boolean.

All intents are described using the following format:

<definition>.<has/get><intent>(<potential arguments>) : <return type> (based on which use-case)

Descriptions of keywords used:

Intent API

The following describes the different definitions and their corresponding intents.

Intents deemed not relevant

These are the intents defined in the issue but deemed not relevant to the parser.

AsyncAPIDocument

Channel

Operation

Channel

Feedback

derberg commented 3 years ago

I still need some time to look at it closely but for no I found a duplication here:

AsyncAPIDocument.getBindingForOperation('<operation id>', '<binding protocol>', '<binding property>') : any (outcome of comment(s): 799481319, 799598596)
AsyncAPIDocument.getBindingForOperation('<operation type>', '<binding protocol>', '<binding property>') : any (outcome of comment(s): 799481319, 799598596)

and because of it, you are missing getBindingForMessage

jonaslagoni commented 3 years ago

@derberg it is not a duplicate, one uses operation id and the other uses operation type πŸ™‚ I am not sure how use full both are though.

fmvilas commented 3 years ago

AsyncAPIDocument.getMessagePayload('<channel name>')

This one is not going to age well. If we end up adding support for Message Id (and most probably we will) we'll also want to have a function like AsyncAPIDocument.getMessagePayload('<message id>'). In both cases, this is a string, making it impossible to distinguish the intent. I'd be careful with these variadic functions.

AsyncAPIDocument.hasContentType('<content type>')

What about getContentType()? I think it's missing.

AsyncAPIDocument.getChannelNames()

What about getChannel(<channel name>)? I think it's missing.

AsyncAPIDocument.hasChannelWithOperation('<channel name>', '<operation type>')

Watch out! If we change the meaning of "publish" and "subscribe", we're screwed here. Try to capture a bit more the intent. For instance, something like:

These four methods will:

a. Express the intent of knowing if my application is subscribing to a channel. Our implementation will look for publish or subscribe depending on its meaning. b. Express the intent of knowing if I β€”as a clientβ€” can publish or subscribe to a channel.

AsyncAPIDocument.getBindingForOperation('<operation type>', '<binding protocol>', '<binding property>')

Same as above. This signature will break if the meaning of publish/subscribe changes. I'm assuming <operation type> is either "publish" or "subscribe".

AsyncAPIDocument.getExtensionForOperation('<operation type>', '<extension property>')

Same as above.

Channel.hasOperation('<operation type>')

Don't assume channels have operations. It's a mistake we did in the past. This issue will most likely decouple channels and operations.

Channel.getMessageHeaders('<operation type>')

This method most likely belongs to Operation instead. Conceptually (forget about AsyncAPI here), a channel does not have any operation associated. Instead, an operation has a channel associated to it. In general, I think you also should avoid explicit mentions to <operation type>, for the semantic reasons describe above.

AsyncAPIDocument.getSecuritySchemaComponents()

Typo. It's SecurityScheme.

Channel.getExtensionForOperation('<extension property>')

I think this one is missing the operation id.

WaleedAshraf commented 3 years ago

Couldn't read all of the above. But I'm thinking there should also be something: Message.getMessageId() and also AsyncAPIDocument.getOperations()

All of them will be like, AsyncAPIDocument.getChannels() AsyncAPIDocument.getOperations() AsyncAPIDocument.getMessages() AsyncAPIDocument.getSchemas()

jonaslagoni commented 3 years ago

Just FYI I am taking all of your thoughts into consideration and gonna write another suggestion based on those instead of addressing them one by one.

smoya commented 3 years ago

@derberg it is not a duplicate, one uses operation id and the other uses operation type πŸ™‚ I am not sure how use full both are though.

How are you gonna differentiate the argument from one function signature to the other if they have the same type?

jonaslagoni commented 3 years ago

How are you gonna differentiate the argument from one function signature to the other if they have the same type?

You can do a couple of things behind the scene to check whether it is an operation type/operation id, but based on @fmvilas reply it seems like we need to remove operation type completely and instead place it in the intent... Gonna fiddle around with some ideas and post them when they are ready. @smoya feel free to also post your comments on the suggested API as well πŸ™‚

smoya commented 3 years ago
  • AsyncAPIDocument.getBinding('<binding protocol>', '<binding property>') : any (outcome of comment(s): 799481319, 799598596)

I don't see now the benefit of moving the property name you wanna get to the arguments. If we can make the assumption that the returned Binding Object is gonna be always a map, then we could access the fields directly through the map. For example: AsyncAPIDocument.getBinding('<binding protocol>').binding_property(). Which could also translate to doc.binding('<binding protocol>')["binding_property"] in Golang as an illustrating example.

smoya commented 3 years ago

On one side, I would like to suggest we remove the get prefix for all the methods. Not sure how idiomatic it is in terms of Javascript but it is common in other modern languages. It is implied the operation you do when calling a function of this library, a parser, that you will mostly get information and never edit it (set operations?).

I also wanna make a formal suggestion based on some of the methods I added in https://gist.github.com/smoya/1d81a9556b8756c883c44ce873b645f1 :

So we can break the confusion barrier of https://github.com/asyncapi/spec/issues/520 and reduce the magnitude of the Operation object, becoming less important for the user.

Considering those intents could also apply in the context of each collection (e.g. Channels array), I'm thinking if it would make more sense, from a pure technical point of view, to avoid using arrays and instead use iterable objects, so each array would become an object of a class with itents as methods. For example, using JS:

class Channels {
  constructor(channels) {
     this.channelsArray = channels;
  }

  [Symbol.iterator]() { return this.channelsArray.values() } // Not sure if this is exactly how you do an iterable

  channelsApplicationPublishesTo() {
  }

  // ...
}
derberg commented 3 years ago

I'm missing functions that would be used in templates when rendering multiple files (with file templates for example). Basically what would, for example, $$channel$$.js get in context? or would context become obsolete?

Operation.getSummary() and Operation.getOperationId()

why not just AsyncAPIDocument.getOperationSummary() and AsyncAPIDocument.getOperationId() ?

smoya commented 3 years ago

why not just AsyncAPIDocument.getOperationSummary() and AsyncAPIDocument.getOperationId()

Would you do this for all the fields within the objects?

derberg commented 3 years ago

I would say yes, just looking at the current structure of the operation, we anyway would like to have dedicated functions for getting a binding basing on operationId or getting a message the same way, so why not having for other fields

current template code (warning: some Nunjucks stuff ahead):

{% for channelName, channel in asyncapi.channels() -%}
{%- if channel.hasSubscribe() %}
  {%- if channel.subscribe().summary() %}
   some logic
  {%- endif %}
{%- endif %}
{%- endfor %}

what about:

{% for operationId in asyncapi.getSubscribeOperationsIds() %}
  {% if asyncapi.hasOperationSummary(operationId) %}
     {{ asyncapi.getOperationSummary(operationId) }}
  {% endif %}
{% endfor %}

getSubscribeOperationsIds() what? ya crazy? πŸ˜„

in templates, we iterate a lot over arrays, just to pick up something by an id, then why not having helpers that just return only Ids collections? JS for a reason exposes API like Object.keys(object1)

warning: I was inventing here while writing the comment, so there might be wrong assumptions, but the code of the current template is a real one and you can see that I need to go through a lot to just grab a summary 🀷🏼

smoya commented 3 years ago

getSubscribeOperationsIds() what? ya crazy? πŸ˜„

In the case of Operations, I think getting operations from the root level (by root level I mean the methods on the AsyncAPIDocument) can work. However, my concern and the reason I would say we should avoid doing that for absolutely all fields/properties is the (big) amount of methods we will have at the root level. In the end, if you expose operation Ids, why wouldn't you also expose any other field around our models, like for example, ​the message title?.

I was thinking about segregating intents and methods across models rather than add all of them at the same root level. By model, I mean models that represent our domain, such as channels, messages, etc., and not the current spec data hierarchy. Meaning Messages will be queried from the root level (e.g. AsyncAPIDocument.messagesApplicationSubscribeTo()), but not their properties. Instead, their properties will be available as either intents or just getters. E.g. message.title() or messages.titles().

I think @jonaslagoni will add more light on this soon as we have been trying to elaborate an assumption based on that, just to make things simpler, especially for newcomers.

fmvilas commented 3 years ago

As a side comment, I think it will be easier to move this conversation to a PR. Easier to leave comments on lines and have discussions there. Plus, once you make changes, we all will see what has changed.

jonaslagoni commented 3 years ago

@smoya and I have added a PR to the parser with an updated suggestion for the API - https://github.com/asyncapi/parser-js/pull/263

We are keeping it in the PR as you suggested @fmvilas to enable better feedback.

smoya commented 3 years ago

/progress 40 We have created a PR that contains a draft of the Parser API. However, the suggested API is not as resilient to breaking changes as we desired. @jonaslagoni applied the emulated breaking changes from shape-up-process/issues/93 and figured out some issues we may face. See the test results here.

jonaslagoni commented 3 years ago

/progress 60 we have defined the mock intent API and started integrating it with tools to validate the API holds up.

smoya commented 3 years ago

/progress 70 New API validated against markdown-template. Diff of changes to adapt it to the new Parser API can be found here

smoya commented 3 years ago

Also new methods has been suggested as addition to the API definition that were required by the markdown-template: https://github.com/jonaslagoni/parser-js/pull/1

smoya commented 3 years ago

Those are gonna be the next steps:

smoya commented 3 years ago

I have been investigating a solution for defining, with a kinda metalanguage, our API definition so it can be given to developers of new Parser implementations (Go, Rust, whatever). I could not find any silver bullet solution besides using UML diagrams (we can consider).

An incomplete example of using PlantUML dsl for generating a UML for our API can be found here

As alternative, We could keep a document similar to https://github.com/asyncapi/parser-js/pull/263/files#diff-b57590968a12cee85a37c1b91d8cc7092cd8b68e50b242c39a178121db82a797 as Development guidelines for new Parser implementations, and instead, use the generated TS types for specific JS users.

Any ideas are welcome anyway.

smoya commented 3 years ago

/progress 75 We have been added new intents to the API documentation so we cover all the use cases we consider validated.

smoya commented 3 years ago

As far as I see, next steps are:

smoya commented 3 years ago

/progress 90 We updated the documentation of the new Intent-driven API and added all missing intents.

smoya commented 3 years ago

/progress 95 We have created a new repository that will contain the new Parser(s) API. There is a PR on it with the new intent-driven API specification and some design documents: https://github.com/asyncapi/parser-api/pull/1

smoya commented 3 years ago

/progress 100 Parser API v1.0.0-alpha got documented: https://github.com/asyncapi/parser-api πŸŽ‰ πŸŽ‰ πŸŽ‰ πŸŽ‰