2: Ins and Outs of RouterRequest and RouterResponse
Let’s look back at that router handler we wrote in the last chapter.
You may recall that I mentioned that request
was a RouterRequest object and that response
was a RouterResponse object. Every route and middleware handler that we write will receive instances of these two objects. In this chapter, we’ll take a closer look at these objects and what we can do with them.
RouterRequest
RouterRequest contains information about the incoming HTTP request. Here’s a non-exhaustive example of some things we can find there. Try adding this to your project from the last chapter. (Or create a new project, if you prefer; just don’t forget you need to instantiate the router
variable and start Kitura at the end.)
Note that we’re using the all()
method here instead of the get()
one as we’ve used before. Using get()
tells Kitura we want our handler to fire only on GET requests, whereas using all()
tells Kitura we want it to fire on all request methods - GET, POST, and so on. These methods and Router objects in general will be examined in more depth later in this book.
Now we’ll request the path using Curl’s -d
flag to post an empty string to our request path.
The queryParameters
property is a [String: String] dictionary of the query parameters.
And the result:
There are a few more things that RouterRequest contains that are of varying level of interest, but these are the most relevant ones in my not so humble opinion. For now, have a look at RouterRequest.swift
in the Kitura project if you’re curious what else you can find there - but then come right back, because things will get more interesting soon.
RouterResponse
The flip side to RouterRequest, which manages data coming in, is RouterResponse, which manages data going out. You’ve already seen in previous examples how we used the send()
method to output strings that are sent to the user-agent; strictly speaking, each of those calls to send()
is appending the string to the body of the HTTP response.
We can use RouterResponse’s status()
method to set a custom status code. Pass it a case from the HTTPStatusCode
struct (defined in KituraNet’s HTTP/HTTP.swift
file). Let’s have a little bit of fun with that.
When we test with Curl, we get the expected status code.
RouterResponse has a headers
property that we can use as a [String: String] dictionary to set headers. It also has a few methods to shortcut the setting of some common headers.
Here’s the response. Note the new headers.
We could set a 301 Moved Permanently or 308 Moved Temporarily status and a “Location” header to redirect the user from one path to another, but RouterRequest provides some shorthand to do that.
(Confused by try?
above? See the “Error Handling” section of The Swift Programming Language for more information.)
We’ll test by using Curl’s --location
flag to tell it to follow “Location” headers when encountered.
Really, though, the star of the show is RouterResponse’s send()
method - or, should I say, methods. The one we’ve used in this book so far has had the following signature:
(That’s right; this whole time, the method has been returning a reference to the RouterResponse object itself, for chaining purposes. We’ve been ignoring it thus far and will probably continue to do so in this book, but just know this basically means you can do something like response.send("foo").send("bar")
if you wish.)
RouteResponse has many other send()
methods, though. For example, if we wanted to send binary data to the server - say, an image generated by an image library - we can use this one:
Or we can send a file read from the disk:
This book will not demonstrate these methods, but it might be handy to know they exist in the future.
For those of you interested in using Kitura to build a REST API server, you might be glad to know that RouterResponse has many methods for sending JSON responses, including the following two for sending a response currently in the form of a Foundation JSON object and a [String: Any] dictionary, respectively:
A later chapter in this book will give a more complex example of sending JSON responses to the client, but let’s play with a simple one now.
And here’s the output:
Note how Kitura automatically added a “Content-Type: application/json” header for us.
Bringing it Together
Let’s make a route with a path of “/calc” that takes two query parameters, “a” and “b,” adds them together, and returns the response. Let’s have our handler respond accordingly in the case that one or both parameters are missing or could not be converted to numbers (in this case, Float objects).
If you’ve been doing all right following along so far, I challenge you to stop reading now and go ahead and try to implement this yourself before peeking at the code sample below. My code doesn’t use anything that hasn’t been covered in this book so far. This time I’m going to show you my code’s output when I test it with Curl first, and show you the code later.
Okay, here’s my code. How does yours compare? (Of course, if yours is quite different, that doesn’t mean it’s wrong!)
If you’re an experienced web developer, you may be cringing at the use of query parameters. Can’t Kitura let us use a nice pretty path with no query parameters instead - maybe something like “/calc/12.44/-88.2”? Well, of course it can, and we’ll find out how when we examine Kitura’s Router object in the next chapter.
Last updated