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

feature: updating the validations API #8

Merged
merged 8 commits into from
May 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
100 changes: 100 additions & 0 deletions docs/features/validations.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
---
title: Form Validation
index: 3
---

Leapkit provides the `form/validate` package that offers a flexible and reusable way to validate form data by defining a set of validation rules that can be applied to form fields.

### How to Use

Validations are a set of rules stablished for different fields passed in the request. You can define these Validations to be used in your http handlers by and call the `form.Validate` function passing the `req` (*http.Request) and handling the `validate.Errors` returned. Example:

```go

passwordExp := regexp.MustCompile(`^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$)`)

rules := validate.Fields(
validate.Field("email", validate.Required("email is required")),
validate.Field(
"password",
validate.Required("password is required"),
validate.MatchRegex(
passwordExp,
"Password must contain at least 8 characters, one uppercase letter, one lowercase letter, one number and one special character",
),
)

verrs := form.Validate(req, rules)
if len(verrs) > 0 {
// handle validation errors...
}
```

### Built-in Rules

You can build your set of rules for each validation by using the package's built-in functions.

```go
// General Rules:
func Required(message ...string) Rule

// String Rules:
func Matches(field string, message ...string) Rule
func MatchRegex(re *regexp.Regexp, message ...string) Rule
func MinLength(min int, message ...string) Rule
func MaxLength(max int, message ...string) Rule
func WithinOptions(options []string, message ...string) Rule

// Number Rules:
func EqualTo(value float64, message ...string) Rule
func LessThan(value float64, message ...string) Rule
func LessThanOrEqualTo(value float64, message ...string) Rule
func GreaterThan(value float64, message ...string) Rule
func GreaterThanOrEqualTo(value float64, message ...string) Rule

// UUID Rule:
func ValidUUID(message ...string) Rule

// Time Rules:
func TimeEqualTo(u time.Time, message ...string) Rule
func TimeBefore(u time.Time, message ...string) Rule
func TimeBeforeOrEqualTo(u time.Time, message ...string) Rule
func TimeAfter(u time.Time, message ...string) Rule
func TimeAfterOrEqualTo(u time.Time, message ...string) Rule
```

### Custom validation Rules

Alternatively, you can create your own validation rules. Example:

```go
func IsUnique(db *sqlx.DB ) func([]string) error {
return func(emails []string) error {
query := "SELECT EXISTS(SELECT 1 FROM users WHERE email = $1)"
stmt, err := db.Prepare(query)
if err != nil {
return err
}

for _, email := range emails {
var exists bool
if err := stmt.QueryRow(email).Scan(&exists); err != nil {
return err
}

if exists {
return fmt.Errorf("email '%s' already exists.", email)
}
}

return nil
}
}

// ...
rules := validation.Fields(
validation.Field("email", validate.Required(), IsUnique(db))
...
)
...
```
5 changes: 2 additions & 3 deletions docs/index.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
---
title: "LeapKit"
title: "About LeapKit"
index: 1
---

LeapKit is a collection of tools to help you build your next application with Go. Its main purpose is to make web development as fast and simple as possible and is targeted at web developers trying to take the leap and launch their next project.
LeapKit is a collection of packages to help you build your next application with Go. Its main purpose is to make web development as fast and simple as possible and is targeted at web developers trying to take the leap and launch their next project.

There are two main components of LeapKit, the LeapKit Core and the LeapKit Template, these two make the use of LeapKit possible.

Expand All @@ -13,5 +13,4 @@ The LeapKit Core contains the Go libraries that facilitate the web development.


## LeapKit Template

The LeapKit Template contains a starting point folder structure using the LeapKit core. It provides some CLI commands to facilitate the web development of your apps, the template can be copied and modified with the `gonew` command.
Empty file added docs/tools/gloves.md
Empty file.
107 changes: 0 additions & 107 deletions docs/validations.md

This file was deleted.

34 changes: 32 additions & 2 deletions form/form.go → form/decode.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package form

import (
"fmt"
"net/http"
"strings"

Expand All @@ -18,8 +19,8 @@ var (
func init() {
// Register custom and common type decoder
// functions.
decoder.RegisterCustomTypeFunc(DecodeUUID, uuid.UUID{})
decoder.RegisterCustomTypeFunc(DecodeUUIDSlice, []uuid.UUID{})
decoder.RegisterCustomTypeFunc(decodeUUID, uuid.UUID{})
decoder.RegisterCustomTypeFunc(decodeUUIDSlice, []uuid.UUID{})
}

// RegisterCustomTypeFunc registers a custom type decoder func for a type.
Expand Down Expand Up @@ -54,3 +55,32 @@ func Decode(r *http.Request, dst interface{}) error {
err := decoder.Decode(dst, r.Form)
return err
}

// decodeUUID a single uuid from a string
// and returns an error if there is a problem
func decodeUUID(vals []string) (interface{}, error) {
uu, err := uuid.FromString(vals[0])
if err != nil {
err = fmt.Errorf("error parsing uuid: %w", err)
}

return uu, err
}

// decodeUUIDSlice decodes a slice of uuids from a string
// and returns an error if there is a problem
func decodeUUIDSlice(vals []string) (interface{}, error) {
var uus []uuid.UUID

for _, val := range vals {
uuid, err := uuid.FromString(val)
if err != nil {
err = fmt.Errorf("error parsing uuid: %w", err)
return nil, err
}

uus = append(uus, uuid)
}

return uus, nil
}
Loading
Loading