Session & cookies
Ts.ED provides two decorators to get Session and Cookies values in your controller.
Installation
Before using the Session and Cookies, we need to install a module like express-session but you can use another module which follows the same convention.
npm install --save express-session yarn add express-session pnpm add express-session bun add express-session
npm install --save koa-session yarn add koa-session pnpm add koa-session bun add koa-session
WARNING
The default server-side session storage, MemoryStore, is purposely not designed for a production environment. It will leak memory under most conditions, does not scale past a single process, and is meant for debugging and developing.
For a list of stores, see compatible session stores.
Configuration
Edit your Server and add these lines:
import {PlatformApplication} from "@tsed/platform-http"; import {Configuration, Inject} from "@tsed/di"; import "@tsed/platform-express"; import compress from "compression"; import cookieParser from "cookie-parser"; import session from "express-session"; import methodOverride from "method-override"; @Configuration({ middlewares: [ cookieParser(), compress(), methodOverride(), session({ secret: "keyboard cat", resave: false, saveUninitialized: true, cookie: {secure: true} }) ] }) export class Server { @Inject() app: PlatformApplication; public $beforeRoutesInit(): void | Promise<any> { this.app.getApp().set("trust proxy", 1); // trust first proxy } }
Usage
Session
Get value
import {Session, BodyParams} from "@tsed/platform-params"; import {Get, Post} from "@tsed/schema"; import {Controller} from "@tsed/di"; import {Returns} from "@tsed/schema"; @Controller("/") export class MyCtrl { @Get("/whoami") whoAmI(@Session() session: any) { console.log("User in session =>", session.user); return session.user && session.user.id ? `Hello user ${session.user.name}` : "Hello world"; } @Post("/login") @Returns(204) login(@BodyParams("name") name: string, @Session("user") user: any) { user.id = "1"; user.name = name; } @Post("/logout") @Returns(204) logout(@Session("user") user: any) { user.id = null; delete user.name; } }
Set value
import {Controller} from "@tsed/di"; import {BodyParams, Session} from "@tsed/platform-params"; import {Post, Returns} from "@tsed/schema"; @Controller("/") export class MyCtrl { @Post("/") updateSession(@Session() session: any) { session.count = (session.count || 0) + 1; return "OK - " + session.count; } }
Cookies
Get value
import {Cookies} from "@tsed/platform-params"; import {Post} from "@tsed/schema"; import {Controller} from "@tsed/di"; import {IUser} from "./interfaces/IUser"; @Controller("/") class MyCtrl { @Post("/") getCookies(@Cookies() cookies: any) { console.log("Entire cookies", cookies); } @Post("/") getIdInCookies(@Cookies("id") id: string) { console.log("ID", id); } @Post("/") getObjectInCookies(@Cookies("user") user: IUser) { console.log("user", user); } }
Set value
import {Controller} from "@tsed/di"; import {BodyParams, Cookies} from "@tsed/platform-params"; import {Post, Returns} from "@tsed/schema"; @Controller("/") export class MyCtrl { @Post("/") updateSession(@Cookies() cookies: any) { cookies.count = (cookies.count || 0) + 1; return "OK - " + cookies.count; } }
Initialize session
Sometimes we want to be sure that the session is correctly initialized with the right values.
Let's start by creating a middleware CreateRequestSessionMiddleware in middlewares
directory:
import {Req} from "@tsed/platform-http"; import {Middleware} from "@tsed/platform-middlewares"; @Middleware() export class CreateRequestSessionMiddleware { use(@Req() request: Req) { if (request.session) { request.session.user = request.session.user || { id: null }; } } }
Then, add this middleware on the server:
import {PlatformApplication} from "@tsed/platform-http"; import {Configuration, Inject} from "@tsed/di"; import "@tsed/platform-express"; import compress from "compression"; import cookieParser from "cookie-parser"; import session from "express-session"; import methodOverride from "method-override"; import {CreateRequestSessionMiddleware} from "./middlewares/CreateRequestSessionMiddleware"; @Configuration({ middlewares: [ cookieParser(), compress({}), methodOverride(), session({ secret: "keyboard cat", // change secret key resave: false, saveUninitialized: true, cookie: { secure: false // set true if HTTPS is enabled } }), CreateRequestSessionMiddleware ] }) class Server { @Inject() app: PlatformApplication; public $beforeRoutesInit(): void | Promise<any> { this.app.getApp().set("trust proxy", 1); // trust first proxy } }
Finally, you can read and write values in your controller:
import {Session, BodyParams} from "@tsed/platform-params"; import {Get, Post} from "@tsed/schema"; import {Controller} from "@tsed/di"; import {Returns} from "@tsed/schema"; @Controller("/") export class MyCtrl { @Get("/whoami") whoAmI(@Session() session: any) { console.log("User in session =>", session.user); return session.user && session.user.id ? `Hello user ${session.user.name}` : "Hello world"; } @Post("/login") @Returns(204) login(@BodyParams("name") name: string, @Session("user") user: any) { user.id = "1"; user.name = name; } @Post("/logout") @Returns(204) logout(@Session("user") user: any) { user.id = null; delete user.name; } }
In addition, you can add integration tests with SuperTest and @tsed/testing
package. Here is an example of Rest API test:
import {PlatformTest} from "@tsed/platform-http/testing"; import * as SuperTest from "supertest"; import {Server} from "../../../src/Server"; describe("Session", () => { beforeAll(PlatformTest.bootstrap(Server)); afterAll(PlatformTest.reset); describe("Login / Logout", () => { it("should create session return hello world and connect a fake user", async () => { const request = SuperTest.agent(PlatformTest.callback()); // WHEN const response1 = await request.get("/rest/whoami").expect(200); await request.post("/rest/login").send({name: "UserName"}).expect(204); const response2 = await request.get("/rest/whoami").expect(200); await request.post("/rest/logout").expect(204); const response3 = await request.get("/rest/whoami").expect(200); // THEN expect(response1.text).toEqual("Hello world"); expect(response2.text).toEqual("Hello user UserName"); expect(response3.text).toEqual("Hello world"); }); }); });
import {it, expect, describe, beforeAll, afterAll} from "vitest"; import {PlatformTest} from "@tsed/platform-http/testing"; import * as SuperTest from "supertest"; import {Server} from "../../../src/Server"; describe("Session", () => { let request: any; beforeAll(() => { PlatformTest.bootstrap(Server); request = SuperTest.agent(PlatformTest.callback()); }); afterAll(PlatformTest.reset); describe("Login / Logout", () => { it("should create session return hello world and connect a fake user", async () => { const request = SuperTest.agent(PlatformTest.callback()); // WHEN const response1 = await request.get("/rest/whoami").expect(200); await request.post("/rest/login").send({name: "UserName"}).expect(204); const response2 = await request.get("/rest/whoami").expect(200); await request.post("/rest/logout").expect(204); const response3 = await request.get("/rest/whoami").expect(200); // THEN expect(response1.text).toEqual("Hello world"); expect(response2.text).toEqual("Hello user UserName"); expect(response3.text).toEqual("Hello world"); }); }); });
import {PlatformTest} from "@tsed/platform-http/testing"; import {expect} from "chai"; import * as SuperTest from "supertest"; import {Server} from "../../../src/Server"; describe("Session", () => { let request: any; before(PlatformTest.bootstrap(Server)); before(() => { request = SuperTest.agent(PlatformTest.callback()); }); after(PlatformTest.reset); describe("Login / Logout", () => { it("should create session return hello world and connect a fake user", async () => { // WHEN const response1 = await request.get("/rest/whoami").expect(200); await request.post("/rest/login").send({name: "UserName"}).expect(204); const response2 = await request.get("/rest/whoami").expect(200); await request.post("/rest/logout").expect(204); const response3 = await request.get("/rest/whoami").expect(200); // THEN expect(response1.text).to.eq("Hello world"); expect(response2.text).to.eq("Hello user UserName"); expect(response3.text).to.eq("Hello world"); }); }); });
TIP
You can find a working example on Express Session here.