1

I have a very basic deno app with oak module to build the http server. I want to send a http file, the index.html, only when the path is / (not /anyotherpath). From oak's github I have this code

app.use(async (ctx, next) => {
try{
    await ctx.send({
        root: `${Deno.cwd()}/public`,
        index:"index.html",
    });
}catch{
    await next();
}
});

But how do I send the html only for that given path? I also tried with Router from oak but I couldn't figure out how to serve the html file.

Tinaira
  • 727
  • 2
  • 7
  • 23

1 Answers1

2

If you only want to respond with the index.html file, and only at the root path /, you can do it the following way:

I've included comments for almost every line of the server example. Feel free to ask any questions in a comment if something is unclear. Be sure to reference the Oak documentation.

./public/index.html:

<!doctype html>
<html lang="en">

<head>
  <title>Hello world</title>
</head>

<body>
  <h1>Hello world</h1>
</body>

</html>

./main.ts:

import * as path from "https://deno.land/std@0.146.0/path/mod.ts";
import { Application, Router } from "https://deno.land/x/oak@v10.6.0/mod.ts";

// The directory of this module
const moduleDir = path.dirname(path.fromFileUrl(import.meta.url));

// The public directory (with "index.html" in it)
const publicDir = path.join(moduleDir, "public");

// A helper function to get the file contents
// of a specific file path in the public directory
function getPublicFile(...filePath: string[]): Promise<Uint8Array> {
  return Deno.readFile(path.join(publicDir, ...filePath));
}

// Create a router
const router = new Router();

// Only handle GET requests to the "/" path
router.get("/", async (ctx, next) => {
  // Set the contents of the "index.html" file to the response body
  ctx.response.body = await getPublicFile("index.html");

  // Set the appropriate resopnse type for HTML
  ctx.response.type = "text/html";

  // This isn't technically needed here, but it's good practice
  // because other middleware might need to run in more complicated routes
  await next();
});

// Create the app
const app = new Application();

// Use the router from above
app.use(router.routes());
app.use(router.allowedMethods());

// This is not needed, but is potentially nice for yourself in the console
function printStartupMessage({ hostname, port, secure }: {
  hostname: string;
  port: number;
  secure?: boolean;
}): void {
  const address = new URL(
    `http${secure ? "s" : ""}://${
      hostname === "0.0.0.0" ? "localhost" : hostname
    }:${port}/`,
  ).href;
  console.log(`Listening at ${address}`);
  console.log("Use ctrl+c to stop");
}

// Run the function above when the server starts listening
app.addEventListener("listen", printStartupMessage);

// Start the server
await app.listen({ port: 8000 });

% deno run --allow-net --allow-read main.ts        
Listening at http://localhost:8000/
Use ctrl+c to stop

Requests to http://localhost:8000/ will respond with the index.html file above, and all other routes will respond with a 404 Not Found response.

jsejcksn
  • 27,667
  • 4
  • 38
  • 62
  • Thanks. I made some changes into your code. I mixed up your code with mine. this is my code: `const app = new Application(); const router = new Router(); router .get('/', async(ctx, next)=>{ try{ await ctx.send({ root: `${Deno.cwd()}/public`, index: "index.html" }); }catch{ await next(); } }); app.use(router.routes()); app.use(router.allowedMethods()); await app.listen({port:8000});` and it works. But there is a problem. The html references some css – Tinaira Jul 05 '22 at 15:46
  • the css file is inside /public/styling/ which I reference with: `` Any tips how to fix the css issue? – Tinaira Jul 05 '22 at 15:49
  • Inline the CSS in the HTML file or create a new route for the CSS file if you don’t want to resolve files from the file system using `send`. – jsejcksn Jul 05 '22 at 16:49
  • but why do I have the problem with the css file only when I do the routing thing but works fine with my original code? why do I have to create a route just for the css? and what do you mean with "resolve files from the file system using `send`"? – Tinaira Jul 05 '22 at 17:14
  • @Tinaira I think you’ll benefit from reading the documentation (especially for the `send` function), and (re)familiarizing yourself with how route matching works. – jsejcksn Jul 05 '22 at 17:36
  • you are right. I am thinking the wrong way. – Tinaira Jul 05 '22 at 18:14
  • @Tinaira That's ok — it sounds like you're figuring things out. Is there anything in my answer that's still confusing at this point? Also, does it [answer your question](https://stackoverflow.com/help/someone-answers)? – jsejcksn Jul 05 '22 at 18:19
  • yes, actually there are few parts I don't really understand. maybe I will understand after I read the documentation. I don't understand `moduleDir`, `publicDir` and the `path.join` function. also maybe because I didn't check your code as it is but modified it from the beginning as in my previous comment. and I can't find a good explanation for `send`. anyway, thank you for your eford to explain things to me – Tinaira Jul 05 '22 at 21:06
  • 1
    @Tinaira Reading documentation is critical to understanding and effectively using software. You can reference Deno's built-in API documentation at https://doc.deno.land/deno/stable, and you can reference the `path` module and its methods here: https://deno.land/std@0.146.0/path – jsejcksn Jul 05 '22 at 21:16