Opens an external site in a new window
Mental Health Awareness Month
“Community”
RODNEY LAB
  • Home
  • Plus +
  • Newsletter
  • Links
  • Profile
RODNEY LAB
  • Home
  • Plus +
  • Newsletter
  • Links

Astro JS Middleware Example: Request Logging 📝 # Astro JS Middleware Example: Request Logging 📝 #

blurry low resolution placeholder image Astro JS Middleware Example
  1. Home Rodney Lab Home
  2. Blog Posts Rodney Lab Blog Posts
  3. Astro Astro Blog Posts
<PREVIOUS POST
NEXT POST >
LATEST POST >>

Astro JS Middleware Example: Request Logging 📝 #

Published: 2 years ago
6 minute read
Gunning Fog Index: 7.4
1 comment
Content by Rodney
blurry low resolution placeholder image Author Image: Rodney from Rodney Lab
SHARE:

🚀 Astro JS Middleware Example #

Astro now includes middleware, which performs a similar function to SvelteKit hooks, Deno Fresh middleware or middleware offered by serverless hosts (such as Cloudflare Workers). Here, we see an Astro JS Middleware example, as well as what middleware is and when you will pull it out of the Astro tool belt. For our example, we add request logging using Astro middleware with the Logtail serverless logging service.

What is Middleware? #

Middleware is just code which runs on a server to intercept requests, potentially modifying them. Astro route files will be invoked, typically for specific routes (/docs/getting-started, for example). Middleware is a little different in that respect, in that it can be less specific; you can invoke a middleware function for all routes, or selected sub-paths. With the logging example we consider, there will be some request details you want to capture, no matter which route the request was made to. Included here might be the request pathname, the time of the request, and perhaps even the time taken to respond. A single middleware file for all routes, rather than including the logging logic in the .astro file for every route, makes sense here.

We will see within your middleware function, you can peek at what the response will be, then send that response, “as-is” or even change certain parts, adding HTTP headers or even changing out parts of the response body, where that makes sense. We also see Astro lets you pass through data to .astro files using the locals object, offering another way to update content. Although Astro middleware works on both SSR and static routes, you will get the most out of it on SSR sites.

🤔 Why use Middleware? #

Some uses for middleware are:

  • analytics code;
  • logging;
  • performance and reliability measurement;
  • manipulating HTML content (e.g. highlighting search terms in body text);
  • adding response headers (such as HTTP security headers); and
  • proxying requests, for example to keep a WordPress backend URL private .

🧱 What are we Building? #

We will look at code for a basic Astro JS middleware logging example. In the code we shall see how you add a middleware function in Astro, as well as the most important methods, for intercepting requests. We also see how you can leave the response intact, yet still pass data through, for use in your front end code.

blurry low resolution placeholder image Astro JS Middleware Example: Screen capture shows an event logged in the Log tail console. Message reads astro-middleware-log. Timestamp and pathname are included, as, well as the event level, which is set to info.
Astro JS Middleware Example: Log event captured by Logtail

If that sounds like what you were looking for, then why don’t we get started? We won’t build an app from scratch, so, you probably want to create a feature branch on an existing project. If this is your first time working in Astro, though, see the quick guide on how to spin up a new Astro project.

🛠️ Astro SSR Middleware #

Middleware works on static as well as SSR sites, however you get most benefit on an SSR site, so we set the output and adapter fields in lines (10 & 11), below. Drop these if you want to stay static. And, of course, switch out the Cloudflare adapter if you prefer using another host.

astro.config.mjs
javascript
    
1 import { defineConfig } from 'astro/config';
2
3 import cloudflare from "@astrojs/cloudflare";
4
5 // https://astro.build/config
6 export default defineConfig({
7 output: "server",
8 adapter: cloudflare()
9 });

🕵🏽 Astro JS Middleware: Middleware Code #

To add Astro middleware to all routes, just create a src/middleware.ts (or src/middleware.js) file which exports an onRequest handler:

src/middleware.ts
typescript
    
1 import { defineMiddleware } from 'astro:middleware';
2
3 export const onRequest = defineMiddleware(async ({ locals, request }, next) => {
4 const { url } = request;
5 const { pathname } = new URL(url);
6 const timestamp = new Date().toISOString();
7
8 (locals as { timestamp: string }).timestamp = timestamp;
9
10 const response = await next();
11
12 return response;
13 });

Some interesting points here:

  • onRequest has two arguments: a context object and next
    • request on the context object is the incoming HTTP request from which you can destructure a URL, as well as other fields, which you will be familiar with 
    • locals (on the context object) lets us pass out data from middleware
    • next is a function; calling that function gives you access to the response that the route normally generates (without middleware)
  • onRequest returns a response object; in this case it is just the response which would have been sent anyway, though you can modify the response, adding HTTP headers or tinkering with the body

We also set locals.timestamp, above. We will see that value is passed through to the front end code a little later.

Astro JS Middleware Example: Adding Logging #

For our example, we want to log the request to our serverless logging service. Since we are just reporting, onRequest can just return the response which would have been sent anyway (no need to modify the response).

Here is the extra code for logging a few response details, using Logtail:

src/middleware.ts
typescript
    
1 import { defineMiddleware } from 'astro:middleware';
2 import { pack } from 'msgpackr';
3
4 const logtailSourceToken = import.meta.env.LOGTAIL_SOURCE_TOKEN;
5
6 export const onRequest = defineMiddleware(async ({ locals, request }, next) => {
7 const { url } = request;
8 const { pathname } = new URL(url);
9 const timestamp = new Date().toISOString();
10
11 (locals as { timestamp: string }).timestamp = timestamp;
12
13 const logData = {
14 dt: timestamp,
15 level: 'info',
16 message: 'astro-middleware-log',
17 item: {
18 pathname,
19 },
20 };
21
22 await fetch('https://in.logs.betterstack.com', {
23 method: 'POST',
24 headers: {
25 Authorization: `Bearer ${logtailSourceToken}`,
26 'Content-Type': 'application/msgpack',
27 },
28 body: pack(logData),
29 });
30
31 const response = await next();
32
33 return response;
34 });

Logtail has a REST API , and we can send the log data using fetch; notice fetch is simply available in line 25; no need to import it. You might notice, from the Content-Type header, that the message body is in msgpack format. This is a slightly more efficient format than JSON. To encode the logData regular JavaScript object in msgpack format, we use the msgpackr package, imported in line 2. The final piece to note is that you will need to add your LOGTAIL_SOURCE_TOKEN to your .env file, sggo that you can import it in line 4.

🖥️ Astro JS Middleware Example: Frontend #

You can update the response in your middleware, perhaps replacing template parameters. We might use this technique to vary content by region or time of day, and can do so just by altering the returned response from within the middleware. Another way of adding new data in middleware is using the locals object. In the middleware code, we added the timestamp there:

    
locals.timestamp = timestamp;

We can access that value in individual .astro files. Here is an example:

src/pages/index.astro
astro
    
1 ---
2 const { timestamp } = Astro.locals as { timestamp: string };
3 ---
4
5 <html lang="en-GB">
6 <head> <!-- TRUNCATED... -->
7 </head>
8
9 <body>
10 <main class="container">
11 <section class="content">{timestamp}</section>
12 </main>
13 </body>
14 </html>

In line 2, we pull our timestamp off Astro.locals. Note, this could be any arbitrary value we decided to include in the middleware function, though it should be possible to serialize the value as JSON. Finally, that value is now available for use in markup, as in line 11.

blurry low resolution placeholder image Astro JS Middleware Example: Screen capture shows a browser window with a timestamp in large text.
Astro JS Middleware Example: Timestamp fed through Astro Middleware locals

Interestingly, middleware works on static as well as SSR sites. For a static site, though, the value displayed here would be the time stamp at build time, rather than at the point the request was made. This is still useful, though, for example to include build time in a page footer.

🗳 Poll #

Are you already using Middleware with an Astro site?
Voting reveals latest results.

🙌🏽 Astro JS Middleware Example: Wrapping Up #

In this post, we saw an example of using the Astro middleware API. In particular, we saw:

  • how to add middleware to your Astro site;
  • how you might use Astro middleware for request logging; and
  • using Astro.locals to pass out data from middleware for use in markup.

You can see the full code for this project in the Rodney Lab GitHub repo . Also see the Astro docs . I do hope you have found this post useful, and am keen to hear how you will use middleware in your next projects. Also, let me know about any possible improvements to the content above.

🏁 Astro JS Middleware Example: Summary #

Does Astro support middleware? #

Yes! Though at the time of writing, support is experimental. While Astro middleware remains experimental, you will have to enable it manually. You can enable Astro middleware by setting `experimental.middleware` to `true` in your `astro.config.mjs` `defineConfig` object. Once that is set, add a `src/middleware.ts` (or equivalent JavaScript) file to your project. You need to export an `onRequest` function from there. `onRequest` itself, has two arguments, the context (similar to Astro endpoint context) and `next`. `next` is a function which gives you access to the incoming request’s regular response object. If you are just adding middleware for logging, for example, you can return this response object without touching it. If you want to update template parameters within the response, on the other hand, return your updated response object instead.

Does Astro Middleware work with both SSG and static sites? #

Yes, Astro middleware works on static sites as well as SSG ones. We saw, as an example, you might use `Astro.locals` to add a build time stamp to the footer on every page. With middleware, you can add the timestamp logic to a single file: middleware.ts.

How can you add request logging in Astro? #

Astro middleware is a great place to add logging. You might want to track how long requests take, which regions you get most traffic from, or even which days or what time of day visitors are most active on the site. You can do all of that by adding logging, using a serverless log provider like Logtail. Logtail has a REST API, and it is quick to code up debug, info and error logs, for consumption in the Logtail console or further downstream.

🙏🏽 Astro JS Middleware Example: Feedback #

Have you found the post useful? Would you prefer to see posts on another topic instead? Get in touch with ideas for new posts. Also, if you like my writing style, get in touch if I can write some posts for your company site on a consultancy basis. Read on to find ways to get in touch, further below. If you want to support posts similar to this one and can spare a few dollars, euros or pounds, please consider supporting me through Buy me a Coffee.

blurry low resolution placeholder image ask Rodney X (formerly Twitter) avatar

Rodney

@askRodney

Just dropped a new post looking at a logging example with Astro middleware, and also pass out custom locals data.

Hope you find it useful!

#askRodneyhttps://t.co/8sy96786B4

— Rodney (@askRodney) May 15, 2023

Finally, feel free to share the post on your social media accounts for all your followers who will find it useful. As well as leaving a comment below, you can get in touch via @askRodney on Twitter, @[email protected]  on Mastodon and also the #rodney  Element Matrix room. Also, see further ways to get in touch with Rodney Lab. I post regularly on Astro as well as SEO. Also, subscribe to the newsletter to keep up-to-date with our latest projects.

Thanks for reading this post. I hope you found it valuable. Please get in touch with your feedback and suggestions for posts you would like to see. Read more about me …

blurry low resolution placeholder image Rodney from Rodney Lab
TAGS:
ASTRO

Related Posts

blurry low resolution placeholder image Get Started with SvelteKit Headless WordPress

Get Started with SvelteKit Headless WordPress

plus
sveltekit
<PREVIOUS POST
NEXT POST >
LATEST POST >>

Leave a comment …

Your information will be handled in line with our Privacy Policy .

Comments

  • There is code that is not used

    import type { MiddlewareHandler } from 'astro'; MiddlewareHandler is not used in the code

    2 years ago

Ask for more

1 Nov 2022 — Astro Server-Side Rendering: Edge Search Site
3 Oct 2022 — Svelte eCommerce Site: SvelteKit Snipcart Storefront
1 Sept 2022 — Get Started with SvelteKit Headless WordPress

Copyright © 2020 – 2025 Rodney Johnson. All Rights Reserved. Please read important copyright and intellectual property information.

  • Home
  • Profile
  • Plus +
  • Newsletter
  • Contact
  • Links
  • Terms of Use
  • Privacy Policy
We use cookies  to enhance visitors’ experience. Please click the “Options” button to make your choice.  Learn more here.