web-dev-qa-db-fra.com

Création d'une erreur personnalisée dans Golang pour les réponses HTTP

je voulais créer des erreurs personnalisées pour mon service d'authentification que je travaille actuellement. Puisque je dois créer une erreur pour chaque réponse HTTP, et je suis assez nouveau à Golang, je suis confronté à des difficultés. Le code ci-dessous est la réplique du code de code JavaScript que je souhaitais implémenter ici.

export abstract class CustomError extends Error {
abstract statusCode: number;

constructor(message: string) {
    super(message);

    Object.setPrototypeOf(this, CustomError.prototype);
}

abstract serializeErrors(): { message: string; field?: string }[];
}

Pour créer des classes étendues en fonction de l'erreur personnalisée comme celle-ci

import { CustomError } from "./custom-error";

export class NotFoundError extends CustomError {
statusCode = 404;

constructor() {
    super("Route not found");

    Object.setPrototypeOf(this, NotFoundError.prototype);
}

serializeErrors() {
    return [{ message: "Not Found" }];
 }
}

afin que je puisse être lancé ou connecté du fichier principal, c'est-à-dire existant existant = attendre l'utilisateur.findone ({email});

    if (existingUser) {
        throw new BadRequestError("Email is already in use");
    }

donc, en langage simple, je voulais créer un objet/modèle de CustomErrors qui peut aider à créer des erros plus diverses comme BADREQUESTERROR ()

donc, j'ai besoin d'aide pour créer celui-ci. Et ceci est ma première question ici

3
Aditya vatsa

Si vous souhaitez des réponses d'erreur HTTP dans le texte brut, http.Error devrait être votre choix. Mais si votre service d'authentification nécessite une réponse d'erreur dans un format spécifique (JSON/XML), vous devez créer des erreurs HTTP personnalisées pouvant être sérialisées et écrites dans la réponse.

Pour créer des réponses d'erreur HTTP personnalisées pour le format JSON (pour la série de modification du format XML), vous devez d'abord créer des types -

type ErrFields map[string]string  // Error field-value pair type

type ResponseError struct {
    Msg    string `json:"message"` // Error message
    Status int    `json:"status"`  // Http status code
    Data   ErrFields               // For extra error fields e.g. reason, details, etc.
}

type ErrList []ResponseError       // Multiple http errors type

Méthodes pour ResponseError Type -

// AddErrField adds a new field to the response error with given key and value
func (err *ResponseError) AddErrField(key, value string) {
    if err.Data == nil {
        err.Data = make(ErrFields)
    }
    err.Data[key] = value
}

// RemoveErrField removes existing field matching given key from response error
func (err *ResponseError) RemoveErrField(key string) {
    delete(err.Data, key)
}

// MarshalJSON marshals the response error into json 
func (err *ResponseError) MarshalJSON() ([]byte, error) {
    // Determine json field name for error message
    errType := reflect.TypeOf(*err)
    msgField, ok := errType.FieldByName("Msg")
    msgJsonName := "message"
    if ok {
        msgJsonTag := msgField.Tag.Get("json")
        if msgJsonTag != "" {
            msgJsonName = msgJsonTag
        }
    }
    // Determine json field name for error status code
    statusField, ok := errType.FieldByName("Status")
    statusJsonName := "status"
    if ok {
        statusJsonTag := statusField.Tag.Get("json")
        if statusJsonTag != "" {
            statusJsonName = statusJsonTag
        }
    }
    fieldMap := make(map[string]string)
    fieldMap[msgJsonName] = err.Msg
    fieldMap[statusJsonName] = fmt.Sprintf("%d", err.Status)
    for key, value := range err.Data {
        fieldMap[key] = value
    }
    return json.Marshal(fieldMap)
}

// SerializeJSON converts response error into serialized json string
func (resErr *ResponseError) SerializeJSON() (string, error) {
    value, err := json.Marshal(resErr)
    if err != nil {
        return "", err
    }
    return string(value), nil
}

Méthodes pour ErrList Type -

// SerializeJSON converts error list into serialized json string
func (errList ErrList) SerializeJSON() (string, error) {
    value, err := json.Marshal(errList)
    if err != nil {
        return "", err
    }
    return string(value), nil
}

Maintenant, vous pouvez créer des réponses d'erreur HTTP personnalisées en créant des valeurs différentes de ResponseError Type -

// Error returns a general response error
func Error(msg string, status int) ResponseError {
    return ResponseError{msg, status, nil}
}

// Errors returns a error list containing given response errors
func Errors(errors ...ResponseError) ErrList {
    return errors
}

// Specific HTTP error responses

func ErrorNotFound() ResponseError {
    return Error("not found", http.StatusNotFound)
}

func ErrorBadRequest() ResponseError {
    return Error("bad request", http.StatusBadRequest)
}

func ErrorInternalServerError() ResponseError {
    return Error("internal server error", http.StatusInternalServerError)
}

func ErrorForbidden() ResponseError {
    return Error("forbidden", http.StatusForbidden)
}

Vous pouvez ajouter/supprimer des champs personnalisés sur les valeurs ResponseError -

notFoundErr := ErrorNotFound()
notFoundErr.AddErrField("reason", "given 'id' does not exist")
notFoundErr.RemoveErrField("reason")

Étant donné qu'en aller, il n'y a pas de concept de lancer, vous ne pouvez que renvoyer une erreur de réponse d'une fonction -

func Foo() (resErr ResponseError, ok bool) {
    ...
    if existingUser {
       resErr = ErrorBadRequest()
       resErr.AddErrField("reason", "Email is already in use")
       return resErr, true
    }
    ...
    return ResponseError{}, false
}

Pour sérialiser l'erreur de réponse dans JSON -

resErr, ok := Foo()
if !ok {
    json, err := resErr.SerializeJSON()
    if err != nil {
        // Handle serialization error
    }
}

Voir l'exemple Go Playground ici .

0
cod3rboy