Skip to content

Conversation

@OlaoluwaM
Copy link
Contributor

@OlaoluwaM OlaoluwaM commented May 8, 2025

Unofficial Haskell SDK for the cloudevents spec. Written with row types to allow for arbitrary extension attributes as per the spec requirements. This gives us field deduplication at the type level but I fear I may have gone too far off the deep end just for that.

Anyways, this is a bare bones SDK that only allows for:

  • Creating a cloud event
  • Modifying a cloud event
  • Serializing a cloud event
  • Producing a Kafka message from a cloud event

@OlaoluwaM OlaoluwaM self-assigned this May 8, 2025
@OlaoluwaM OlaoluwaM requested a review from a team as a code owner May 8, 2025 20:29
@OlaoluwaM OlaoluwaM requested review from chris-martin, jason-lieb, mjgpy3, pbrisbin and z0isch and removed request for a team May 8, 2025 20:29
Copy link

@z0isch z0isch left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You already know the feelings I have about the fancy haskell stuff here, but I'll try to reiterate it.

I think a simpler design is going to work out better:

data CloudEvent extension data = CloudEvent {
    extension :: extension,
    data :: data,
    ...
    }

data KafkaExtension = KafkaExtension {
    partitionKey :: Text
    }

newtype KafkaCloudEvent data = KafkaCloudEvent (CloudEvent KafkaExtension data)

The tradeoff of this design is that it does not get compiler errors when an extension's name conflicts with the CloudEvent top level properties. Given that a user of this library will most likely not be using CloudEvent directly I don't see this as too big of a downside. The most frequent usage of CloudEvent will be in library maintainers implementing new bindings but those are governed by a spec and the likelihood of a conflict seems non-existent.

- FlexibleInstances
- GADTs
- GeneralizedNewtypeDeriving
- ImportQualifiedPost

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you follow our style guide and set the language to GHC2021, you don't need most of these extensions explicitly enabled.

Comment on lines +164 to +178
ceFocus
:: ( Functor f
, KnownSymbol l
, r .! l a
, r ~ Rec.Modify l a r'
, r' .! l b
, r' ~ Rec.Modify l b r
)
=> Label l -> (a -> f b) -> CloudEventRec r -> f (CloudEventRec r')
ceFocus l f r =
let
rec = getCloudEventRec r
updatedRec = Rec.focus l f rec
in
CloudEventRec <$> updatedRec

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I haven't the slightest idea what's going on here. Does this function do something complicated?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With great power of types comes great responsibility to write documentation and usage examples

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's kinda like zoom from the curricula project

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I should add more documentation. I kinda wanted to get the team's thoughts on the overall approach first

@chris-martin
Copy link

I suggest writing some tests and putting something into README.lhs as a next step - Seeing this code do something and produce some output would help me understand what it's for and whether the complexity is appropriate for what it does.

Copy link

@mjgpy3 mjgpy3 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm blocking to second AJ's suggestion.

The complexity of these new types far outweighs any benefits I can perceive. I'd also like to not have to learn a new DSL to construct an event.

@OlaoluwaM
Copy link
Contributor Author

OlaoluwaM commented May 9, 2025

I get your point @mjgpy3 (and @z0isch), while I do agree somewhat, I think the complexity here is pretty isolated in that a user never has to interface with row-types directly but only the mkCloudEventRec function (which takes a regular Haskell records btw) to construct a CloudEventRec then make use of the functions defined in Kafka.hs to construct a kafka message out of said cloudevent representation. There's really never a need to muck around with row-types.

Furthermore this much complexity isn't completely unheard of in the realm of SDKs given it's all for the sake of DevEx. Nevertheless, let me write up some example as @chris-martin suggests to show you what I mean

@OlaoluwaM
Copy link
Contributor Author

@chris-martin added some more details and an example to the README.md

@OlaoluwaM OlaoluwaM requested a review from chris-martin May 9, 2025 19:35
Support for release candidates is not required, but strongly encouraged.

\* Note: v1.0 is a special case and it is recommended that as long as v1.0
is the latest version, SDKs should also support v0.3.
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Restyled by prettier-markdown

Suggested change
is the latest version, SDKs should also support v0.3.
is the latest version, SDKs should also support v0.3.

`Integer` values in this range.
- String encoding: Integer component of the JSON Number per
[RFC 7159, Section 6](https://tools.ietf.org/html/rfc7159#section-6)
optionally prefixed with a minus sign.
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Restyled by prettier-markdown

Suggested change
optionally prefixed with a minus sign.
optionally prefixed with a minus sign.

@OlaoluwaM OlaoluwaM requested a review from mjgpy3 May 9, 2025 19:35
@pbrisbin pbrisbin removed their request for review May 12, 2025 15:00
@OlaoluwaM OlaoluwaM closed this May 12, 2025
@OlaoluwaM OlaoluwaM changed the title feat: Initialize project feat: Initialize project (row-types version) May 12, 2025
@chris-martin
Copy link

Well that readme definitely helps make the project not look scary anymore.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants