En omfattande guide för att förstÄ och implementera TypeScript-mellanprogram i Express.js-applikationer. Utforska avancerade typpmönster för robust och underhÄllbar kod.
TypeScript Mellanprogram: BemÀstra Typpatrön för Express Mellanprogram
Express.js, ett minimalistiskt och flexibelt webapplikationsramverk för Node.js, tillÄter utvecklare att bygga robusta och skalbara API:er och webbapplikationer. TypeScript förbÀttrar Express genom att lÀgga till statisk typning, förbÀttra kodunderhÄll och fÄnga fel tidigt. Mellanprogramfunktioner Àr en hörnsten i Express, vilket gör att du kan fÄnga upp och bearbeta förfrÄgningar innan de nÄr dina rutt-hanterare. Den hÀr artikeln utforskar avancerade TypeScript-typpmönster för att definiera och anvÀnda Express-mellanprogram, vilket förbÀttrar typsÀkerheten och kodtydligheten.
FörstÄ Express Mellanprogram
Mellanprogramfunktioner Àr funktioner som har Ätkomst till begÀranobjektet (req), svarobjektet (res) och nÀsta mellanprogramfunktion i applikationens begÀran-svar-cykel. Mellanprogramfunktioner kan utföra följande uppgifter:
- Exekvera vilken kod som helst.
- Gör Àndringar i begÀran- och svarobjekten.
- Avsluta begÀran-svar-cykeln.
- Anropa nÀsta mellanprogramfunktion i stacken.
Mellanprogramfunktioner körs sekventiellt nÀr de lÀggs till i Express-applikationen. Vanliga anvÀndningsfall för mellanprogram inkluderar:
- Logga begÀranden.
- Autentisera anvÀndare.
- Auktorisera Ätkomst till resurser.
- Validera begÀrandedata.
- Hantera fel.
GrundlÀggande TypeScript Mellanprogram
I en grundlÀggande TypeScript Express-applikation kan en mellanprogramfunktion se ut sÄ hÀr:
import { Request, Response, NextFunction } from 'express';
function loggerMiddleware(req: Request, res: Response, next: NextFunction) {
console.log(`Request: ${req.method} ${req.url}`);
next();
}
export default loggerMiddleware;
Detta enkla mellanprogram loggar begÀransmetoden och URL:en till konsolen. LÄt oss bryta ner typannotationerna:
Request: Representerar Express-begÀranobjektet.Response: Representerar Express-svarobjektet.NextFunction: En funktion som, nÀr den anropas, exekverar nÀsta mellanprogram i stacken.
Du kan anvÀnda detta mellanprogram i din Express-applikation sÄ hÀr:
import express from 'express';
import loggerMiddleware from './middleware/loggerMiddleware';
const app = express();
const port = 3000;
app.use(loggerMiddleware);
app.get('/', (req, res) => {
res.send('Hello, world!');
});
app.listen(port, () => {
console.log(`Server listening on port ${port}`);
});
Avancerade Typpatrön för Mellanprogram
Ăven om det grundlĂ€ggande mellanprogramsexemplet Ă€r funktionellt saknar det flexibilitet och typsĂ€kerhet för mer komplexa scenarier. LĂ„t oss utforska avancerade typpmönster som förbĂ€ttrar mellanprogramutveckling med TypeScript.
1. Anpassade BegÀran/Svarstyper
Ofta behöver du utöka Request- eller Response-objekten med anpassade egenskaper. Till exempel, efter autentisering, kanske du vill lÀgga till en user-egenskap till Request-objektet. TypeScript lÄter dig förstÀrka befintliga typer med hjÀlp av deklarationssammanslagning.
// src/types/express/index.d.ts
import { Request as ExpressRequest } from 'express';
declare global {
namespace Express {
interface Request {
user?: {
id: string;
email: string;
// ... other user properties
};
}
}
}
export {}; // This is needed to make the file a module
I det hÀr exemplet förstÀrker vi Express.Request-grÀnssnittet för att inkludera en valfri user-egenskap. Nu, i ditt autentiseringsmellanprogram, kan du fylla i den hÀr egenskapen:
import { Request, Response, NextFunction } from 'express';
function authenticationMiddleware(req: Request, res: Response, next: NextFunction) {
// Simulate authentication logic
const userId = req.headers['x-user-id'] as string; // Or fetch from a token, etc.
if (userId) {
// In a real application, you would fetch the user from a database
req.user = {
id: userId,
email: `user${userId}@example.com`
};
next();
} else {
res.status(401).send('Unauthorized');
}
}
export default authenticationMiddleware;
Och i dina rutt-hanterare kan du sÀkert komma Ät req.user-egenskapen:
import express from 'express';
import authenticationMiddleware from './middleware/authenticationMiddleware';
const app = express();
const port = 3000;
app.use(authenticationMiddleware);
app.get('/profile', (req: Request, res: Response) => {
if (req.user) {
res.send(`Hello, ${req.user.email}! Your user ID is ${req.user.id}`);
} else {
// This should never happen if the middleware is working correctly
res.status(500).send('Internal Server Error');
}
});
app.listen(port, () => {
console.log(`Server listening on port ${port}`);
});
2. Mellanprogramfabriker
Mellanprogramfabriker Àr funktioner som returnerar mellanprogramfunktioner. Det hÀr mönstret Àr anvÀndbart nÀr du behöver konfigurera mellanprogram med specifika alternativ eller beroenden. TÀnk till exempel pÄ ett loggningsmellanprogram som loggar meddelanden till en specifik fil:
import { Request, Response, NextFunction } from 'express';
import fs from 'fs';
import path from 'path';
function createLoggingMiddleware(logFilePath: string) {
return (req: Request, res: Response, next: NextFunction) => {
const logMessage = `[${new Date().toISOString()}] Request: ${req.method} ${req.url}\n`;
fs.appendFile(logFilePath, logMessage, (err) => {
if (err) {
console.error('Error writing to log file:', err);
}
next();
});
};
}
export default createLoggingMiddleware;
Du kan anvÀnda den hÀr mellanprogramfabriken sÄ hÀr:
import express from 'express';
import createLoggingMiddleware from './middleware/loggingMiddleware';
const app = express();
const port = 3000;
const logFilePath = path.join(__dirname, 'logs', 'requests.log');
app.use(createLoggingMiddleware(logFilePath));
app.get('/', (req, res) => {
res.send('Hello, world!');
});
app.listen(port, () => {
console.log(`Server listening on port ${port}`);
});
3. Asynkron Mellanprogram
Mellanprogramfunktioner behöver ofta utföra asynkrona operationer, till exempel databasfrÄgor eller API-anrop. För att hantera asynkrona operationer korrekt mÄste du se till att next-funktionen anropas efter att den asynkrona operationen har slutförts. Du kan uppnÄ detta med hjÀlp av async/await eller Promises.
import { Request, Response, NextFunction } from 'express';
async function asyncMiddleware(req: Request, res: Response, next: NextFunction) {
try {
// Simulate an asynchronous operation
await new Promise(resolve => setTimeout(resolve, 100));
console.log('Asynchronous operation completed');
next();
} catch (error) {
next(error); // Pass the error to the error handling middleware
}
}
export default asyncMiddleware;
Viktigt: Kom ihÄg att hantera fel i ditt asynkrona mellanprogram och skicka dem till felhanteringsmellanprogrammet med next(error). Detta sÀkerstÀller att fel hanteras och loggas korrekt.
4. Felhanteringsmellanprogram
Felhanteringsmellanprogram Àr en speciell typ av mellanprogram som hanterar fel som uppstÄr under begÀran-svar-cykeln. Felhanteringsmellanprogramfunktioner har fyra argument: err, req, res och next.
import { Request, Response, NextFunction } from 'express';
function errorHandler(err: any, req: Request, res: Response, next: NextFunction) {
console.error(err.stack);
res.status(500).send('Something went wrong!');
}
export default errorHandler;
Du mÄste registrera felhanteringsmellanprogram efter alla andra mellanprogram och rutt-hanterare. Express identifierar felhanteringsmellanprogram genom förekomsten av de fyra argumenten.
import express from 'express';
import asyncMiddleware from './middleware/asyncMiddleware';
import errorHandler from './middleware/errorHandler';
const app = express();
const port = 3000;
app.use(asyncMiddleware);
app.get('/', (req, res) => {
throw new Error('Simulated error!'); // Simulate an error
});
app.use(errorHandler); // Error handling middleware MUST be registered last
app.listen(port, () => {
console.log(`Server listening on port ${port}`);
});
5. BegÀranvalideringsmellanprogram
BegÀranvalidering Àr en avgörande aspekt av att bygga sÀkra och tillförlitliga API:er. Mellanprogram kan anvÀndas för att validera inkommande begÀrandedata och sÀkerstÀlla att de uppfyller vissa kriterier innan de nÄr dina rutt-hanterare. Bibliotek som joi eller express-validator kan anvÀndas för begÀranvalidering.
HÀr Àr ett exempel med express-validator:
import { Request, Response, NextFunction } from 'express';
import { body, validationResult } from 'express-validator';
const validateCreateUserRequest = [
body('email').isEmail().normalizeEmail(),
body('password').isLength({ min: 8 }),
(req: Request, res: Response, next: NextFunction) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({ errors: errors.array() });
}
next();
}
];
export default validateCreateUserRequest;
Detta mellanprogram validerar fÀlten email och password i begÀranorganet. Om valideringen misslyckas returneras ett 400 Bad Request-svar med en array av felmeddelanden. Du kan anvÀnda detta mellanprogram i dina rutt-hanterare sÄ hÀr:
import express from 'express';
import validateCreateUserRequest from './middleware/validateCreateUserRequest';
const app = express();
const port = 3000;
app.post('/users', validateCreateUserRequest, (req, res) => {
// If validation passes, create the user
res.send('User created successfully!');
});
app.listen(port, () => {
console.log(`Server listening on port ${port}`);
});
6. Beroendeinjektion för Mellanprogram
NÀr dina mellanprogramfunktioner beror pÄ externa tjÀnster eller konfigurationer kan beroendeinjektion hjÀlpa till att förbÀttra testbarheten och underhÄllbarheten. Du kan anvÀnda en beroendeinjektionsbehÄllare som tsyringe eller helt enkelt skicka beroenden som argument till dina mellanprogramfabriker.
HÀr Àr ett exempel med en mellanprogramfabrik med beroendeinjektion:
// src/services/UserService.ts
export class UserService {
async createUser(email: string, password: string): Promise {
// In a real application, you would save the user to a database
console.log(`Creating user with email: ${email} and password: ${password}`);
await new Promise(resolve => setTimeout(resolve, 500)); // Simulate a database operation
}
}
// src/middleware/createUserMiddleware.ts
import { Request, Response, NextFunction } from 'express';
import { UserService } from '../services/UserService';
function createCreateUserMiddleware(userService: UserService) {
return async (req: Request, res: Response, next: NextFunction) => {
try {
const { email, password } = req.body;
await userService.createUser(email, password);
res.status(201).send('User created successfully!');
} catch (error) {
next(error);
}
};
}
export default createCreateUserMiddleware;
// src/app.ts
import express from 'express';
import createCreateUserMiddleware from './middleware/createUserMiddleware';
import { UserService } from './services/UserService';
import errorHandler from './middleware/errorHandler';
const app = express();
const port = 3000;
app.use(express.json()); // Parse JSON request bodies
const userService = new UserService();
const createUserMiddleware = createCreateUserMiddleware(userService);
app.post('/users', createUserMiddleware);
app.use(errorHandler);
app.listen(port, () => {
console.log(`Server listening on port ${port}`);
});
BÀsta Metoder för TypeScript Mellanprogram
- HÄll mellanprogramfunktioner smÄ och fokuserade. Varje mellanprogramfunktion bör ha ett enda ansvar.
- AnvÀnd beskrivande namn för dina mellanprogramfunktioner. Namnet ska tydligt ange vad mellanprogrammet gör.
- Hantera fel korrekt. FÄnga alltid fel och skicka dem till felhanteringsmellanprogrammet med
next(error). - AnvĂ€nd anpassade begĂ€ran/svarstyper för att förbĂ€ttra typsĂ€kerheten. Ăka
Request- ochResponse-grÀnssnitten med anpassade egenskaper efter behov. - AnvÀnd mellanprogramfabriker för att konfigurera mellanprogram med specifika alternativ.
- Dokumentera dina mellanprogramfunktioner. Förklara vad mellanprogrammet gör och hur det ska anvÀndas.
- Testa dina mellanprogramfunktioner noggrant. Skriv enhetstester för att sÀkerstÀlla att dina mellanprogramfunktioner fungerar korrekt.
Slutsats
TypeScript förbÀttrar avsevÀrt utvecklingen av Express-mellanprogram genom att lÀgga till statisk typning, förbÀttra kodunderhÄll och fÄnga fel tidigt. Genom att bemÀstra avancerade typpmönster som anpassade begÀran/svarstyper, mellanprogramfabriker, asynkron mellanprogram, felhanteringsmellanprogram och begÀranvalideringsmellanprogram kan du bygga robusta, skalbara och typsÀkra Express-applikationer. Kom ihÄg att följa bÀsta metoder för att hÄlla dina mellanprogramfunktioner smÄ, fokuserade och vÀldokumenterade.