Step-By-Step Guide
Building a tiny HTTP application
Overview
This guide helps you build a tiny HTTP application using the HTTP module’s Application class. If you want a finished app instead of a walkthrough, view the examples.
Recommended Reading
- Complete the Prerequisites
- Read the concepts on HTTP applications and resources
Objectives
To gain familiarity with:
- the HTTP module’s
Applicationclass; - how
Applicationcan be used in different runtimes; - receiving and handling requests; and
- responding to requests.
Instructions
End State
After completing the steps in this section, your project's directory should look similar to the directory tree below.
- app.js
Before You Get Started
- All of the code will be written in the same file for simplicity.
- Each next step adds code to the step before it. The code that is highlighted is the code that is being added.
- The code comments explain the code in a line-by-line manner. Please read them to gain a better understanding of the code.
- The Node.js code blocks will show code that creates a
contextobject. Thiscontextobject contains theurlandmethodfields the HTTP module’sApplicationrequires. These fields are mentioned in Concepts > HTTP Application > Handler Requirements. - Deno and Cloudflare Workers provide a global
URLPattern, so they use the native module. Node and Bun do not, so they use the polyfill module. The two modules are otherwise identical. See Concepts > Native vs. Polyfill.
Steps and Verification
Initialize Your Project
npm init --yes
npm install @drashland/drashThe --yes flag accepts all defaults for the package.json file the init command creates for you. Learn more about the --yes flag here .
Define Your Resource
A resource is a class that answers requests for one or more paths. You define one using the Resource class.
import {
Resource,
} from "@drashland/drash/modules/http.polyfill.js";
class Home extends Resource {
paths = ["/"];
GET(context) {
context.response.end("Oh so easy");
}
}Good to know
Node’s node:http server hands you an IncomingMessage and a ServerResponse — not a Web Request and Response. Because of that, this resource writes to context.response directly instead of returning a response. The context object is built in Step 4 - Add Your App to Your Server.
Build the Application
An application routes requests to the resources you give it. You build one using the Application class.
import {
Application,
Resource
} from "@drashland/drash/modules/http.polyfill.js";
class Home extends Resource {
paths = ["/"];
GET(context) {
context.response.end("Oh so easy");
}
}
const app = Application
.builder() // Get the app builder so we can build an app easily.
.resources(Home) // Add the `Home` resource to the app.
.build(); // Build the app.Good to know
Drash uses the builder pattern to create objects. You will see build() calls many times throughout these documentation pages. See Concepts > Builders for why.
Add Your App to Your Server
Drash is not a server. Your runtime provides the server and you plug Drash into it to handle the request-response lifecycle.
import {
Application,
Resource
} from "@drashland/drash/modules/http.polyfill.js";
import { createServer } from "node:http";
class Home extends Resource {
paths = ["/"];
GET(context) {
context.response.end("Oh so easy");
}
}
const app = Application
.builder() // Get the app builder so we can build an app easily.
.resources(Home) // Add the `Home` resource to the app.
.build(); // Build the app.
const hostname = "localhost";
const port = 1447;
const server = createServer((request, response) => {
const context = { // Build the context object the app will process.
url: `http://${hostname}:${port}${request.url}`, // `url` must be absolute. `request.url` is path-only here.
method: request.method, // `method` tells the app which resource method to call.
request, // Passed along so resources can read the raw request.
response, // Passed along so resources can write the response.
};
return app // Let the app
.handle(context) // handle the context object
.catch(() => { // Catch errors and
response.statusCode = 500; // send a 500 response
response.end("Oops.");
});
});
server.listen(port, hostname);Run Your App
node app.jsThe file above uses import statements, so Node needs to treat it as an ES module. Either add "type": "module" to your package.json or rename the file to app.mjs.
With the app running, go to http://localhost:1447 in your browser. You should see something like:
Oh so easyKnown Behaviors
Seeing HTTPError: Not Found messages? Click here
HTTPError: Not Found messages? Click hereIf you see HTTPError: Not Found in the terminal where you are running your app, it is most likely from a favicon.ico request from your browser.
You can ignore this error or (if you want to exercise your resource creation skills) you can create a resource that handles GET requests to the /favicon.ico path. From there, you can use your chosen runtime’s reading APIs (e.g., readFile()) to send a favicon.ico file in the body of the response. For example, the favico.ico response you build could look something like:
return new Response(
await readFile("favicon.ico"), // Use your runtime's file reading API here
{
status: 200,
statusText: "OK",
headers: {
"content-type": "image/x-icon",
}
}
);