diff --git a/HISTORY.md b/HISTORY.md
index af2c2de2..ef6a55d7 100644
--- a/HISTORY.md
+++ b/HISTORY.md
@@ -23,10 +23,11 @@ Developers are not forced to upgrade if they don't really need it. Upgrade whene
Changes apply to `main` branch.
+- Add `x/errors.ReadPayload`, `ReadQuery`, `ReadPaginationOptions`, `Handle`, `HandleCreate`, `HandleCreateResponse`, `HandleUpdate` and `HandleDelete` package-level functions as helpers for common actions.
- Add `x/jsonx.GetSimpleDateRange(date, jsonx.WeekRange, time.Monday, time.Sunday)` which returns all dates between the given range and start/end weekday values for WeekRange.
- Add `x/timex.GetMonthDays` and `x/timex.GetMonthEnd` functions.
- Add `iris.CookieDomain` and `iris.CookieOverride` cookie options to handle [#2309](https://github.com/kataras/iris/issues/2309).
-- New `x/errors.ErrorCodeName.MapErrorFunc`, `x/errors.ErrorCodeName.MapErrors`, `x/errors.ErrorCodeName.Wrap` methods and `x/errors.HandleError` package-level function.
+- New `x/errors.ErrorCodeName.MapErrorFunc`, `MapErrors`, `Wrap` methods and `x/errors.HandleError` package-level function.
# Sun, 05 Nov 2023 | v12.2.8
diff --git a/LICENSE b/LICENSE
index de4e4a3e..69a1ca75 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,6 +1,6 @@
BSD 3-Clause License
-Copyright (c) 2016-2023, Gerasimos (Makis) Maropoulos
+Copyright (c) 2016-2024, Gerasimos (Makis) Maropoulos
All rights reserved.
Redistribution and use in source and binary forms, with or without
diff --git a/README.md b/README.md
index a85aa919..277030bf 100644
--- a/README.md
+++ b/README.md
@@ -4,6 +4,34 @@
Try the official [Iris Command Line Interface](https://github.com/kataras/iris-cli) today! -->
+# 🎅 Happy new year to everyone!
+
+```
+A new year is here, full of hope and cheer
+A time to celebrate, and appreciate
+the past year's achievements, and the future's improvements.
+
+We are proud to present, our open-source project
+Iris web framework, a fast and elegant way to make
+Web applications, with ease and satisfaction.
+
+Iris is built with Go, a language you should know
+It offers high performance, and great concurrency.
+It has a rich ecosystem, and a friendly community.
+
+Iris is designed to be, simple and flexible
+It has a modular structure, and a powerful router.
+It supports middleware, and many features.
+
+Iris is more than a tool, it is a vision
+To empower developers, and inspire creations
+to make the web better, and brighter.
+
+We thank you for your support, and your feedback.
+We hope you enjoy using Iris, and find it useful.
+We wish you a happy new year, and a successful career.
+```
+
# Iris Web Framework
[![build status](https://img.shields.io/github/actions/workflow/status/kataras/iris/ci.yml?branch=main&style=for-the-badge)](https://github.com/kataras/iris/actions/workflows/ci.yml) [![view examples](https://img.shields.io/badge/examples%20-285-a83adf.svg?style=for-the-badge&logo=go)](https://github.com/kataras/iris/tree/main/_examples) [![chat](https://img.shields.io/gitter/room/iris_go/community.svg?color=cc2b5e&logo=gitter&style=for-the-badge)](https://gitter.im/iris_go/community) [![donate](https://img.shields.io/badge/support-Iris-blue.svg?style=for-the-badge&logo=paypal)](https://iris-go.com/donate)
diff --git a/x/errors/errors.go b/x/errors/errors.go
index 57f5d9f2..5b6aad95 100644
--- a/x/errors/errors.go
+++ b/x/errors/errors.go
@@ -59,7 +59,7 @@ var errorCodeMap = make(map[ErrorCodeName]ErrorCode)
// Example:
//
// var (
-// NotFound = errors.E("NOT_FOUND", http.StatusNotFound)
+// NotFound = errors.E("NOT_FOUND", http.StatusNotFound)
// )
// ...
// NotFound.Details(ctx, "resource not found", "user with id: %q was not found", userID)
@@ -118,6 +118,7 @@ var (
)
// errorFuncCodeMap is a read-only map of error code names and their error functions.
+// See HandleError package-level function.
var errorFuncCodeMap = make(map[ErrorCodeName][]func(error) error)
// HandleError handles an error by sending it to the client
diff --git a/x/errors/handlers.go b/x/errors/handlers.go
new file mode 100644
index 00000000..98ff3f6c
--- /dev/null
+++ b/x/errors/handlers.go
@@ -0,0 +1,145 @@
+package errors
+
+import (
+ "net/http"
+
+ "github.com/kataras/iris/v12/context"
+ "github.com/kataras/iris/v12/x/pagination"
+)
+
+// ReadPayload reads a JSON payload from the context and returns it as a generic type T.
+// It also returns a boolean value indicating whether the read was successful or not.
+// If the read fails, it sends an appropriate error response to the client.
+func ReadPayload[T any](ctx *context.Context) (T, bool) {
+ var payload T
+ err := ctx.ReadJSON(&payload)
+ if err != nil {
+ if vErrs, ok := AsValidationErrors(err); ok {
+ InvalidArgument.Data(ctx, "validation failure", vErrs)
+ } else {
+ InvalidArgument.Details(ctx, "unable to parse body", err.Error())
+ }
+ return payload, false
+ }
+
+ return payload, true
+}
+
+// ReadQuery reads URL query values from the context and returns it as a generic type T.
+// It also returns a boolean value indicating whether the read was successful or not.
+// If the read fails, it sends an appropriate error response to the client.
+func ReadQuery[T any](ctx *context.Context) (T, bool) {
+ var payload T
+ err := ctx.ReadQuery(&payload)
+ if err != nil {
+ if vErrs, ok := AsValidationErrors(err); ok {
+ InvalidArgument.Data(ctx, "validation failure", vErrs)
+ } else {
+ InvalidArgument.Details(ctx, "unable to parse query", err.Error())
+ }
+ return payload, false
+ }
+
+ return payload, true
+}
+
+// ReadPaginationOptions reads the ListOptions from the URL Query and
+// any filter options of generic T from the request body.
+func ReadPaginationOptions[T /* T is FilterOptions */ any](ctx *context.Context) (pagination.ListOptions, T, bool) {
+ list, ok := ReadQuery[pagination.ListOptions](ctx)
+ if !ok {
+ var t T
+ return list, t, false
+ }
+
+ filter, ok := ReadPayload[T](ctx)
+ if !ok {
+ var t T
+ return list, t, false
+ }
+
+ return list, filter, true
+}
+
+// Handle handles a generic response and error from a service call and sends a JSON response to the context.
+// It returns a boolean value indicating whether the handle was successful or not.
+// If the error is not nil, it calls HandleError to send an appropriate error response to the client.
+func Handle(ctx *context.Context, resp interface{}, err error) bool {
+ if HandleError(ctx, err) {
+ return false
+ }
+
+ return ctx.JSON(resp) == nil
+}
+
+// IDPayload is a simple struct which describes a json id value.
+type IDPayload struct {
+ ID string `json:"id"`
+}
+
+// HandleCreate handles a create operation and sends a JSON response with the created id to the client.
+// It returns a boolean value indicating whether the handle was successful or not.
+// If the error is not nil, it calls HandleError to send an appropriate error response to the client.
+// If the id is not empty, it sets the status code to 201 (Created) and sends the id as a JSON payload.
+func HandleCreate(ctx *context.Context, id string, err error) bool {
+ if HandleError(ctx, err) {
+ return false
+ }
+
+ ctx.StatusCode(http.StatusCreated)
+
+ if id != "" {
+ ctx.JSON(IDPayload{ID: id})
+ }
+
+ return true
+}
+
+// HandleCreateResponse handles a create operation and sends a JSON response with the created resource to the client.
+// It returns a boolean value indicating whether the handle was successful or not.
+// If the error is not nil, it calls HandleError to send an appropriate error response to the client.
+// If the response is not nil, it sets the status code to 201 (Created) and sends the response as a JSON payload.
+func HandleCreateResponse(ctx *context.Context, resp interface{}, err error) bool {
+ if HandleError(ctx, err) {
+ return false
+ }
+
+ ctx.StatusCode(http.StatusCreated)
+ if resp != nil {
+ return ctx.JSON(resp) == nil
+ }
+
+ return true
+}
+
+// HandleUpdate handles an update operation and sends a status code to the client.
+// It returns a boolean value indicating whether the handle was successful or not.
+// If the error is not nil, it calls HandleError to send an appropriate error response to the client.
+// If the updated value is true, it sets the status code to 204 (No Content).
+// If the updated value is false, it sets the status code to 304 (Not Modified).
+func HandleUpdate(ctx *context.Context, updated bool, err error) bool {
+ if HandleError(ctx, err) {
+ return false
+ }
+
+ if updated {
+ ctx.StatusCode(http.StatusNoContent)
+ } else {
+ ctx.StatusCode(http.StatusNotModified)
+ }
+
+ return true
+}
+
+// HandleDelete handles a delete operation and sends a status code to the client.
+// If the error is not nil, it calls HandleError to send an appropriate error response to the client.
+// It sets the status code to 204 (No Content).
+func HandleDelete(ctx *context.Context, err error) bool {
+ if HandleError(ctx, err) {
+ return false
+ }
+
+ ctx.StatusCode(http.StatusNoContent)
+
+ return true
+}