Episode #3: Rapid Side Projects with Cloudflare Workers and Workers Sites
Continuing API development with the Workers Router Template, Mocha and Test Driven Development
Hello. Hi, everyone. It's Trevor Noah. I mean, it's Steve Pack here for Episode 3, Season 1 of Rapid Side Projects with Cloudflare Workers.
I'm on the strategic partnerships team at Cloudflare.
I'm the solution engineer for that team.
But I don't write work. So the big disclaimer for all of this is this is a guy hacking around in his spare time.
You know, for enterprise, for your account, and, you know, everybody else docs and, you know, support other sources of truth.
But if you just get started with working to bash out some things quickly and productively, which is what I love about workers, then this is the place for you.
Recap Episode 1. So let's start sharing. Episode 1, we, we deployed a workers.
And it was a really sort of simple converter. Just to show is how quickly it is to get a, like a dynamic sort of client side dynamic website on to Cloudflare.
Cloudflare Workers. And so then we're sort of like, okay, like, how can we how can we build something a bit more functional, um, you know, let's ideally add an API.
And so we settled on a like a foreign currency exchange.
And so we started working on the API for that.
Um, we got to the point of having something deployed. And, you know, wanting to like, you know, checking that we could hit an API wrap, get a response are actually looking to do some some logic, if you recall, so we got as far as this sort of rate handler that would and we're just trying to like write our first test.
And we had that over here in mock up and we've got our first sort of issue here, which is that this response object isn't available in the node runtime.
And I think we looking up the the docs.
Shout out to Mozilla was the best docs for this stuff for the web.
Um, yeah. And that's where we got to. So that's where we're kicking off from.
And we're just going to see how far we can get in the next 27 minutes together.
I'm going to be taking like shortcuts. I'm going to be doing hacks to just sort of see how far we can get quickly.
Again, these aren't like hard and fast recommendations.
But I get things going and explore the platform can can help you get started.
Okay. Um, so when we get things like this, like Like the, the runtime where workers can run and like what we're running locally.
There's a few options.
One is to mock things out and have one thing run this time and one thing run at production and runtime clearly pros and cons, you know, there are tests won't match production.
There are workarounds. And there's also a tool wrangler dev, which allows you to Like run a sort of production like environment locally does require Internet connection, though.
So there's I'm going to go, which is to and sort of work around it.
And that is the logic that I'm really going to test is going to be an actually going in this right from Like from the API.
I'm not going to.
And then when I get it back. I'm just going to put in response. I would As well, but we won't do that today because I think there's a more sort of critical Sort of issue that you can run up against when you're doing rather do first.
So let's get going.
We're passing it with defined a certain API looks like this forward slash. So these like these are the one I get back and I'm going to assume That we're gonna get something rates with Some things like We do comma separated You know something like Like this.
And so we want to pull these out, send it to an actual for X, X, get the result back.
We might might catch it in the future. See, see how far we get. Okay. I'm gonna get a request.
And it's going to have a URL.
And so again, what's that going Like Yeah.
I'm doing this live with you and not having it all prepared is that you can sort of see like for real things in it and like one of the common ones is, you know, I'm looking at where the where the sort of best docs are so We're going to say New URL.
I know that the URL objects got some good Some good methods for me for doing things like getting Getting through parameters.
So what are we going to say here is equal to those new URL objects.
What does it have so search params, I think, is the one we want To see if my doxy.
Yeah, I get the IntelliSense, but not the messages. And is this a So what they say we're going to get pairs.
So I'm hoping that when I pass in a URL with a bunch of bunch of things.
I'm going to get this pairs and then I'm going to some of our service.
Let's just sort of See if we've got this part. Going on. Um, Just see, do we get do we get anything here.
Because part of if you remember where we we left off we're returning response and that wasn't part of the runtime.
So instead, I'm going to just test like the logic.
You know, rather than something which doesn't really have a lot of logic and we'll look at mocking that a bit later.
Okay. Um, so at the moment I'm expecting this will just give me some pairs.
What does it look like I did.
So this takes in a request. So just mock this out manually. The one thing that we're getting from this is the URL like Right.
Yeah. Okay, so far, so good.
So we're avoiding this response, not by fixing it just by circumventing it because we're not testing this logic.
We're just testing this This looks right.
We're getting our pairs. So let's actually go and like right Maybe sort of the integration test to see if we can actually get some A Lucky service.
I found earlier.
Where, yeah, it looks Pretty good in that it's sort of passing in it sort of Sort of shape, I guess, to the API that I was thinking about.
So it's API code slash live and then comma separate list of pairs.
Okay, so far, so good. Right. So, um, let's keep Going with this.
So, Sort of, I guess you call it like the origin URL or the API according to We're going to say is This And we're going to want to pass pairs.
So I haven't split them at this point that actually, you know, the format that I'm defining for our API is exactly what what the website takes.
So let's just do that. Fine. I sort of natural reaches to reach for like axios or request or some sort of request library.
But I know that Again, one of the cool things with workers is it's really built around the web sort of service worker API, which is actually really helpful in lots of ways.
And it makes you sort of Like your workers and Service right for the web actually quite, quite similar.
Okay, so what is the fetch. Client. Like me, particularly in hat mode.
It's just give me the give me the code example code.
So let's see if that works. And I'm just going to return the raw answer.
What that looks like. Okay, so I've constructed a URL.
Let's Test. So now we're actually respecting some sort of response.
That's probably going to be Jason's If we actually get anything.
Which we don't Second problem.
Fetch also isn't defined. So it probably feels like this is happening a lot, but this is really like just the most common ones that you'll hit.
And once you work around these, you can really get, you know, So, um, yeah.
Again, fetch isn't defined in node. So at this point we're thinking actually maybe You know, maybe I'm node isn't the right sort of local development environment for this.
I still think so. For me, at least. Anyway, I'm pretty familiar with it.
And once you sort of got the little things in place that you need to To work around it like smooth.
Okay, so the way I go about this is with just a really simple dependency injection.
This is a class that expose a method fetch which calls fetch.
So because this will be defined in the workers runtime.
It's going to work fine. And a pass in something different, but with the same interface and that works essentially the same at test time.
And that's, um, that's just one Like has been able to get me sort of, you know, going pretty quickly, you know, on site projects.
Plus, once you do it once you know you really just start using it.
I would love Anyone watching or anyone on the questions to share, share how the folks do this.
All or You know, whether you do something similar or with the mock out sort of factions way.
This is my approach.
So if we pass one in, we're going to use that. Otherwise, we're going to use this one.
And again, all this one. It has one method same params as the You know, as the window or worker.
And then calls Set of return fetch. We're just going to say this Picture.
And that should But need a test version.
Right. So for You know, one that that node runs So, Slightly just to speed this up a little bit.
I will find an old That has this defined And it will look pretty, pretty similar to the first test feature.
One same interface, but uses a package called node fetch That actually called Node fetch So basically, as you can guess, like that's going to provide, you know, an implementation of the For node.
But I sort of wrap it. I can't actually remember the original reason now.
I couldn't figure out. But anyway, I know this one works pretty well for me.
So We're going to need And we set in.
So now hopefully That gets it passing as a dependency. When this calls get right, it's going to use that one called node fetch actually it'll do the same thing in the end, which is call that URL.
Actually, Okay, so the URL looks right.
So this was this is a sink.
Often when you just get like something empty or you're getting a Result will often be that you're not waiting on the response for something so that you can see.
So that felt like it went out over the wire took a second. Not a super interesting result.
So what is fetch Return For most that results to a response.
Okay, so that should be getting a response. Yeah, so response.
We've got headers status. And then some Methods to get a readable stream.
I think we've got some more here. Okay, so here's one that returns Jason and here's one that returns and that's not super obvious that I'm pretty sure this is a sink.
Yeah. Again, another promise. Okay, so we just learned was We get We actually need to get the data out.
This, although it was also a sink.
So are we starting to get data.
Yes, we're getting rates.
Okay, now, Vision here where I'm going to return this raw Actually, and I've got this code.
I don't really just want the rates so Also on the air handling so far as you can see, um, let's just get one.
Okay, so right. Seems a reasonable sort of shape of an API, like what I'm thinking here is if I had other origins and, you know, maybe picked one that was this like did a race or for whatever the reason, um, you know, to make sure I've defined my response sort of schema.
It's actually So we'll do, we'll do that. So I guess more complete test and you'll notice here.
So this, you know, Tests, I'll leave it up to the reader to decide how they want to structure things like do you want a unit test section integration test section, you separate all that stuff.
I'm just see what we have for the moment.
Okay, so we're actually expecting to get now a Like a rates object back and we're going to expect that there's something there on So we're expecting there'll be a right And And we're expecting that, um, that that rate also has a value.
More specifically, a rate Looks like it's a float.
So let's Make sure that we're getting Decent Negative.
I think so.
Reminder in these times. Negative interest rates, but no negative exchange rate.
That doesn't quite make sense. Okay. Alright, so This is our This is not defined test all and 32 Keep in will keep in this just Have visibility until we know it all looks good.
Oh, so, so far, so good.
So this is the part where testing, you know, remember again.
Now skipping, you know, this part's not being properly tested. We should get back to that at some point and can see just there.
I wasn't waiting on that. So if we just deployed, I would have to debug so good indication, we should we should Figure out our mocking of response later.
Okay, but it looks like if we And called it, we would get real real rates.
Let's do that. Did I did I do anything around deployment for the API.
I think we did for the site. Don't know if we did for the API.
Let's Copy that. Reasonable way to do it. Where are we package.json. No, we've just got.
So let's Have a good time seven minutes.
I guess if we get an API up that's returning some real data and then we can come back next time to actually call it from the UI that be good result.
Wait, is any valid and async function.
So that's a, that's a nice thing.
So my own tests didn't pick that up. But, um, you know, building before Before deploying actually did Interesting.
Hey, All right. Let me see. This is a benefit of having Done a couple of things before.
To a previous one. What are we doing here. Actually look like Looks like the Router is probably smart enough to do that for us.
So this Yep. Trying to deploy here.
Oh, There was no build.
Why was that I think we we we generated the site from a template.
Went from scratch. Right. So let's just make sure I've got our command. Right way.
Build Publish And we'll build anyway for our Site.
I was building. Fair enough. So for this probably like wrangle public Deployed We didn't change any routes.
So theoretically, if I was to go Right.
Start with one No, it wasn't.
So this is currently an object Turn object. Guess no surprise. I get to return to the client as an object.
Now, I could put like patients last Jason in here because Because I'm not like this.
I don't want to like keep adding logic To To this method. Exactly.
But I would have liked to Let's see if we can Let's just see if we can do this.
Content And The pressure of live TV.
Something meaty out there for the audience per episode.
Okay, let's just do that. And I don't know if I actually do this or Some runtime smarts will have done this for me because of the content type, but just to try and give us our best shot of getting it out the door.
In the next 120 seconds or less.
Try this. Cool.
So We have an API. And, you know, with Some sort of interface for it. Not super restful, I guess, with the params, but we can argue that some other time.
So this puts us in a good spot for next episode because, you know, we started out just this one type of conversion to add You know, a API to it so we can, um, you know, improve this UI.
So you can go to the black converter area or the Yeah, and then go from there.
I should have mentioned I haven't read the terms of service for this.
Um, I'm not suggesting that this just unlimited requests, um, you know, will be okay to go and check that out.
But, um, you know, for demo purposes. I think it's, um, it's probably pretty fun.
Things like caching in future episodes to make sure that we don't we don't sort of overwhelm this in the Site gets wildly popular as the go to conversion place on the web.
Yeah, right. To the countdown.
Next up, we've got Doug Kramer head of legal Founders focus is going to talk to a founder of drift.
Um, it sounds really interesting courage, courage, you all to stick around and see