Repository navigation
Description
What follows is a thought dump, so sorry if it rambles a bit.
This module is in a pretty good state with the HTTP Protocol, so i started thinking about what the next protocol that could be added.
As I thought about it, I realized a couple things.
This first is we probably need to make our top level Receiver and Emitter a little more generic. At the moment, they have things related to the HTTP Protocol in them.
This second thins is when we add a new transport protocol in, we are also potentially going to increase the dependencies for each one added. My assumption would be that we would use a library related to that transport protocol for emitting events. For example, if we added MQTT then we might use the mqtt module.
The problem, and maybe it isn't a problem, is that a user might only want or need 1 protocol, and if we had multiple protocols implemented, then they would be getting more dependencies than needed.
One solution to this could be creating new modules that depend on this module as a base for each of the new Protocols. I would assume we would just keep the HTTP protocol in the base module since, and i have no data to back this up, it might the most common to use. So if a user wanted the MQTT protocol, they could just install that module. However; if they wanted to use multiple protocols, I could see this becoming a little messy.
Another solution i thought about was some sort of plugin architecture, but i not really sure of the UX of it. with this case we would still be creating separate modules to plugin, but there would be one "entry point" to creating new Emitters and Receivers
Again, this was a thought dump to start a discussion on our best path forward.
Activity
lholmquist commentedon Aug 20, 2020
@cloudevents/sdk-javascript-maintainers and anyone else
lance commentedon Aug 20, 2020
@lholmquist thanks for bringing this up! As you know, I'm interested in moving ahead with MQTT protocol support in the near future.
One thing to consider is that we don't really need to support the MQTT protocol itself, we just need to provide a means for developers to express a
CloudEventas an MQTT publish message. In fact, I would say with regard to HTTP, our choice to use Axios to send over the wire may not actually be the best thing. The module could be smaller and more concise if we simply provided methods similar to this.In fact, that's essentially how our
Receiverworks today. It doesn't really know about the HTTP protocol itself - it just accepts some headers and a body. It's a little strange to me that we do it so differently by actually sending an event over the wire when emitting an event.I say all of this to emphasize that we don't really need to worry about the MQTT protocol. We just need to provide a way to transform a
CloudEventinstance into an MQTT publish message, and to read an MQTT publish message and convert it into an event. This is good, because themqttmodule is not small. Including all of its dependencies, it runs about 10MB.lholmquist commentedon Aug 20, 2020
One reason i can see having an Emitter, is to make the users life a little easier with not having to worry about setting the correct method and those other tiny details. But I think that making this library smaller, and focused on just formatting(receieving and sending) the CloudEvents might be a good direction to go in
That would allow a user to use their http lib of choice(or other protocol lib of choice).
This would also solve the issue #314 about the Emitter being static, since we wouldn't have an emitter function anymore
lholmquist commentedon Aug 21, 2020
So i wanted to close the loop on this, since we talked about this a little bit in the SDK meeting. It looks like we might be in favor of reworking Emitter to remove any type of transport functionality and let the user decide which library they want to use to send/emit the events.
This would allow us not to have to add other 3rd part libs related to sending over a protocol and also makes it so we don't have to worry about creating plugins
We would provide a function/functions that takes a CloudEvent. The return value could be an object with properly formatted properties such as
headersandbodythat a user would use in with their transport libraryAn example of what a function could look like for HTTP, it could look something like @lance post above:
HTTP.asStructured(ce)and a MQTT version might look like:
MQTT.asStructured(ce)Another version could be the function taking the CloudEvent, the mode(structured/binary) and the protocol
I'm not tied to either option
As for the Receiver class, I think the way that works now, is probably ok. I still think the top level Receiver function needs to be refactored to remove HTTP related code. HTTP can still be the default though
lholmquist commentedon Aug 21, 2020
I think once we have a path forward, we should add a deprecation warning to the current emitter and release a version, so users now what is happening
lance commentedon Aug 21, 2020
Thanks for the follow up. In terms of namespacing, what do you think about having this and some
senderinterfaces under amessagesnamespaces? Here's a strawman API.lholmquist commentedon Aug 21, 2020
I like the concept. I know in the above post i said we could probably leave the Receiver alone, but would make sense to add an accept method(or similar) to this, so
HTTP.acceptorMQTT.accept?I realize this is just a strawman, but i wonder if it makes sense for the
sendmethods signature to besend(message, sender)instead. I've been doing some swift in my spare time and it is starting to influence my function names :) So that function would read " send a message using this sender "grant commentedon Aug 21, 2020
Hey, thanks for raising this. I'll add my 2 cents.
Ideally this module does not need to worry about the protocol or module we want to use with the protocol too much. We can just provide utility functions to help a protocol. For example, we shouldn't wrap modules like axios because axios is going to have many features that aren't in this library and folks can just use that module or other ones directly.
As Lance mentioned, the
receiver.tsandemitter.tslogic seen herehttps://github.com/cloudevents/sdk-javascript/tree/main/src/transport
should really be in the
httpfolder as it is http specific. Yup 👍With respect to some of the ideas above, Node core and node modules, from what I know, it's less common to have classes like
HTTPandHTTP.accept. It's more common to export functionsimport {accept} from 'cloudevents/transport/http'.Likewise, I could imagine
import {accept} from 'cloudevents/transport/mqtt'.Then we can expand protocols by adding another folder with a set of functions.
(imo
accept(req)is a weird term which could betoCE(req))Hope this is a useful perspective.
lholmquist commentedon Aug 21, 2020
WRT the namespacing, Are we going to run into the issue where we have to have "dist" in the namespace path?
This was how we used to get Constants before we moved it to the top level:
const Constants = require('cloudevents/dist/constants').default;maybe there is a way to get around that?
grant commentedon Aug 21, 2020
WRT namespacing, we can probably still import from
cloudevents, not withsrc.The main point I wanted to say is that we ideally don't overdo the protocols, and just have utility functions for getting things like HTTP headers, body, and forming CE to other transport primatives.
lance commentedon Aug 21, 2020
Good point. I suppose it should only be available via the top level export.
I wasn't thinking classes, exactly. Something more like this, where HTTP is just an object with a few functions hanging off of it:
I've been playing around with this on a branch, with interfaces like this:
I will try and push a branch to this repo with a first pass at an implementation similar to this next week. We can iterate on it there since, it's often easier to actually talk about code that actually exists.
lance commentedon Aug 21, 2020
OK - I've pushed a branch with a first pass at something like this. https://github.com/cloudevents/sdk-javascript/tree/lance/ce-next
This folder contains the bulk of the work: https://github.com/cloudevents/sdk-javascript/tree/lance/ce-next/src/messages
And there's a single simple test: https://github.com/cloudevents/sdk-javascript/blob/lance/ce-next/test/integration/message_test.ts#L39
lance commentedon Aug 22, 2020
On this new branch, I've removed the concept of
Senderentirely as it was really just a wrapper around invocation of a user supplied function. I don't think we need to have this level of indirection. It seems like overkill. The concept ofReceiverhas been changed toDeserializerand the exported function namedtoEvent(message: Message): CloudEvent.I've changed the existing HTTP transport bits to use
MessageandHTTP.binary(),HTTP.structured()andHTTP.toEvent(). Have not added any deprecation notices yet. I think this is coming along. @cloudevents/sdk-javascript-maintainers please feel free to pull my fork and let me know what you think.lholmquist commentedon Aug 22, 2020
Regarding Deprecations. I wonder if we should have some sort of deprecation policy for the future. Is it to overkill to deprecate a feature and then need to wait for 2 major releases before it is removed?
So for example, we release a 3.2 which has deprecation notices for
ReceiverandEmitter, then in 4.0 we introduce the new way from the above post, but we don't remove the old way until 5.0?Thats similar to how node core does things, but maybe we don't need to be that process heavy and a new major version is fine for removal. But we should probably do a minor release of the current version adding the deprecations in
lance commentedon Aug 22, 2020
@lholmquist I think we can probably push 3.2.0 with deprecations for everything under
src/transport, and the addition ofsrc/messages, since it's only additive. This way, we can document and promote the usage ofMessageinstead of the hackey transport bits, and even iterate on the new stuff, fixing any bugs that are found and potentially changing the API until 4.0.0 when we removesrc/transportandsrc/messagesbecomes a fixed API with breaking changes requiring major version bumps. What do you think?I'm thinking it's probably time to create a WIP pull request for detailed feedback if folks have it.