Skip to content
This repository has been archived by the owner on Jun 22, 2024. It is now read-only.

Feature/fastify examples session #26

Open
wants to merge 13 commits into
base: main
Choose a base branch
from
2 changes: 2 additions & 0 deletions .markdownlintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
node_modules
/servers/fastify/session/node_modules
7 changes: 6 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"scripts": {
"test:unit": "jest --coverage",
"test:onlychanged": "jest --onlyChanged --coverage",
"test:markdown": "markdownlint . --ignore ./node_modules",
"test:markdown": "markdownlint . ",
"lint": "standard",
"test": "npm run lint && npm run test:unit && npm run test:markdown"
},
Expand All @@ -20,6 +20,11 @@
"standard": "^14.3.3"
},
"dependencies": {
"connect-redis": "^5.0.0",
"fastify-cookie": "^4.0.2",
"fastify-session": "^5.0.0",
"is-docker": "^2.1.1",
"redis": "^3.0.2",
"yargs": "^15.3.1"
},
"standard": {
Expand Down
63 changes: 63 additions & 0 deletions servers/fastify/session/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
# Fastify Session

A common use case for a web framework is to provide session storage. Fastify has a [concept of plugins](https://www.fastify.io/docs/latest/Plugins-Guide/)
and the plugin for session is [fastify-session](https://github.com/SerayaEryn/fastify-session). These examples
will demonstrate server side session storage.

## Simple local http session demonstration using local storage

[http-session-server](./http-session-server/http-session-server.js)

The most simple demonstration is an http server using a memory store. A memory store would be a local nodeJS based
storage mechanism. This demonstrates the concept of
session in fastify but is not what you would want in production. You would want to use an https server and
you would want to use a network based storage mechanism. In order to scale your NodeJS based servers you
would need to share the session storage between multiple instances of the same program so that any particular
cookied request would find its own session.

In this example in addition to requiring fastify there are two additional modules being required. These are

- [fastify-session](https://www.npmjs.com/package/fastify-session)
- [fastify-cookie](https://www.npmjs.com/package/fastify-cookie)

The fastify cookie plugin will add support to read and set cookie headers. The fastify session plugin provides session
based storage on the localhost.

## Simple local https session demonstration using local storage

[https-session-server](./https-session-server/https-session-server.js)

Another simple demonstration is the use of https on your local machine using local nodeJS based storage. In order to
start **fastify** as an https server it is necessary to provide certificates. Localhost certificates have been provided
to save the user the difficulty of creating one. This is a command to create certificates.

```shell script
penssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout selfsigned.key -out selfsigned.crt -subj "/CN=localhost"
```

The key and cert are created using [openssl](https://www.openssl.org/) and were created on a linux ubuntu system. The
commands are similar for osx.

## Local https session using redis

[https-session-server-redis](./https-session-server-redis/https-session-server-redis.js)

A more realistic example of creating a session on fastify would involve using a network based store. This would allow
multiple instances of fastify to access the session data when a cookie is sent.
In order to run this you either have to have a local [redis](https://redislabs.com/get-started-with-redis/) running or
use docker. If you have [docker](https://www.docker.com/products/docker-desktop) installed then can simple bring the
service up

```shell script
docker-compose up
```

The server will be running on port 3000 and the session will be stored in the redis cache.

Each time you hit the url the response will tell you how many times you requested this URL.

```json
{
"hello": "route requested 6 times in this session"
}
```
34 changes: 34 additions & 0 deletions servers/fastify/session/http-session-server/http-session-server.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
'use strict'

/* These examples are based on those from the fastify-session plugin readme */

const Fastify = require('fastify')
const fastifySession = require('fastify-session')
const fastifyCookie = require('fastify-cookie')

const APP_PORT = 3000
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
const APP_PORT = 3000
const APP_PORT = process.env.PORT || 3000

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

agreed

const fastify = Fastify({ logger: true })
fastify.register(fastifyCookie)
const sessionOptions = {
secret: 'a secret with minimum length of 32 characters',
cookieName: 'example-name',
cookie: {
secure: false,
maxAge: 1000 * 60 * 3
}
}
fastify.register(fastifySession, sessionOptions)

fastify.get('/', async (request, reply) => {
if (request.session) {
request.session.count = request.session.count ? request.session.count + 1 : 1
}
return { hello: `route requested ${request.session.count} times in this session` }
})

fastify.listen(APP_PORT, function (err) {
if (err) {
fastify.log.error(err)
process.exit(1)
}
})
15 changes: 15 additions & 0 deletions servers/fastify/session/https-session-server-redis/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
FROM node:12-alpine

USER node

RUN mkdir /home/node/code

WORKDIR /home/node/code

COPY --chown=node:node package.json package-lock.json ./

RUN npm ci

COPY --chown=node:node . .

CMD ["node", "https-session-server-redis.js"]
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
-----BEGIN CERTIFICATE-----
MIIDCTCCAfGgAwIBAgIUGSuVcr1tSWFodB3chT1HG3ExSdEwDQYJKoZIhvcNAQEL
BQAwFDESMBAGA1UEAwwJbG9jYWxob3N0MB4XDTIwMDgxNjEzMzAwN1oXDTIxMDgx
NjEzMzAwN1owFDESMBAGA1UEAwwJbG9jYWxob3N0MIIBIjANBgkqhkiG9w0BAQEF
AAOCAQ8AMIIBCgKCAQEAx+TCGDTi5hULfciEG18Ec6M9aL+CbjQxFVKpLpoE2uKG
kJesSjze489PFV/355ai+afx/FV6yUSFTd5ZiBSFRPWecZ2/QVZdbkrdUjCF4EKN
+z40arZpb5l82R6RXgIfcZkcTjqrfX4TXoWrC5PhmdOtgG/BWCtwDSOBYfCb3uRP
iWyD2+9OLblbjOezuxrOYR6N6R+bIFtacp0Agunyd88RYeuYTTjWMmridf29Nip4
Tyg6fFmFcJ0BhzyrQQM95eSDoABJv7V001WUiXGI/Y47XdhUxL4J1F5ZEbp3GglP
lj5kzip4hIN4AOdRJOPiRDtJSUdHcBqc1qi1IJcj4QIDAQABo1MwUTAdBgNVHQ4E
FgQU9TlVrEOHqghi+3yxCL2dDOBwH8kwHwYDVR0jBBgwFoAU9TlVrEOHqghi+3yx
CL2dDOBwH8kwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEANDOt
uiMWeQhm8b/aBPlmC6ABDsQRGsZX9j3mlKcdoQmLfXJc6ZtfK+gi54hYQWDcprp+
Xa2odGLi1kKmn1Sv1kjHhA7sUrSZKV+1mAujDkO9lwygIRoqPqeW9DX4g8mfxWXd
X5zQ5ZaO8gAG1qgdGAut3JU0GLCduDBRJ6UJvzYrVGGY6Uhocp1u6u2drhC8QtJk
x4/piT/JFFzdGTAwpUCsYkElTW5sIEM4Nx1+g37My/KQqajWI38paa2TpMOiI5rU
MtVgL8QAKlly1TA8lmXtfwsod3Y4gnyd6F7Jr4Vzx2OcCPZn0uyz7lQRqbHT3hNU
ieLvVoq75jbffPxewQ==
-----END CERTIFICATE-----
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDH5MIYNOLmFQt9
yIQbXwRzoz1ov4JuNDEVUqkumgTa4oaQl6xKPN7jz08VX/fnlqL5p/H8VXrJRIVN
3lmIFIVE9Z5xnb9BVl1uSt1SMIXgQo37PjRqtmlvmXzZHpFeAh9xmRxOOqt9fhNe
hasLk+GZ062Ab8FYK3ANI4Fh8Jve5E+JbIPb704tuVuM57O7Gs5hHo3pH5sgW1py
nQCC6fJ3zxFh65hNONYyauJ1/b02KnhPKDp8WYVwnQGHPKtBAz3l5IOgAEm/tXTT
VZSJcYj9jjtd2FTEvgnUXlkRuncaCU+WPmTOKniEg3gA51Ek4+JEO0lJR0dwGpzW
qLUglyPhAgMBAAECggEAF/br8hz9CtqBCy5r8CAfF4H9jb5P88hcDhNf5w9d/6Pi
wBj+9dOAYU1sTMK5pNEhbs7cqwTQeKq3VJOQpkjXhWHxAewIjtu8zck56W2Zzz4L
aZCWliiSUWfUWO9aPCwC+wqBIzvTbXMc/VsHG5c6F8gR5/D9/AURJPIZw9Ulyr3c
IhAodL3SbqZUr7WT3ZzHeQ5WsDqq8Y8lOSIgemRO5RAkv3r7FQgUyoWu6P3fQTSd
Eb6ZLQ6xRnxNvKDGea1Bv5DI1Nuni9Cv7XoVDatUukYXMQqYrQWNXS20/OVzJxF2
tNsCbG0pZcEp0cf2tWTQHyYN/iMWEA63Aox0BGFkVQKBgQDtKq0EncX9zyiGreOD
WV6PSQamN4rfQlzkN77U+WNut3JDwUv5CdavpTt2Qr0g/wLsmovKpMUnwhERyO4X
JBL41/eAOtHeQzwYxE7aoVGFPS4/3QIGV8Bqd0rHgYJHztfa26WJWJcnIpwWBZgY
Oao1xlveI+3zPO++ajw8OA2HywKBgQDXxFzzb1oNM6E9+w+r/kXW1fUM2gln5RgU
Jdc+H/ckiJSGes3e7ci5zek53vgCMiQdmQ6kDON/bnArRg+ol7fCC9sUeuXg1TA4
cNaeBjf7fQhzb1CQlJp+h38Vy7NgkvPAkgI4PWJihgT7QEsiMn+k3mBHAXkfcbuh
WwJ2mbUVgwKBgBcaQSBh/hdrRpdX+QGigwOSKYOnhW+aF1Jj28MDSBxQ4mCXQ79O
pgsWHWS3u5SrQq2poFRtGId28BK7b/XxHaf/4awsDqWIByKifMvvSvGftBGkhb34
blXwqOgmRXqZO42mN8nZR2AYjvvWL6qsc1gpqmlJNrSrCu+RiayUCT1hAoGBAKaW
NgnBdC5zKU+4Uh5BwFwhbwRQJyju6QtNOAUAGwk65il6EQ7IWcyS3TnQG31ehyHO
9U3VoaPWeYX/nsFU+gw4qRoD1Q4kqwk4nYr+VCS4IVk2nWYzRaDhLk5+qmyqqMWK
NWqEgjx9KsVtm1S41nJNOto3mfOcFPh8UseM3xHPAoGBAKzHshWR+jmRrVp0XKrz
Yl/Vz1pCIg1bbQk9iip08FqJTpMMd3sr/XS/ULX5jaOeEQcT4JQRr8H84rhunoBu
AMCPCbqLNjpyxxY6zWftYOx4chLECh6/ro/EOOiJnxrQB5AHcHOoHi0mjl+Lux/q
1jbqcR5IfkapWhD2xuyLgVOz
-----END PRIVATE KEY-----
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
version: "3"
services:
fastify-session-with-redis:
build: .
ports:
- "3000:3000"
volumes:
- .:/home/node/code
- /home/node/code/node_modules
depends_on:
- redis
redis:
image: redis:6.0.5
ports:
- "6379:6379"
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
'use strict'

const path = require('path')
ghinks marked this conversation as resolved.
Show resolved Hide resolved
const Fastify = require('fastify')
const fastifySession = require('fastify-session')
const fastifyCookie = require('fastify-cookie')
const fs = require('fs')
const isDocker = require('is-docker')

const APP_PORT = 3000

// the docker compose service is called redis
let host = 'localhost'
if (isDocker()) {
host = 'redis'
}

const getCertificates = () => {
const cert = fs.readFileSync(path.join(__dirname, './certificates/selfsigned.crt'), 'utf-8')
const key = fs.readFileSync(path.join(__dirname, './certificates/selfsigned.key'), 'utf-8')
return {
cert,
key
}
}
const { key, cert } = getCertificates()

const fastify = Fastify({
https: {
key,
cert
},
logger: true
})

fastify.register(fastifyCookie)
fastify.register(require('fastify-redis'), { host })

const sessionOptions = {
secret: 'a secret with minimum length of 32 characters',
cookieName: 'example-redis-session',
cookie: {
secure: true,
maxAge: 1000 * 60 * 3
}
}
fastify.register(fastifySession, sessionOptions)
ghinks marked this conversation as resolved.
Show resolved Hide resolved

fastify.get('/', async (request, reply) => {
if (request.session) {
request.session.count = request.session.count ? request.session.count + 1 : 1
}
return { hello: `route requested ${request.session.count} times in this session` }
})

fastify.listen(APP_PORT, '0.0.0.0', (err) => {
if (err) {
fastify.log.error(err)
process.exit(1)
}
})
20 changes: 20 additions & 0 deletions servers/fastify/session/https-session-server-redis/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"name": "https-session-server-redis",
"version": "1.0.0",
"description": "",
"main": "https-session-server-redis.js",
"scripts": {
"start": "node https-session-server-redis.js"
},
"keywords": [],
"author": "",
"license": "MIT",
"dependencies": {
"connect-redis": "^5.0.0",
"fastify": "^3.2.0",
"fastify-cookie": "^4.0.2",
"fastify-redis": "^4.0.3",
"fastify-session": "^5.0.0",
"is-docker": "^2.1.1"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
-----BEGIN CERTIFICATE-----
MIIDCTCCAfGgAwIBAgIUGSuVcr1tSWFodB3chT1HG3ExSdEwDQYJKoZIhvcNAQEL
BQAwFDESMBAGA1UEAwwJbG9jYWxob3N0MB4XDTIwMDgxNjEzMzAwN1oXDTIxMDgx
NjEzMzAwN1owFDESMBAGA1UEAwwJbG9jYWxob3N0MIIBIjANBgkqhkiG9w0BAQEF
AAOCAQ8AMIIBCgKCAQEAx+TCGDTi5hULfciEG18Ec6M9aL+CbjQxFVKpLpoE2uKG
kJesSjze489PFV/355ai+afx/FV6yUSFTd5ZiBSFRPWecZ2/QVZdbkrdUjCF4EKN
+z40arZpb5l82R6RXgIfcZkcTjqrfX4TXoWrC5PhmdOtgG/BWCtwDSOBYfCb3uRP
iWyD2+9OLblbjOezuxrOYR6N6R+bIFtacp0Agunyd88RYeuYTTjWMmridf29Nip4
Tyg6fFmFcJ0BhzyrQQM95eSDoABJv7V001WUiXGI/Y47XdhUxL4J1F5ZEbp3GglP
lj5kzip4hIN4AOdRJOPiRDtJSUdHcBqc1qi1IJcj4QIDAQABo1MwUTAdBgNVHQ4E
FgQU9TlVrEOHqghi+3yxCL2dDOBwH8kwHwYDVR0jBBgwFoAU9TlVrEOHqghi+3yx
CL2dDOBwH8kwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEANDOt
uiMWeQhm8b/aBPlmC6ABDsQRGsZX9j3mlKcdoQmLfXJc6ZtfK+gi54hYQWDcprp+
Xa2odGLi1kKmn1Sv1kjHhA7sUrSZKV+1mAujDkO9lwygIRoqPqeW9DX4g8mfxWXd
X5zQ5ZaO8gAG1qgdGAut3JU0GLCduDBRJ6UJvzYrVGGY6Uhocp1u6u2drhC8QtJk
x4/piT/JFFzdGTAwpUCsYkElTW5sIEM4Nx1+g37My/KQqajWI38paa2TpMOiI5rU
MtVgL8QAKlly1TA8lmXtfwsod3Y4gnyd6F7Jr4Vzx2OcCPZn0uyz7lQRqbHT3hNU
ieLvVoq75jbffPxewQ==
-----END CERTIFICATE-----
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDH5MIYNOLmFQt9
yIQbXwRzoz1ov4JuNDEVUqkumgTa4oaQl6xKPN7jz08VX/fnlqL5p/H8VXrJRIVN
3lmIFIVE9Z5xnb9BVl1uSt1SMIXgQo37PjRqtmlvmXzZHpFeAh9xmRxOOqt9fhNe
hasLk+GZ062Ab8FYK3ANI4Fh8Jve5E+JbIPb704tuVuM57O7Gs5hHo3pH5sgW1py
nQCC6fJ3zxFh65hNONYyauJ1/b02KnhPKDp8WYVwnQGHPKtBAz3l5IOgAEm/tXTT
VZSJcYj9jjtd2FTEvgnUXlkRuncaCU+WPmTOKniEg3gA51Ek4+JEO0lJR0dwGpzW
qLUglyPhAgMBAAECggEAF/br8hz9CtqBCy5r8CAfF4H9jb5P88hcDhNf5w9d/6Pi
wBj+9dOAYU1sTMK5pNEhbs7cqwTQeKq3VJOQpkjXhWHxAewIjtu8zck56W2Zzz4L
aZCWliiSUWfUWO9aPCwC+wqBIzvTbXMc/VsHG5c6F8gR5/D9/AURJPIZw9Ulyr3c
IhAodL3SbqZUr7WT3ZzHeQ5WsDqq8Y8lOSIgemRO5RAkv3r7FQgUyoWu6P3fQTSd
Eb6ZLQ6xRnxNvKDGea1Bv5DI1Nuni9Cv7XoVDatUukYXMQqYrQWNXS20/OVzJxF2
tNsCbG0pZcEp0cf2tWTQHyYN/iMWEA63Aox0BGFkVQKBgQDtKq0EncX9zyiGreOD
WV6PSQamN4rfQlzkN77U+WNut3JDwUv5CdavpTt2Qr0g/wLsmovKpMUnwhERyO4X
JBL41/eAOtHeQzwYxE7aoVGFPS4/3QIGV8Bqd0rHgYJHztfa26WJWJcnIpwWBZgY
Oao1xlveI+3zPO++ajw8OA2HywKBgQDXxFzzb1oNM6E9+w+r/kXW1fUM2gln5RgU
Jdc+H/ckiJSGes3e7ci5zek53vgCMiQdmQ6kDON/bnArRg+ol7fCC9sUeuXg1TA4
cNaeBjf7fQhzb1CQlJp+h38Vy7NgkvPAkgI4PWJihgT7QEsiMn+k3mBHAXkfcbuh
WwJ2mbUVgwKBgBcaQSBh/hdrRpdX+QGigwOSKYOnhW+aF1Jj28MDSBxQ4mCXQ79O
pgsWHWS3u5SrQq2poFRtGId28BK7b/XxHaf/4awsDqWIByKifMvvSvGftBGkhb34
blXwqOgmRXqZO42mN8nZR2AYjvvWL6qsc1gpqmlJNrSrCu+RiayUCT1hAoGBAKaW
NgnBdC5zKU+4Uh5BwFwhbwRQJyju6QtNOAUAGwk65il6EQ7IWcyS3TnQG31ehyHO
9U3VoaPWeYX/nsFU+gw4qRoD1Q4kqwk4nYr+VCS4IVk2nWYzRaDhLk5+qmyqqMWK
NWqEgjx9KsVtm1S41nJNOto3mfOcFPh8UseM3xHPAoGBAKzHshWR+jmRrVp0XKrz
Yl/Vz1pCIg1bbQk9iip08FqJTpMMd3sr/XS/ULX5jaOeEQcT4JQRr8H84rhunoBu
AMCPCbqLNjpyxxY6zWftYOx4chLECh6/ro/EOOiJnxrQB5AHcHOoHi0mjl+Lux/q
1jbqcR5IfkapWhD2xuyLgVOz
-----END PRIVATE KEY-----
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
'use strict'

const path = require('path')
const Fastify = require('fastify')
const fastifySession = require('fastify-session')
const fastifyCookie = require('fastify-cookie')
const fs = require('fs')

const APP_PORT = 3000
const getCertificates = () => {
const cert = fs.readFileSync(path.join(__dirname, './certificates/selfsigned.crt'), 'utf-8')
const key = fs.readFileSync(path.join(__dirname, './certificates/selfsigned.key'), 'utf-8')
return {
cert,
key
}
}
const { key, cert } = getCertificates()

const fastify = Fastify({
logger: true,
https: {
key,
cert
}
})

fastify.register(fastifyCookie)

const sessionOptions = {
secret: 'a secret with minimum length of 32 characters',
cookieName: 'example-using-https-connection',
cookie: {
secure: true,
maxAge: 1000 * 60 * 3
}
}
fastify.register(fastifySession, sessionOptions)

fastify.get('/', async (request, reply) => {
if (request.session) {
request.session.count = request.session.count ? request.session.count + 1 : 1
}
return { hello: `route requested ${request.session.count} times in this session` }
})

fastify.listen(APP_PORT, function (err) {
if (err) {
fastify.log.error(err)
process.exit(1)
}
})