kv_sessions
Overview
kv_sessions is a key-value session management library for Wisp, inspired by the Rust crate tower sessions. This library allows you to manage user sessions with ease, storing session data in a simple key-value store.
Example Usage
An minimal example usage is available in ./example/app.gleam
.
import gleam/erlang/process
import gleam/option
import gleam/result
import gleam/string_builder
import mist
import wisp
import wisp/wisp_mist
import kv_sessions
import kv_sessions/actor_adapter
import kv_sessions/session
import kv_sessions/session_config
pub fn main() {
// Setup session_adapter
use store <- result.map(actor_adapter.new())
use cache_store <- result.map(actor_adapter.new())
// Create session config
let session_config =
session_config.Config(
default_expiry: session.ExpireIn(60 * 60),
cookie_name: "SESSION_COOKIE",
store:,
cache: option.Some(cache_store),
)
let secret_key_base = wisp.random_string(64)
// Start the Mist web server.
let assert Ok(_) =
wisp_mist.handler(handle_request(_, session_config), secret_key_base)
|> mist.new
|> mist.port(8000)
|> mist.start_http
process.sleep_forever()
}
pub fn handle_request(req: wisp.Request, session_config) -> wisp.Response {
// Run the middleware and construct current_session
use req <- kv_sessions.middleware(req, session_config)
let current_session = kv_sessions.CurrentSession(req, session_config)
case wisp.path_segments(req) {
[] -> get_value_page(req, current_session)
["set"] -> set_value_page(req, current_session)
_ -> wisp.not_found()
}
}
fn get_value_page(
_req: wisp.Request,
session: kv_sessions.CurrentSession,
) -> wisp.Response {
// Read value to the session
let assert Ok(key) =
session
|> kv_sessions.key("test_key")
|> kv_sessions.get()
case key {
option.Some(k) -> {
wisp.html_response(string_builder.from_string(k), 200)
}
option.None -> {
wisp.html_response(
string_builder.from_string("No value set. Go to /set to set a value"),
200,
)
}
}
}
fn set_value_page(
_req: wisp.Request,
session: kv_sessions.CurrentSession,
) -> wisp.Response {
// Set value to the session
let _ =
session
|> kv_sessions.key("test_key")
|> kv_sessions.set("something")
wisp.redirect("/")
}
Running the Example
To start the server, cd into /example and run gleam run
.
Visit (http://localhost:8000) in your browser. The page should display “No value set. Go to /set to set a value.”
Navigate to (http://localhost:8000/set). You will be redirected back to the main page, which will now display “something”.
Development
gleam run # Run the project
gleam test # Run the tests
just watch-test # Run test and reload on file changes
Caching
A session config can be passed an optional cache parameter that is a SessionStore
wrapped in an option.Option
. If the cache is option.Some
sessions will be
fetched from the cache. If the data is not in the cache the store
will be
tried.
Session data will be automatically added and removed from the cache.
SessionStore
There are different places you may want to store sessions such as postgres/ETS/sqlite. The way you integrate with them is through storage adapters that implement the type SessionStore. You can use one of the prebuild storage adapters from down below, or implement a new one if the one you are looking for does not exist.
For an example implementation, see ./src/kv_sessions/ets_adapter.gleam
.
SessionStore adapters
actor_adapter
The actor_adapter driver is suitable for development and testing purposes, but not recommended for production due to its non-concurrent nature. Internally, it uses an actor, which may become a bottleneck under heavy loads.
Usage Example:
import kv_sessions/actor_adapter
use session_store <- result.map(actor_adapter.new())
// ...
See ./example/src/app.gleam
for full example
postgres_adapter
The postgres_adapter, that allows you to use postgres as the storage implementation
gleam add kv_sessions_postgres_adapter
import kv_sessions/postgres_adapter
let db =
pog.default_config()
|> pog.connect()
// Migrate
use _ <- result.try(postgres_adapter.migrate_up(conn))
// Setup session_store
use session_store <- result.map(postgres_adapter.new(conn))
//...
ets_adapter
The ets_adapter uses Erlang Term Storage and carpenter to store session information. This will NOT be persistant after restarts. But is a good option for caching.
gleam add kv_sessions_ets_adapter
import kv_sessions/ets_adapter
// Setup session_store
use session_store <- result.map(ets_adapter.new(conn))
//...