Using Web Server Middlewares
The Blocklet SDK comes bundled with a suite of powerful, ready-to-use middlewares for Express.js. These tools are designed to handle common web development challenges like security, SEO, and single-page application (SPA) routing, allowing you to build more robust and feature-rich blocklets with less boilerplate code.
This guide will walk you through the most essential middlewares and how to integrate them into your application.
CSRF Protection#
Cross-Site Request Forgery (CSRF) is a common web security vulnerability. The SDK's csrf middleware provides a straightforward way to protect your application against such attacks.
It works by creating a unique token for each user session and requiring that token to be sent with any state-changing request (like POST or PUT).
Usage
To enable CSRF protection, simply add the csrf and cookie-parser middlewares to your Express application.
Express.js Server Setup
import express from 'express';
import cookieParser from 'cookie-parser';
import { csrf } from '@blocklet/sdk/middlewares';
const app = express();
// cookie-parser is required for the csrf middleware to work
app.use(cookieParser());
// Apply the csrf middleware globally
app.use(csrf());
app.post('/api/data', (req, res) => {
res.json({ message: 'Data updated successfully!' });
});
// Your other routes...
app.listen(3000);How It Works
- Token Generation: For
GETrequests, the middleware automatically generates ax-csrf-tokencookie based on the user'slogin_token. - Token Verification: For
POST,PUT,PATCH, andDELETErequests, it compares thex-csrf-tokencookie with the value of thex-csrf-tokenHTTP header. If they don't match, the request is rejected. - Frontend Implementation: Your frontend client is responsible for reading the
x-csrf-tokencookie and sending its value in thex-csrf-tokenheader for all subsequent state-changing API calls.
Sitemap Generation#
A sitemap is crucial for SEO, as it helps search engines discover and index your application's pages. The sitemap middleware automates the creation of a compliant sitemap.xml file.
Usage
You provide a generator function that writes your application's URLs to a stream. The middleware handles the rest.
Sitemap Generation
import express from 'express';
import { sitemap } from '@blocklet/sdk/middlewares';
const app = express();
// A mock function to get dynamic data
const getBlogPosts = async () => [
{ slug: 'my-first-post', updatedAt: new Date() },
{ slug: 'my-second-post', updatedAt: new Date() },
];
app.get('/sitemap.xml', sitemap(async (stream) => {
// 1. Add static pages
stream.write({ url: '/' });
stream.write({ url: '/about' });
stream.write({ url: '/contact' });
// 2. Add dynamic pages from a database or API
const posts = await getBlogPosts();
posts.forEach(post => {
stream.write({ url: `/blog/${post.slug}`, lastmod: post.updatedAt });
});
}));
app.listen(3000);When a user or search engine crawler visits /sitemap.xml, this endpoint will return a dynamically generated XML sitemap.
SPA Fallback for Single-Page Applications#
Single-Page Applications (SPAs) handle routing on the client side, which can be problematic for SEO and direct URL access. The fallback middleware solves this by ensuring that all non-asset requests serve your main index.html file while allowing you to inject dynamic metadata for SEO and social sharing.
Usage
The fallback middleware should typically be placed at the end of your middleware chain to catch any GET requests that haven't been handled by other routes (like API endpoints or static file servers).
SPA Fallback Setup
import express from 'express';
import path from 'path';
import { fallback } from '@blocklet/sdk/middlewares';
import { env } from '@blocklet/sdk/config';
const app = express();
const publicPath = path.join(__dirname, '../dist');
// Serve static assets like CSS, JS, and images
app.use(express.static(publicPath));
// Your API routes go here
app.get('/api/user', (req, res) => res.json({ name: 'John Doe' }));
// The fallback middleware handles all other GET requests
app.use(fallback('index.html', {
root: publicPath,
// Dynamically set meta tags based on the request path
async getPageData(req) {
if (req.path.startsWith('/posts/')) {
const postId = req.path.split('/').pop();
const post = await getPostById(postId); // Fetch post data
return {
title: post.title,
description: post.summary,See all 12 lines
Key Features
- Dynamic Metadata: The
getPageDatafunction is the core feature, allowing you to return page-specifictitle,description, andogImagetags, which are then injected into the HTML response. - Automatic Injections: The middleware automatically injects the necessary Blocklet JavaScript (
__blocklet__.js) and theme styles into the HTML, ensuring seamless integration with the Blocklet Server environment. - Caching: It includes an in-memory cache to improve performance for frequently accessed pages.