Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

errors store added #7

Closed
wants to merge 1 commit into from
Closed
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
8 changes: 8 additions & 0 deletions inertia.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package gonertia

import (
"context"
"fmt"
"html/template"
"io"
Expand All @@ -21,6 +22,8 @@ type Inertia struct {
ssrURL string
ssrHTTPClient *http.Client

errorsStore errorsStore

containerID string
version string
jsonMarshaller JSONMarshaller
Expand Down Expand Up @@ -87,6 +90,11 @@ type logger interface {
Println(v ...any)
}

type errorsStore interface {
Push(ctx context.Context, errors ValidationErrors) error
Pop(ctx context.Context) (ValidationErrors, error)
}

// ShareProp adds passed prop to shared props.
func (i *Inertia) ShareProp(key string, val any) {
i.sharedProps[key] = val
Expand Down
8 changes: 8 additions & 0 deletions option.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,3 +80,11 @@ func WithSSR(url ...string) Option {
return nil
}
}

// WithErrorsStore returns Option that will set Inertia's errors store.
func WithErrorsStore(errorsStore errorsStore) Option {
return func(i *Inertia) error {
i.errorsStore = errorsStore
return nil
}
}
46 changes: 42 additions & 4 deletions props.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package gonertia

import (
"context"
"fmt"
"net/http"
)
Expand Down Expand Up @@ -45,12 +46,12 @@ type ValidationErrors map[string]any
func (i *Inertia) prepareProps(r *http.Request, component string, props Props) (Props, error) {
result := make(Props)

// Add validation errors from context.
ctxValidationErrors, err := ValidationErrorsFromContext(r.Context())
// Add validation errors to the result.
validationErrors, err := i.resolveValidationErrors(r)
if err != nil {
return nil, fmt.Errorf("getting validation errors from context: %w", err)
return nil, fmt.Errorf("resolve validation errors: %w", err)
}
result["errors"] = AlwaysProp{ctxValidationErrors}
result["errors"] = AlwaysProp{validationErrors}

// Add shared props to the result.
for key, val := range i.sharedProps {
Expand Down Expand Up @@ -112,6 +113,43 @@ func (i *Inertia) prepareProps(r *http.Request, component string, props Props) (
return result, nil
}

func (i *Inertia) resolveValidationErrors(r *http.Request) (ValidationErrors, error) {
// Add validation errors from storage.
storageValidationErrors, err := i.restoreValidationErrors(r.Context())
if err != nil {
return nil, fmt.Errorf("getting validation errors from context: %w", err)
}

// ... and from context.
ctxValidationErrors, err := ValidationErrorsFromContext(r.Context())
if err != nil {
return nil, fmt.Errorf("getting validation errors from context: %w", err)
}

validationErrors := make(ValidationErrors)
for key, val := range storageValidationErrors {
validationErrors[key] = val
}
for key, val := range ctxValidationErrors {
validationErrors[key] = val
}

return ctxValidationErrors, nil
}

func (i *Inertia) restoreValidationErrors(ctx context.Context) (ValidationErrors, error) {
if i.errorsStore == nil {
return nil, nil
}

storageValidationErrors, err := i.errorsStore.Pop(ctx)
if err != nil {
return nil, fmt.Errorf("errors store pop: %w", err)
}

return storageValidationErrors, nil
}

func (i *Inertia) getOnlyAndExcept(r *http.Request, component string) (only, except map[string]struct{}) {
// Partial reloads only work for visits made to the same page component.
//
Expand Down
17 changes: 17 additions & 0 deletions response.go
Original file line number Diff line number Diff line change
Expand Up @@ -218,13 +218,30 @@ func (i *Inertia) htmlContainer(pageJSON []byte) (inertia, _ template.HTML, _ er
// Otherwise, it will do an HTTP redirect with specified status (default is 302 for GET, 303 for POST/PUT/PATCH).
func (i *Inertia) Location(w http.ResponseWriter, r *http.Request, url string, status ...int) {
if IsInertiaRequest(r) {
i.captureValidationErrors(r)
setInertiaLocationInResponse(w, url)
return
}

redirectResponse(w, r, url, status...)
}

func (i *Inertia) captureValidationErrors(r *http.Request) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right now it returns early if there is no errorStore. Maybe it's smart to still check and add the errors from context before checking if there is an errorStore

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, I rethought some ideas and it seemed easier to start over.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@romsar I just saw, I think that is the correct way, not forcing people to use it but add the possibility.

if i.errorsStore == nil {
return
}

validationErrors, err := ValidationErrorsFromContext(r.Context())
if err != nil {
i.logger.Printf("invalid validation errors from context: %s", err)
}

err = i.errorsStore.Push(r.Context(), validationErrors)
if err != nil {
i.logger.Printf("cannot push validation errors to storage: %s", err)
}
}

// Back creates redirect response to the previous url.
func (i *Inertia) Back(w http.ResponseWriter, r *http.Request, status ...int) {
i.Location(w, r, i.backURL(r), status...)
Expand Down
Loading