In un'API REST, dovresti correggere l'input dell'utente sul lato server?

2

Abbiamo un'API REST con un endpoint che accetta i dati JSON dal client. Uno dei campi JSON è un URL che verrà reso ad altri utenti come collegamento ipertestuale a una pagina del sito Web associata alla risorsa. Da qualche parte nella pipeline dovevamo assicurarci che l'URL sia valido (inizia con http(s):// , contiene un dominio da una whitelist, ecc.).

Quindi abbiamo progettato l'API in modo tale che accetti solo URL validi e restituisca un errore (400) quando l'URL è considerato non valido. Sul lato dell'interfaccia utente, l'utente deve correggere l'URL finché non è valido, il messaggio di errore si adatta al caso di errore (valore mancante, dominio non valido, formato non valido ...).

Il nostro proprietario del prodotto ha testato la nostra implementazione prima di andare in diretta e ha avuto problemi con questo approccio semplice. Ha digitato "facebook.com/foobar" e si aspettava che l'URL fosse valido. Il messaggio di errore era qualcosa del tipo "Inserisci un URL valido come link ". Si aspettava (giustamente) che il campo di input avrebbe accettato qualsiasi cosa accettasse una barra degli indirizzi del browser. Il messaggio di errore avrebbe potuto essere più chiaro ("l'URL dovrebbe iniziare con http (s): //"), ma abbiamo concordato che aveva ragione e che in questo caso l'input dell'utente dovrebbe essere corretto dalla nostra applicazione prima di essere salvato.

Qui abbiamo avuto 2 idee:

  • Sia che l'API corregga l'URL (antepone un protocollo predefinito) al momento del salvataggio;
  • Oppure anteponi il protocollo sul lato client e non toccare la convalida dell'API.

Ho una strong preferenza per il metodo lato client, perché credo che un'API REST non debba mai alterare l'input dell'utente in modo silenzioso (non sai mai quale tipo di client consumerà la tua API, e la modifica silenziosa dell'input dell'utente potrebbe avere effetti collaterali inaspettati- effetti). Il problema è che non sono riuscito a trovare alcun esempio di vita reale per supportare il mio punto di vista.

Al contrario, uno dei miei compagni di squadra (quello responsabile della correzione) non ha trovato alcun motivo valido per preferire un metodo rispetto all'altro e ha optato per la correzione dell'API (principalmente perché è molto più veloce da implementare e non devi implementare questo comportamento per ogni client utilizzando la tua API).

Che ne pensi?

    
posta Maxime Rossini 17.09.2018 - 16:05
fonte

5 risposte

6

Sono d'accordo con la modifica non silenziosa dell'input dell'utente, potrebbe causare confusione e non riflette perfettamente i dati JSON inviati dall'utente finale.

Sebbene la verifica dell'input dell'utente sul lato client possa essere aggirata, è comunque una mossa saggia mostrare all'utente che il suo url verrà modificato prima che venga consumato.

In ogni caso, verifica sempre l'input lato server, perché potresti assumere che i dati (in questo caso l'url) siano ben formati, ma l'utente ha il controllo completo sull'interfaccia utente e potrebbe inviare dati difettosi che risultano in un cattivo errore del server.

    
risposta data 17.09.2018 - 18:09
fonte
4

Per me c'è un chiaro vincitore.

Dovresti sempre chiederti chi è responsabile di cosa? Per me, l'API Rest (e qualsiasi API) deve essere mantenuta semplice, non aggiungere mai comportamenti al di fuori di quanto ci si aspetta da essa, in questo scenario, l'API ha il ruolo di memorizzare i dati per l'ultimo utilizzo, quindi no, non correggere silenziosamente .

Inoltre, se aggiungete questa responsabilità all'API, dove tracciate la linea di cosa dovrebbe essere corretto e cosa no?

Se hai bisogno di coerenza sul lato client, aggiungi una classe nell'API consumer che gestisce questo tipo di problemi e riutilizzala ovunque utilizzi l'API.

    
risposta data 18.09.2018 - 00:34
fonte
1

Non vedo un problema in questo caso specifico poiché il riferimento all'URL è ben noto. Il tuo servizio non dovrebbe avere problemi ad accettare facebook.com/foobar o https://www.facebook.com/foobar come input valido.

Sai che l'URL fa riferimento a una pagina di Facebook, le pagine di Facebook possono sempre utilizzare HTTPS e Facebook eseguirà il reindirizzamento se www non è specificato.

Non modificherei l'input dell'utente; Vorrei semplicemente

  • convalidare che corrisponda al formato di un URL
    • aggiungi uno schema mancante solo nel test per la convalida, in modo che i dati realmente non validi ( facebook=com\foobar ) possano essere rifiutati
  • memorizza tutto ciò che l'utente ti ha dato così com'è
  • formatta in modo appropriato (aggiungi https:// mancante) durante il rendering

Se l'utente ha bisogno di modificare l'URL in futuro, può essere presentato con esattamente quello che ha inserito e non sarà sorpreso da eventuali modifiche.

Puoi tenere conto delle aspettative degli utenti mentre non modifichi i dati.

    
risposta data 17.09.2018 - 19:45
fonte
1

C'è un'opzione che non è stata menzionata, e quella è la definizione di ciò che costituisce un input corretto per l'API. Rendi "facebook.com" un valore di campo accettabile (nota: il campo ora è NON un URL) e documentalo. Quindi non è necessaria la correzione . L'API quindi utilizza questo campo per creare un collegamento ipertestuale quando genera una risposta successiva, se necessario, proprio come userebbe una data di nascita per calcolare l'età di un utente.

Il resto del mio punto di vista segue ciò che Dan Wilson ha scritto.

    
risposta data 02.10.2018 - 11:28
fonte
-1

Non sembra esserci una vera ragione per preferire l'uno sull'altro.

Essenzialmente hai un metodo che vuoi esporre (sarebbe bello avere alcuni nomi reali qui)

service.Method(urlLikeString)

e un codice che cambia una stringa simile a un url in un URL. Ci sono tre possibili posizioni per metterlo

1 l'applicazione

app.Method(urlLikestring)
{
    url = getUrl(urlLikestring)
    client.Method(url);
}

2 il client

app.Method(urlLikestring)
{
    client.Method(urlLikestring);
}

client.Method(urlLikestring)
{
    url = getUrl(urlLikestring)
    httpclient.post(url)
}

3 il server

client.Method(urlLikestring)
{
    httpclient.post(urlLikestring)
}


server.Method(urlLikestring)
{
    url = getUrl(urlLikestring);
    logic.Method(url);
}

A meno che non ci sia uno scenario in cui non vuoi convertire UrlLikeString, o la conversione richiede informazioni che solo uno dei livelli ha. Non fa alcuna differenza dove si inserisce la conversione.

Ovviamente devi ancora verificare che urlLikeString sia simile a url qualunque cosa tu faccia

    
risposta data 17.09.2018 - 18:11
fonte

Leggi altre domande sui tag