Progettazione dell'architettura dell'API Web

0

Sto imparando e tuffo nelle API Web. Ho usato i servizi Web prima, ma non specificamente con l'API Web. Di seguito è riportato come lo sto progettando fino ad ora e sono stato curioso del feedback.

Ho un oggetto ReturnMessages. Questo è fondamentalmente un oggetto standard che viene restituito da una qualsiasi delle chiamate API, eseguito correttamente o si verifica un errore. All'interno di ogni metodo API ho una presa di prova. se tutto va bene, specificherò i valori di cui ho bisogno all'interno del mio oggetto ReturnMessages e di Ok(_returnMessages) . Ora, se si verifica un errore, riempio l'oggetto ReturnMessages con le informazioni sull'errore e ancora una volta restituisco Ok(_returnMessages) .

L'oggetto ReturnMessages contiene un campo ReturnClass per contenere qualsiasi tipo di altri oggetti che potrebbe essere necessario restituire. Un singolo oggetto o una matrice. Ha anche un codice di ritorno, un messaggio di risposta, un messaggio amichevole per l'utente finale nel caso in cui qualcosa di sbagliato accada e di una lista di string generica di dati che è stata trasmessa e che posso inviare e utilizzare a scopo di test per provare e ricreare il di errore.

Di seguito è riportato un esempio di codice da uno dei metodi che mostra ciò di cui sto parlando. Questo approccio è ok se restituisco sempre Ok con l'oggetto che sto restituendo o mi mancano i potenziali pezzi all'interno dell'API Web che dovrei utilizzare? Ho visto le eccezioni NotFound e tutte quelle altre cose divertenti.

** EDIT: ho apportato alcune modifiche in termini di cosa stavo passando quando le cose non funzionano. Ho estratto ReturnMessage e anche ReturnData e l'ho scritto nel registro eventi dell'applicazione per un nuovo valore di stringa per questa particolare web api. Taht si verifica nella riga di codice _lw che è solo una classe LogWriter che utilizza i valori passati per scrivere nel registro eventi dell'applicazione.

public IHttpActionResult method1(string arg 1= null, string arg2 = null, string arg3 = null)
        {
            try
            {
                clrObject1 varClrObject = (from p in db.clrObject1
                                            where p.column1 == arg1
                                            select p).SingleOrDefault();

                if (varClrObject == null)
                {
                    _returnMessages = new ReturnMessages
                    {
                        ReturnCode = 204,
                        FriendlyErrorMessage = "Nothing found matches the supplied values."
                    };

                   _lw.SetupEventLog("No data was found that matched the information supplied.\n\nParameters:\narg1: " + arg1 + "\narg2: " + arg2 + "\narg2=" + arg2, "Warning");
                }
                else
                {
                    _returnMessages = new ReturnMessages
                    {
                        ReturnCode = 200,
                        ReturnClass = varClrObject,
                        ReturnMessage = "Information Successfully Retrieved"
                    };
                }
            }
            catch (Exception e)
            {
                _returnMessages = new ReturnMessages
                {
                    FriendlyErrorMessage = "An error has occurred while getting your information. Please try again in a few minutes.  A notification was already sent to the company about this issue.",
                    ReturnCode = 400
                };

                _lw.SetupEventLog("Parameters:\narg1: " + arg1 + "\narg2: " + arg2 + "\narg3=" + arg3, "Error", e);
            }

            return Ok(new { Response = _returnMessages });
        }
    
posta iCobot 15.03.2014 - 22:47
fonte

2 risposte

2

La stai complicando in questo modo.

Le API Web sono progettate per consentirti di scrivere il codice del tuo controller in modo "naturale" il più possibile. Il tipo di ritorno IHttpActionResult è principalmente inteso come un tratteggio di escape quando si desidera la massima flessibilità.

Ecco come scriverei il tuo metodo:

public ClrObject1 Method1(string arg1 = null, string arg2 = null, string arg3 = null)
{
    ClrObject1 varClrObject = (from p in db.clrObject1
                               where p.column1 == arg1
                               select p).SingleOrDefault();

    if (varClrObject == null)
    {
        // This line will automatically return a 404 error to the user.
        throw new HttpResponseException(HttpStatusCode.NotFound);
        // If you want, you can also build a full HttpResponseMessage
        // to give more details about the error.
    }

    // Web API will automatically return serialize and return your object
    // in a 200 OK response.
    return varClrObject;
}

Noterai che non metto un blocco di try - catch per gestire le eccezioni - il motivo è che, se un'eccezione viene sollevata e non gestita, verrà restituito all'utente un errore 500, che di solito è quello che voglio. Inoltre, non si desidera sempre restituire dettagli sulla propria eccezione nella risposta HTTP, in quanto tali informazioni potrebbero rivelare informazioni che potrebbero essere utilizzate per aiutare l'hacking del server delle applicazioni.

    
risposta data 15.03.2014 - 23:04
fonte
1

Sono d'accordo con @jhominal che stai rendendo questo modo più complicato di quanto debba essere. Innanzitutto, l'azione deve restituire un'istanza concreta di un oggetto. La ragione di ciò è di consentire al framework API Web di eseguire la negoziazione del contenuto tra JSON e Xml senza troppi problemi. Se non ti devi preoccupare di questo e puoi scegliere tra l'uno o l'altro, puoi usare un'interfaccia per il tuo oggetto (che è in genere ideale), ma non hai bisogno di un HttpActionResult perché quando esegui un entrare nell'API Web stai cercando una risorsa specifica e quella risorsa dovrebbe avere un tipo. Qualsiasi cosa che non restituisce una risorsa dovrebbe restituire un HttpResponseMessage formattato correttamente che è più facilmente gestito attraverso un HttpResponseException . Incollerò uno snippet qui sotto con i commenti per descrivere come mi piace creare azioni del controllore:

// I always specify the http verb that the method is 
// intended to respond to. It's extremely rare that
// multiple verbs should perform the same actions in
// an API. Also, I'm not a big fan of using optional
// parameters in this manner. I much prefer to use a 
// common get action and then pull the arguments like
// this from the RequestUri. It helps keep my routes
// nice and clean
[HttpGet]        
public MyCustomObject Post(string arg 1= null, string arg2 = null, string arg3 = null)
{
    // Perform validation of arguments as necessary
    // If it's not necessary, then skip this
    if (string.IsNullOrWhiteSpace(arg1))
    {
        throw new HttpResponseException(Request.CreateErrorResponse(
            HttpStatusCode.BadRequest,
            "I need to be supplied with arg1."));
    }

    // I prefer to send a request with relevant data to 
    // a rules engine/library of some sort that returns 
    // a formatted response (very similar to your
    // ReturnMessages object
    var response = MyRules.PerformQuery<MyCustomObject>(arg1, arg2, arg3);

    // Just as your ReturnMessages I use a status code
    if (response.Code == ResponseCode.Success)
    {
        return response.Entity;
        // In my preferred architecture, response.Entity is a
        // generic type, in this case MyCustomObject as above
    }

    // If you get to this point, something has gone wrong.
    // You can add additional logic before or after your
    // call to deliver this response message. The arguments
    // necessary are a property HttpStatusCode (any code)
    // and a valid response message string.
    throw new HttpResponseException(
        Request.CreateErrorResponse(response.Code, response.Message));
}

Quindi, per riassumere, cerco di mantenere la mia architettura il più semplice possibile. Le sue ossa sono la convalida dell'argomento, una chiamata a un motore di regole, una risposta all'oggetto concreto e quindi casi di eccezione. Aiuta a mantenere l'azione del controller fornendo risposte HTTP adeguate rispetto a risorse e messaggi.

    
risposta data 19.03.2014 - 14:14
fonte

Leggi altre domande sui tag