Skip to main content
← Back

Transcript: wRPC Error Handling & axios in a Wasm Component Model App

← Back to watch page

wasmCloud Weekly Community Call — Wed, May 14, 2025 · 37 minutes

Speakers: Brooks Townsend, Victor Adossi, Jochen Rau


Transcript

Brooks Townsend 01:02

Okay, well, now is as good a time as any, so let's do the thing. Hello everybody, welcome to wasmCloud Wednesday — Wednesday, May 14. Let me go ahead and share the agenda here. We're going to do something pretty special today, bringing back a recurring segment. As far as I know we don't have a demo or any long-standing discussion items that we were bringing over to this week. But one thing we did want to do — and thank you so much, Eric, for the suggestion — is, I don't know if people look at the notes beforehand, but we actually have a space in the weekly highlights to talk about the Issue of the Week and the Documentation Page of the Week.

We did this quite a while ago just to highlight, like, "hey, new documentation is coming in." I know that all of you read through all of the wasmCloud documentation every single week just to see if something has changed — but not everybody does that, you know? So we want to make sure that we're calling out fun things that are coming across, and fun issues to work on. So I just had some quick discussion items to call those out, and then get folks' feedback on bringing back this recurring segment.

wasmCloud community call agenda with the weekly highlights section

So, on the Documentation Page of the Week — the documentation page of the week is on error handling, error handling with custom interfaces and wRPC. This is actually a feature that we landed in wasmCloud 1.8 for all of our custom interfaces. Implicitly, when you make a custom interface and you run a component or a provider in wasmCloud, that is converted to use wRPC and the component model encoding to send it over an RPC call. You can do it with NATS, you could do it with TCP or QUIC, and we have a feature flag to turn this on, since it's something we're essentially experimenting with — we want to get some reps under our belt trying it out and seeing how it goes.

Essentially, all you need to do for your custom interface is wrap your desired return type in a result, and then make the error type this wRPC error. It's a resource that our wasmCloud host and the wRPC bindings beneath it understand, so that whenever you call this custom interface that's been generated by wit-bindgen — or if you're calling it underneath some higher-level RPC — if there was a problem during transport (which is not something we'd normally express in terms of, say, the general hello-world interface), say your socket disconnects or your NATS credentials change, you'll actually get an actionable error on the guest side that you can take action in response to. You can try to recall the function — maybe it was an intermittent error — you can bail in a different way using your own custom error implementation, you could sleep for a second and try again. It's really case by case about what you'd want to do in the case of a platform-level error.

Documentation page on error handling with custom interfaces and wRPC

So this is the first step in making this work for any interface. Right now, for the wasmCloud messaging interface, we can let you know if there's a NATS problem by giving you back an error type with a string. But this lets you opt into this with custom interfaces and opt into this level of error handling. Previously — just to set the baseline — what this would be is a hello-world function that just returned a string, and if there was a platform-level error (NATS disconnected, didn't have a proper link), the component would just panic at that point, because we don't know what to do; there was no way to give that feedback back. So this is the first step, I think, in a lot more robust custom interface support. The real call-out here is around the feature and also around the documentation. So this is great — if anybody's taking a look and wants to see how you could use this, you just need wasmCloud 1.8 and come check out the errors page on the interfaces side. Did anybody have any questions on this docs page?

Brooks Townsend 07:01

Yeah, I hope that we can continue this Documentation and Issue of the Week tradition. I think it's really nice to call out some of the new features when they land, and docs, because a lot of our documentation ends up being written in response to feedback from Slack, from GitHub issues — just like, "oh yeah, we probably should have a docs page on that." So leading on from that, the issue that I linked (unfortunately under the documentation side, so I'll get that fixed up) is that it would be nice to have more of a wasmCloud-specific example for the RPC error handling.

On that documentation page, we showed an example from the wRPC examples repository. That's the baseline — this is exactly how it works. I think it would be really nice if we were to go into the wasmCloud repository where we have our examples. For example, I know that we have a composition example where you compose two components together — essentially a hello-world that calls another component, and you get a response back. It would be great to redefine this WIT, for example; it could be any interface that's more specific to wasmCloud. But the Issue of the Week here is really building this into an example that shows off how this works in a real wasmCloud deployment, so it's not something you have to go specifically to the interface error-handling documentation to understand — it's just something that we use whenever we have a custom interface.

I really don't see much of a reason not to. In my opinion, it's pretty much always better to be able to take action off of a platform-level error than to panic in the component and not be able to take action there. So if anybody's interested in taking this on — you explore this, you create an example, or you change your code to use this — happy to accept really any kind of example here. This is a hot Issue of the Week to take a look at. Do folks have any suggestions on the wasmCloud-specific example, things you'd like to see? I know we're just throwing out ping-pong, which is a solid example, but there's plenty of room for additional feedback.

Brooks Townsend 10:16

Alrighty. Other than that, that was most of our regularly scheduled agenda, but I also wanted to bring up some of the interesting patterns we're seeing in wasmCloud today. We have a new blog that went out yesterday — I'll post the link in the Zoom chat as soon as I can find it. This is on the wasmCloud documentation site, under blog, really around platform engineering with Wasm and the platform harness pattern.

The platform harness pattern is something we're seeing much more commonly used by people who are taking wasmCloud to host and run a platform internally for Wasm. Really what this comes down to is the difference between the implementation of platform concerns and user code. That's expressed in this diagram midway down the blog. Things like interacting with a filesystem, interacting with the environment, interacting with proprietary internal things are all done with this platform harness component, since every single application essentially uses it in the same way — and the component that an individual developer works on is much smaller in scope. It's essentially just business logic, and we can compose those components together either when you build it using WebAssembly composition, or when you run it using dynamic links, wRPC — all the things wasmCloud is good at.

Diagram of the platform harness pattern separating platform concerns from user business logic

This platform harness seems to resonate really well with folks who are running platforms internally and bringing wasmCloud into that workflow. So I'm very curious about some of the folks on this call who have been with the community for quite a long time — I'm really interested in what you think of this terminology, how it resonates with what we've been trying to do with the wasmCloud project. There's nothing here that's an architectural change required on the wasmCloud side; it's really just a pattern that I think we can document around and give recommendations on. So I'm really curious to hear if this is something you'd find yourself using in the general case, or why not. We have a pretty light agenda today, so we're kind of at the end here. Oh yeah — hey, Victor, what do you got? You might be double-muted.

Victor Adossi 13:29

Yeah, can you hear me now? Hey. So I wanted to show some stuff I'd been working on and put up a pull request for, in the JavaScript ecosystem that we've been working on sort of long-term. I'm not sure if Lachlan demoed some of the awesome work he did around integrating Hono — but one of the things we've been looking at recently was also making sure that axios, which is a really popular request library, works. Okay, yes — Milan did an awesome demo of the Hono stuff, so for people watching online, make sure you go back and watch that. I think that was maybe last week, or a week before.

Another thing that's really popular in the JS ecosystem is axios, sort of an alternative to fetch. While fetch wasn't still quite everywhere and super easy to use, some people still prefer axios because it's a bit easier to use. So I'll share my screen here real quick. We've got the wasmCloud TypeScript repo, which is where all our TypeScript projects have moved to. There are still some TypeScript projects in wasmCloud/wasmCloud if I remember correctly, but this is really where you should look for newer stuff, honestly updated examples for TypeScript, and best practices and things like that.

The wasmCloud TypeScript repository on screen

So the PR that's up here is this one — adding an example that uses axios to do a fetch. Native fetch works just fine: StarlingMonkey, which is the engine underneath that your JavaScript is running in when a WebAssembly component written in JavaScript is running, has support for fetch, and that bubbles up to the tooling like ComponentizeJS and JCO, which is what we use when we build components with wash, because we use standard tooling across the ecosystem. So fetch is supported, but it can be a question of what libraries you can pull in. We have some examples that build Node.js-like libraries, and those are nice, but obviously we can't have an example for every single kind of Node.js library that could be built.

The pull request adding an axios example to the wasmCloud TypeScript repo

Trying to build native libraries — for example, if you've ever seen node-gyp in your builds for Node.js, that means you're trying to build a native binding, like C++ or something else during the Node build — we can't include those, because that has to do with linking and is a bit more complex when you're trying to make that into a WebAssembly component. But for libraries like axios that have good browser and JavaScript-native bindings, or are written in a JavaScript-native way, we can use them kind of simply. It does require some tweaking, and this example is a good chance to show what that looks like.

So I'll jump down here. The real important bit is the Rollup file. Of course you can use any bundler you want — you can use esbuild, you can use Rollup, you can use Rolldown if you want, you can use whatever else. But the important thing to include, if you're using Rollup and want to use Node-style dependencies, is that you want to be able to resolve Node, to replicate the Node require and resolution methodology in your project. Because by default the WebAssembly JavaScript toolchain is not going to do all the things Node.js does when it tries to resolve a package. So you need to do the bundling step ahead of time and get one JavaScript file out, and then ComponentizeJS and the WebAssembly ecosystem JS tooling can work off one single JavaScript file. It's almost like you're bundling for a super-old browser — it's different, but kind of similar. You just generally want a bundle.

The Rollup config with Node resolution, CommonJS, TypeScript, and JSON plugins

So here in the Rollup config we've got TypeScript, we've got the Node resolution mechanism as a plugin, we've got CommonJS supported — so all the features there — and this JSON one is to enable JSON imports. Once you have Rollup set up — and of course you can just copy this setup and it'll just work — the code to use axios looks like this. It's pretty simple. The actual code you really need to care about is right here; there's not too much more than this. This bottom one is actually just an extra way to invoke this component. But here we're exporting the wasi:cli/run interface, which means you can run this with wasmtime run or jco run, and you can also call it with wash. Most of this is basic, pretty standard axios stuff. We hit jsonplaceholder.typicode.com, which is a convenient site for getting some JSON output back, and then we write to standard out with the stringified version of the response, which axios turns into JSON for us automatically. It's really easy to use in that way.

The TypeScript component code making an axios request and writing the response to stdout

One thing I'll show, in addition, is the WIT interface. Here's the WIT interface that corresponds to the JavaScript file we just saw. One thing I want to point out is that you don't see an import of wasi:http. For those who aren't familiar, when you make web requests from inside a WebAssembly module, you generally need to pull in the functionality to do that. So for example, if we're making an outgoing request, you'd normally see something like import wasi:http/outgoing-handler. In this case we actually don't need to, because JCO and the JavaScript WebAssembly ecosystem tooling will add in that import for you, because fetch is always available — that import is always available, essentially. So it's even simpler than you'd otherwise have to write in other languages. Keep that in mind in case you're wondering, in the WASI system, how we're able to make an HTTP call when we didn't ask for that capability. Well, it got added in when you built with JCO. It can be a surprise to people. So we'd love some feedback — if there are any other packages people commonly use that you'd love us to make an example for, we'd love to hear about it. And if you're trying to use axios, you can start here and build whatever you're trying to build.

The WIT interface for the axios component, exporting wasi:cli/run with no explicit HTTP import

Brooks Townsend 22:10

I just had a quick question. I'm actually not familiar with the axios library, but does it do anything on the HTTP incoming side, or is it just like a fetch? Is it primarily an outgoing HTTP thing?

Victor Adossi 22:29

Yeah, it's primarily outgoing HTTP. There's a lot of complexity in there — you could do things like attach hooks and do pre- and post-processing, and you can modify it in a lot of ways. But I think one of the main reasons people reach for it is that it just has slightly better defaults than fetch, and is a little bit more automatic. And of course projects that were built a while ago, before fetch was as ergonomic as it is now, would clearly be using axios. At this point there's a bunch of legacy code that's also built with axios, and axios is still good, so it's definitely widely used.

Brooks Townsend 23:20

Yeah, awesome. Thank you.

Victor Adossi 23:27

Oh, and Aditya has a great point in the chat that the error handling with axios is way better. There are a lot of people who are very big fans and like axios a lot more than fetch — it's one of those things that's always worth mentioning.

Brooks Townsend 23:52

I guess this also — from a new-example perspective, this is really nice, it's really clean. The more examples we get under our belt with libraries just working, feasibly there's JavaScript code out there that uses axios in a really simple way that now, with just a bundling assist, could compile to a WebAssembly component and speak WASI HTTP without changing the original code.

Victor Adossi 24:26

Yeah, that's definitely what this unlocks. With this configuration you're able to use, at the very least, things that use axios — and a lot of this same configuration will work for a lot of other libraries, especially ones that are isomorphic, so they run in both the browser and Node. I'm glad you stated that question, because that's a great time to mention the Node support that will eventually land in StarlingMonkey, and maybe even somewhere else. Depending on how we want to move this through the ecosystem, we do want Node.js built-ins in StarlingMonkey, ComponentizeJS, JCO, and so on, bubbling its way up — which means you'll get Node support in your WebAssembly components without doing anything. So this theoretically just unlocks all of the NPM ecosystem.

Right now a lot of the NPM and JavaScript ecosystem, whether in the browser or in Node, is available if it's pure JavaScript — because all you need to do is bundle it together, it's just JavaScript, it runs in StarlingMonkey, it runs in Wasm like normal. But if you use some interfaces or standard-library functions from Node that rely on platform things — for example, if you try to get a random number and Node expects /dev/urandom to be there to get a secure random number — that's obviously not going to work in WebAssembly. So someone has to do the work to port the Node standard library. Technically what Node.js brings is the standard library, so it's a little redundant to say "Node.js standard library," because it's Node plus V8 — that's really what Node is. But the point is someone has to implement the same fs interface, or the same random interface, and make that available. There are plans that this will happen at the StarlingMonkey level eventually, which means it'll be available at the WebAssembly JS component level without users having to do anything — you just write your component like normal, pull in your import like normal, and hopefully the Node shim works and makes whatever you pulled in just work off the shelf, which would be awesome.

Oh, I see there was a comment in the chat — they're pointing out the hello-world example. I'm really glad you like that, because one of the things we did very intentionally was, in the quickstart, show the quickest way to get started. A little bit of context: this is the HTTP hello-world example, a basic server that just returns "hello world" when you throw GET requests at it. In the docs we show the quickest way to get started, which is wash dev — that'll start your component and start the necessary providers. I won't go through the description because you can read faster than I can talk. But we also include the slow start, which is nice because it shows how to do what wash dev would have done for you, a little bit slower, with just wash. Because before wash dev existed, these were the steps anyone could use to build a component and start it on a running wasmCloud lattice — which feels like a word we haven't used in a while, the "lattice" word — how you could run a component in the slow, manual way. We were happy to include this because I think it's great to have other options, so people feel like they know the system a little bit more.

The HTTP hello world quickstart docs showing wash dev and the slower manual path

Brooks Townsend 29:38

Oh yeah, I saw you were unmuted, Jochen — I don't know if you had something.

Jochen Rau 29:40

No, no, nothing more to say. Just to say, this is a great thing — it's not just magic behind the scenes. The next step is to visibly go through the single steps, and then you can learn more from that.

Brooks Townsend 30:00

Yeah. Any other questions or feedback for Victor? Victor, thanks so much for coming in and showing off some of this work — this is super awesome to see.

Brooks Townsend 30:25

Alrighty. Hey, I actually got a message behind the scenes and wanted to share and give kudos for one more thing, to Dia, who's been doing a ton of work across a bunch of different issues on the wasmCloud side. Dia, if you're still watching, huge kudos to you. You've been putting in a ton of work on many different issues, especially since becoming a maintainer. On the wasmCloud side you've been pulling this cron job capability provider through a good couple rounds of feedback — we've looked at the interface, you've been implementing it in a distributed fashion, you've integrated it into the runtime, iterating on the WIT, iterating on the provider. The idea of calling something on a cron trigger is simple, but doing it in a distributed way with many providers running across a whole lattice is more complex, so great job carrying this one forward.

I saw that you said the cron job capability provider PR was ready for review, but the hold-offs in some new NATS features may make this a little bit simpler — so we'll look toward your feedback on that one. And then, for coming in kind of out of nowhere in the best way to be like "hey, now we can set memory limits per component" — this is awesome. I haven't taken a look at this one in depth; I think we'll probably want to look at how much changes on the control interface, and if it's not a lot, then we should roll it out as soon as we can. The control interface is one of those big old things, but you've come in and changed something that basically goes down the whole stack, all the way down to the Wasmtime engine layer. So a huge shout out for coming in and taking something that we've wanted to do for quite a while. Please keep bothering us if we're holding you up on reviews.

Oh, hey, there you are — we were just talking about you. I don't know if you're in a place to chat, but awesome work on some of the issues you've been working on lately. I wanted to ask: for the cron job capability provider PR, do you want a review on that one now, or did you want us to wait for a future NATS version so we can have that as an option? Feel free to respond via chat.

Brooks Townsend 33:36

Okay, nice, great — you said in chat we could implement the updated one in a few days. So we just need to get 2.11.2 in there with the updated version. For the updated version under the documentation, we'd just say: hey, if you're using the cron capability provider, make sure to have your NATS version set up to a minimum of 2.11.2. And in wash dev and everything, we can update that version so that everybody's on that by default for wasmCloud. Is that kind of what you were thinking? Oh yes, absolutely — but I don't know if you said that the test util uses... oh okay, so we're just a patch version behind. Easy. Awesome.

This probably looks like I'm just talking to myself here, but Dia is really here and messaging in the call, I swear. Awesome. Well, hey man, just awesome job on some of the recent work you've been taking — the per-component memory limits is something we've really wanted to do for a long time. So thank you so much for taking those issues and just jumping in on everything. And don't worry about not coming on the call — this is in the middle of the day, so everybody's got stuff all the time. Alright folks, that was all I really wanted to talk about today. Did folks have anything else they wanted to discuss, generally in wasmCloud land?

Brooks Townsend 35:44

Alrighty, well, I think we can give folks a little bit of time back today. Thank you all for coming to wasmCloud Wednesday — talking about issues and documentation and new exciting things in the JavaScript ecosystem. As always, this agenda for the community meeting is totally open. So if you're working on something cool in WebAssembly land, or you did something cool with wasmCloud, or you have a feature you want to discuss, just put up a PR, change the agenda — we welcome everything on this call. We'd love to have everybody participate like you all do every week. With that, I think we'll go ahead and call it, and we'll see you next week. Thanks, everybody. Have a wonderful day.