Sessions¶
Sessions allow you to persist a user's data between multiple requests. Sessions work by creating and returning a unique cookie alongside the HTTP response when a new session is initialized. Browsers will automatically detect this cookie and include it in future requests. This allows Vapor to automatically restore a specific user's session in your request handler.
Sessions are great for front-end web applications built in Vapor that serve HTML directly to web browsers. For APIs, we recommend using stateless, token-based authentication to persist user data between requests.
Configuration¶
To use sessions in a route, the request must pass through SessionsMiddleware
. The easiest way to achieve this is by adding this middleware globally. It is recommended that you do add this after you declare the cookie factory. This is because Sessions is a struct, therefore it is a value type, and not a reference type. Since it is a value type, you must set the value before using SessionsMiddleware
.
app.middleware.use(app.sessions.middleware)
If only a subset of your routes utilize sessions, you can instead add SessionsMiddleware
to a route group.
let sessions = app.grouped(app.sessions.middleware)
The HTTP cookie generated by sessions can be configured using app.sessions.configuration
. You can change the cookie name and declare a custom function for generating cookie values.
// Change the cookie name to "foo".
app.sessions.configuration.cookieName = "foo"
// Configures cookie value creation.
app.sessions.configuration.cookieFactory = { sessionID in
.init(string: sessionID.string, isSecure: true)
}
app.middleware.use(app.sessions.middleware)
By default, Vapor will use vapor_session
as the cookie name.
Drivers¶
Session drivers are responsible for storing and retrieving session data by identifier. You can create custom drivers by conforming to the SessionDriver
protocol.
Warning
The session driver should be configured before adding app.sessions.middleware
to your application.
In-Memory¶
Vapor utilizes in-memory sessions by default. In-memory sessions require zero configuration and do not persist between application launches which makes them great for testing. To enable in-memory sessions manually, use .memory
:
app.sessions.use(.memory)
For production use cases, take a look at the other session drivers which utilize databases to persist and share sessions across multiple instances of your app.
Fluent¶
Fluent includes support for storing session data in your application's database. This section assumes you have configured Fluent and can connect to a database. The first step is to enable the Fluent sessions driver.
import Fluent
app.sessions.use(.fluent)
This will configure sessions to use the application's default database. To specify a specific database, pass the database's identifier.
app.sessions.use(.fluent(.sqlite))
Finally, add SessionRecord
's migration to your database's migrations. This will prepare your database for storing session data in the _fluent_sessions
schema.
app.migrations.add(SessionRecord.migration)
Make sure to run your application's migrations after adding the new migration. Sessions will now be stored in your application's database allowing them to persist between restarts and be shared between multiple instances of your app.
Redis¶
Redis provides support for storing session data in your configured Redis instance. This section assumes you have configured Redis and can send commands to the Redis instance.
To use Redis for Sessions, select it when configuring your application:
import Redis
app.sessions.use(.redis)
This will configure sessions to use the Redis sessions driver with the default behavior.
Seealso
Refer to Redis → Sessions for more detailed information about Redis and Sessions.
Session Data¶
Now that sessions are configured, you are ready to persist data between requests. New sessions are initialized automatically when data is added to req.session
. The example route handler below accepts a dynamic route parameter and adds the value to req.session.data
.
app.get("set", ":value") { req -> HTTPStatus in
req.session.data["name"] = req.parameters.get("value")
return .ok
}
Use the following request to initialize a session with the name Vapor.
GET /set/vapor HTTP/1.1
content-length: 0
You should receive a response similar to the following:
HTTP/1.1 200 OK
content-length: 0
set-cookie: vapor-session=123; Expires=Fri, 10 Apr 2020 21:08:09 GMT; Path=/
Notice the set-cookie
header has been added automatically to the response after adding data to req.session
. Including this cookie in subsequent requests will allow access to the session data.
Add the following route handler for accessing the name value from the session.
app.get("get") { req -> String in
req.session.data["name"] ?? "n/a"
}
Use the following request to access this route while making sure to pass the cookie value from the previous response.
GET /get HTTP/1.1
cookie: vapor-session=123
You should see the name Vapor returned in the response. You can add or remove data from the session as you see fit. Session data will be synchronized with the session driver automatically before returning the HTTP response.
To end a session, use req.session.destroy
. This will delete the data from the session driver and invalidate the session cookie.
app.get("del") { req -> HTTPStatus in
req.session.destroy()
return .ok
}