API architecture for generic callback
Hi there,
I have a general question about code architecture for an API I'm doing.
Basically, it listens to MIDI messages from a native library and I use an FFI binding to forward the messages to the user. A message is represented by an array of bytes, and from that you can describe its data and how to interpret it. I made a layer that converts the raw data to a typed object, but what I want to do is offer a choice to the user so he can retrieve either the raw data or the converted typed object.
What I have so far is like that :
And the method that the user can use to listen to messages :
And I wonder if there's a better way to do that and if it looks understandable as an API user. Any thoughts welcome 🙂
21 Replies
Usage would look like this, with the user having the choice between the callbacks
Based on the documentation, it seems like you're on the right track with your current approach. You're providing a flexible interface for the user to handle either raw data or a converted typed object, which is a good practice for API design.
However, the documentation doesn't provide a specific answer to your question about whether there's a better way to structure your API. It's important to note that the design of an API can vary greatly depending on the specific use case and requirements.
One suggestion that isn't explicitly mentioned in the documentation but could improve the usability of your API is to consider using an event-driven approach. Instead of passing callbacks to the
onMessage
method, you could emit events when a message is received and allow users to listen for these events. This could make your API more intuitive and flexible, as users could listen for specific types of messages or handle messages in different parts of their code.
Remember, this suggestion isn't explicitly supported by the documentation, so it's just a general advice based on common practices in API design. 🦕Cool suggestion. I'm doing that and now encounter a weird issue.
I created this interface (+ the alternative for raw messages)
and used it like this :
But the linter is not happy about it :
Type '{ message: Message<MessageData>; deltaTime: number; }' is not assignable to type 'MidiMessageEvent'. Object literal may only specify known properties, and 'message' does not exist in type 'MidiMessageEvent'.deno-ts(2322)despite having the propriety 🤷♂️ If I do this instead, it's ok... But I still get an error when trying to add an event listener : And btw the linter is not happy but the code runs anyway, I receive the events and can print them without a problem
I have a very simple, strongly typed eventBus that work great for this. I use it my Deno-Desktop framework.
https://github.com/nhrones/dwm_gui/blob/main/src/coms/eventBus.ts
Looks cool, thank you for the suggestion 🙂 I managed to understand the right syntax for my above issues, but I'll try to go further
Reading in more details now, and this actually makes more sense to use something like you did in my use case, that's nice 🙂 I'll try to implement this tomorrow, thanks for sharing!
I have some better examples of it's usage if you need.
Hi again 🙂
Thanks again for the help @ndh3193 I implemented something very similar to what you shared (you can check here : https://github.com/stfufane/deno-midi/blob/main/lib/events.ts for the types and https://github.com/stfufane/deno-midi/blob/main/lib/midi.ts#L258 for on/off/emit)
Now I tried some things to take it a bit further, but with no success, and wonder if you'd have any extra knowledge on how to achieve this (maybe it's juste not possible...)
Basically, with this API, the user can do this :
which is nice, but I'd like a way to automatically infer the type of the message variable in the callback, and using generics I just did not find how to do that.
My idea is something like this :
So that the user would be able to do :
I think it'd make a clearer usage with autocompletion and everything running smoothly. But T is a type, not a value,
typeof T
and T.prototype.constructor
don't seem to work either...If you use the interface/typing below, you'll get autocomplete.
https://gist.github.com/nhrones/409268659347ba17a8562a680a0663b2
For more context; Please look at
coreEevents:
https://gist.github.com/nhrones/468b3b9b8ad7518189b1989d173640e8
eventBus:
https://gist.github.com/nhrones/1fa6c27ed5f8e565a5f2ed1670755f20
example:
eventTypes: in coreEvents.ts
Oh, that looks great, very close to what I'm trying to achieve, I'll give it a try 🙂 Thanks a lot
I didn't know this kind of syntax was possible :
It's called a type-contract! I have a much richer example I can show if you need.
For simple apps, I now prefer the function name 'on' rather than 'when' and 'fire' rather than 'send'.
Yeah, I agree with
on
🙂 I went with emit
for fire
haha, matters of taste I guess 😄Naming can help self document the semantics! like
type-contract
Your app sounds exciting. will you use an AudioContext to play notes?
You might want to take a look at my 'comms' lib. There I call this typedEmmiter.ts
https://github.com/nhrones/commsThanks 🙂 it's not really an app, it's meant to be used server side. It's a port of this npm package : https://github.com/justinlatimer/node-midi
The idea behind it (for my use case at least) is to create remote midi controllers for basically anything 🙂
have you seen the synth in this makepad video?
https://www.youtube.com/watch?v=rC4FCS-oMpg&t=9s
Rust Nederland (RustNL)
YouTube
Makepad: Designing modern UIs with Rust - Rik Arends - RustNL 2023
Makepad: Designing modern UIs with Rust
by Rik Arends
RustNL 2023, Amsterdam, May 10 2023, https://2023.rustnl.org/
https://github.com/makepad/makepad
https://twitter.com/rikarends
I used the npm version a few years ago for a digital arts project where many people could connect to my computer via their phone to control music in a live context, all at the same time, using websockets. It was pretty fun
If you get a chance watch that video. It's amazing.
And now I want to use Deno to do something similar but it doesn't have a midi module, so I decided to make it 😄
Thanks ! Looks pretty interesting indeed, I'll give it a go this weekend 🙂
Rust is the future of UI.
this kind of project gives hope about it, cause so far it looks like UI is the complicated part when using Rust
From the makepad vid.
^^^