Upgrades
What to do when a new Loco version is out?
- Create a clean branch in your code repo.
- Update the Loco version in your main
Cargo.toml
- Consult with the CHANGELOG to find breaking changes and refactorings you should do (if any).
- Run
cargo loco doctor
inside your project to verify that your app and environment is compatible with the new version
As always, if anything turns wrong, open an issue and ask for help.
Major Loco dependencies
Loco is built on top of great libraries. It's wise to be mindful of their versions in new releases of Loco, and their individual changelogs.
These are the major ones:
Upgrade from 0.15.x to 0.16.x
Use AppContext
instead of Config
in init_logger
in the Hooks
trait
PR: #1418
If you are supplying an implementation of init_logger
in your impl
of the Hooks
trait in order to set up your own logging, you will need to make the following change:
- fn init_logger(config: &config::Config, env: &Environment) -> Result<bool> {
+ fn init_logger(ctx: &AppContext) -> Result<bool> {
Any code in your init_logger
implementation that makes use of the config
can access it through ctx.config
. In addition, you will also be able to access anything else in the AppContext
, such as the new shared_store
. The env
parameter is also removed, as that is accessible from the AppContext
as ctx.environment
.
Swap to validators builtin email validation
PR: #1359
Swap from using the loco custom email validator, to the builtin email validator from validator
.
- #[validate(custom (function = "validation::is_valid_email"))]
+ #[validate(email(message = "invalid email"))]
pub email: String,
Job system
Two major changes have been made to the background job system:
- The Redis provider is no longer Sidekiq-compatible and uses a custom implementation
- All providers (Redis, PostgreSQL, SQLite) now support tag-based job filtering
What Changed
Removing Sidekiq Compatibility
The Redis background job system has been completely refactored, replacing the Sidekiq-compatible implementation with a new custom implementation. This provides greater flexibility and improved performance, but means:
- Jobs pushed from older Loco versions (pre-0.16) will not be recognized or processed
- The Redis data structures have changed entirely
- There is no automatic migration path for existing queued jobs
Adding Job Filtering
A new tag-based job filtering system has been added to all background worker providers:
- Workers can now specify which tags they're interested in processing
- Jobs can be tagged when enqueued
- Workers with no tags only process untagged jobs, while tagged workers process jobs with matching tags
- The same API is used across all providers
How to Upgrade
To upgrade to the new job system:
-
Process existing jobs:
- Make sure all jobs in your queue are processed/completed before upgrading
-
Clean up old data:
- For Redis: Flush the Redis database used for jobs (
FLUSHDB
command) - For PostgreSQL: Drop the job queue tables
- For SQLite: Delete the job queue tables
- For Redis: Flush the Redis database used for jobs (
-
Update Loco:
- Update to Loco 0.16+
- Loco will automatically create new job tables with the correct schema on first run
Generic Cache
PR: #1385
The cache API has been refactored to support storing and retrieving any serializable type, not just strings. This is a breaking change that requires updates to your code:
Breaking Changes:
- Type Parameters Required: All cache methods now require explicit type parameters
- Method Signatures: Some method signatures have changed to support generics
- Object Serialization: Any type you store must implement
Serialize
andDeserialize
from serde
Migration Guide:
Before:
// Get a string value from cache
let value = cache.get.await?;
// Insert or get with callback
let value = app_ctx.cache.get_or_insert.await.unwrap;
// Insert or get with expiry
let value = app_ctx.cache.get_or_insert_with_expiry.await.unwrap;
After:
// Get a string value from cache - specify the type
let value = cache..await?;
// Direct insert with any serializable type
cache.insert.await?;
// Insert or get with callback - specify return type
let value = app_ctx.cache..await.unwrap;
// Store complex types
let user = app_ctx.cache..await.unwrap;
Implementing for Custom Types:
For your custom types to work with the cache, ensure they implement Serialize
and Deserialize
:
use ;
Authentication Error Handling
Authentication error handling has been improved to better distinguish between actual authorization failures and system errors:
- System errors now return 500: Database errors during authentication now return Internal Server Error (500) instead of Unauthorized (401)
- Improved error logging: Authentication errors are now logged with detailed messages using
tracing::error
- Message changes: Generic error messages have been updated from "other error: '{e}'" to "could not authorize"
Migration Guide:
If you have code that relies on database errors during authentication returning 401 status codes, you'll need to update your error handling. Any code expecting a 401 for database connectivity issues should now handle 500 responses as well.
Client applications should be prepared to handle both 401 and 500 status codes during authentication failures, with 401 indicating authorization problems and 500 indicating system errors.
Upgrade from 0.14.x to 0.15.x
Upgrade validator crate
PR: #1199
Update the validator
crate version in your Cargo.toml
:
From
validator = { version = "0.19" }
To
validator = { version = "0.20" }
User claims
PR: #1159
-
Flattened (De)Serialization of Custom User Claims: The
claims
field inUserClaims
has changed fromOption<Value>
toMap<String, Value>
. -
Mandatory Map Value in
generate_token
function: When callinggenerate_token
, theMap<String, Value>
argument is now required. If you are not using custom claims, pass an empty map (serde_json::Map::new()
). -
Updated generate_token Signature: The
generate_token
function now takesexpiration
as a value instead of a reference.
Pagination Response
PR: #1197
The pagination response now includes the total_items
field, providing the total number of items available.
Explicit id in migrations
PR: #1268
Migrations using create_table
now require ("id", ColType::PkAuto)
, new migrations will have this field automatically added.
async fn up(&self, m: &SchemaManager) -> Result<(), DbErr> {
create_table(m, "movies",
&[
+ ("id", ColType::PkAuto),
("title", ColType::StringNull),
],
&[
("user", ""),
]
).await
}
Upgrade from 0.13.x to 0.14.x
Upgrading from Axum 0.7 to 0.8
PR: #1130 The upgrade to Axum 0.8 introduces a breaking change. For more details, refer to the announcement.
Steps to Upgrade
- In your
Cargo.toml
, update the Axum version from0.7.5
to0.8.1
. - Replace use
axum::async_trait
; with useasync_trait::async_trait;
. For more information, see here. - The URL parameter syntax has changed. Refer to this section for the updated syntax. The new path parameter format is:
The path parameter syntax has changed from
/:single
and/*many
to/{single}
and/{*many}
.
Extending the boot
Function Hook
PR: #1143
The boot
hook function now accepts an additional Config parameter. The function signature has changed from:
From
async
To:
async
Make sure to import the Config
type as needed.
Upgrade validator crate
PR: #993
Update the validator
crate version in your Cargo.toml
:
From
validator = { version = "0.18" }
To
validator = { version = "0.19" }
Extend truncate and seed hooks
PR: #1158
The truncate
and seed
functions now receive AppContext
instead of DatabaseConnection
as their argument.
From
async
async
To
async
async
Impact on Testing:
Testing code involving the seed function must also be updated accordingly.
from:
async
to
async