Paths and Request Methods
Learning objectives
- Knows what paths are and can handle requests to paths.
- Knows what request methods are and can handle requests with different request methods.
The server that we previously studied is a HTTP server that responds to HTTP requests. Each request is made to a path using a specific request method. Let us look at paths and methods next.
Requested URL
The URL that has been requested can be accessed through the property url
of the request
-object. Running the following application launches a server that responds to the user with the URL that the request is made to.
import { serve } from "https://deno.land/std@0.222.1/http/server.ts";
const handleRequest = (request) => {
return new Response(request.url);
};
serve(handleRequest, { port: 7777 });
We can test the printed URL either by using the browser or by using the curl
command. In the following example, we first make a request to the root path of the server, i.e. to http://localhost:7777
, after which make a request to the path /hello
on the server, i.e. to http://localhost:7777/hello
.
curl http://localhost:7777
http://localhost:7777/%
curl http://localhost:7777/hello
http://localhost:7777/hello%
In the above example where the curl
command is run within a terminal, the percentage-sign %
visible in the output depicts the lack of a line change at the end of the response. When trying out the request in a browser, no percentage sign is shown.
Requested paths
If we wish to use the path of the URL, e.g. /hello
from http://localhost:7777/hello
, we can use the URL-class to create an URL
object out of the url
variable representing the requested URL. The created object has properties through which we can access a variety of url parts, including the the path, which is stored in a property called pathname
.
The example below launches a server that responds with the requested path.
import { serve } from "https://deno.land/std@0.222.1/http/server.ts";
const handleRequest = (request) => {
const url = new URL(request.url);
return new Response(url.pathname);
};
serve(handleRequest, { port: 7777 });
curl http://localhost:7777
/%
curl http://localhost:7777/hello
/hello%
Path-specific responses
Normally, when we make requests to different paths of websites, we get different responses. Let's mimic this behavior through a simple example. In JavaScript, comparisons can be made using the if
statement as follows.
const path = "hello world!";
if (path === "hello world!") {
console.log("The result of the statement evaluation was true.");
} else {
console.log("The result of the statement evaluation was false.");
}
In the above example, we check for an exact match (comparing both variable type and variable content). It is also possible to check whether a string contains another string -- this is done with the includes
-method of a string.
const path = "hello world!";
if (path.includes("hello")) {
console.log("The result of the statement evaluation was true.");
} else {
console.log("The result of the statement evaluation was false.");
}
The following example creates a server that responds with the message world
to requests that are made to the path /hello
and with the message ingredient
to requests that are made to a path containing the string secret
. Any other requests receive a response with the message hello
.
import { serve } from "https://deno.land/std@0.222.1/http/server.ts";
const handleRequest = (request) => {
const url = new URL(request.url);
let message = "hello";
if (url.pathname === "/hello") {
message = "world";
} else if (url.pathname.includes("secret")) {
message = "ingredient";
}
return new Response(message);
};
serve(handleRequest, { port: 7777 });
We can, again, try out the application using the browser or the command line. In the following example, the application is tried out with a few curl
requests.
curl http://localhost:7777
hello%
curl http://localhost:7777/world
hello%
curl http://localhost:7777/helloes
hello%
curl http://localhost:7777/hello
world%
curl http://localhost:7777/secret
ingredient%
curl http://localhost:7777/secrets
ingredient%
Request methods
Let's look at handling request methods next. Each HTTP request is made using a particular request method, of which GET
and POST
are the most common ones. The method GET
is used for retrieving content, while the method POST
is used for posting content.
The request method can be accessed through the property method
of the request
-object. Running the following application launches a HTTP server that responds to the user with the name of the method that the request was made with.
import { serve } from "https://deno.land/std@0.222.1/http/server.ts";
const handleRequest = (request) => {
return new Response(request.method);
};
serve(handleRequest, { port: 7777 });
Making a GET-request in curl
is easy.
curl http://localhost:7777
GET%
In order to make another type of a request with curl
, we need to use flag -X
to pass the request method as a parameter. In the following example, we first make a request using the request method POST
, after which we try to make a request with a request method called Alohomora
.
curl -X POST http://localhost:7777
POST%
curl -X Alohomora http://localhost:7777
Alohomora%
As you notice, even though Alohomora
is not a real HTTP request method, it still works -- in practice, it is both the browser's and the server's responsibility to make sure to adhere to existing standards and protocols. One could, on the other hand, also invent new ones..
Similar to working with paths, we can adjust the functionality of the server based on the request. In the following example, the server responds with the message Retrieving information, are you?
to requests made with the GET
-method, Posting information, are you?
to requests made with the POST
-method, and with the message Magicking, are you?
to requests made with the (above-invented) Alohomora
-method.
import { serve } from "https://deno.land/std@0.222.1/http/server.ts";
const handleRequest = (request) => {
if (request.method === "GET") {
return new Response("Retrieving information, are you?");
} else if (request.method === "POST") {
return new Response("Posting information, are you?");
} else if (request.method === "Alohomora") {
return new Response("Magicking, are you?");
}
};
serve(handleRequest, { port: 7777 });
curl http://localhost:7777
Retrieving information, are you?
curl -X POST http://localhost:7777
Posting information, are you?%
curl -X Alohomora http://localhost:7777
Magicking, are you?%
Interestingly, if we make a request that does not match any of the options outlined in the handleRequest
-function, we end up in a situation where the response from the server is empty, as shown below.
curl -X Hello http://localhost:7777
curl: (52) Empty reply from server
This is due to our implementation. There is no default processing strategy (i.e. else
-branch) in our handleRequest
-function. Let's fix this by adding an else
-branch. In this case, if the request method does not match the given options, the server will respond with the message I am unsure what I should do here!
-- we also adjust the function overall so that there is just a single return
statement.
import { serve } from "https://deno.land/std@0.222.1/http/server.ts";
const handleRequest = (request) => {
let message = "I am unsure what I should do here!";
if (request.method === "GET") {
message = "Retrieving information, are you?";
} else if (request.method === "POST") {
message = "Posting information, are you?";
} else if (request.method === "Alohomora") {
message = "Magicking, are you?";
}
return new Response(message);
};
serve(handleRequest, { port: 7777 });
Paths and methods
Creating an application that functions based on both paths and methods is naturally also possible. The following example responds to the request with a message that contains both the request method and the requested path.
In the following example, we use template literals, which are effectively an easy way to construct strings into which variable values are injected -- a variable that is injected to the string is added using a dollar sign and curly brackets, e.g. ${variable}
. Note that instead of the normal quotation marks that we use for strings (i.e. ''
) , we use backticks for the template literals (i.e. \
``).
import { serve } from "https://deno.land/std@0.222.1/http/server.ts";
const handleRequest = (request) => {
const url = new URL(request.url);
return new Response(`${request.method} ${url.pathname}`);
};
serve(handleRequest, { port: 7777 });
curl http://localhost:7777
GET /%
curl http://localhost:7777/hello-world
GET /hello-world%
curl -X POST http://localhost:7777/hello
POST /hello%
While writing and executing simple GET and POST requests using cURL is fast and straightforward, it can become tedious rather quickly when
repeated a lot when debugging applications and especially when the requests carry content (more on request content later on).
VSCode provides a REST Client plugin to alleviate server side testing.
The plugin allows executing HTTP queries from the editor when defined in a file with a .http
extension. The plugin supports cURL commands and queries in RFC 2616 specification format, for instance POST http://localhost:7777
.

Debugging applications
Remember to also look into how Deno can be debugged with Chrome Devtools and with VSCode. See the part on debugging your code in Deno Manual.