Dovremmo personalizzare le API per il cliente o chiedere al cliente di utilizzare quello esistente?

4

Sono un unico sviluppatore e di recente ho scritto una nuova applicazione web sotto forma di API con Swagger e front-end. Questo era il modo in cui i clienti potevano usare l'API da soli, di solito forscripting.

È quasi in fase di completamento e il mio capo che non è uno sviluppatore ha rilevato che l'API sembra troppo difficile per i consumatori e ritiene che ci sarà un po 'di respingimento. Ad esempio, quando premi / api / clienti puoi recuperare i dati correlati nel formato di Id: { name: "Bob", FavoriteProducts: [ 1, 2, 5] } .

Funziona alla grande per il front-end. Esistono molte pagine che caricano i dati correlati su richiesta, a volte mostriamo un riepilogo del cliente per esempio e non utilizziamo i prodotti preferiti, a volte mostriamo una grande tabella di clienti, quindi tutti i dati correlati richiederebbero un caricamento per sempre.

Dice che i clienti non vorranno dover effettuare chiamate separate per i dati correlati, e dice che su un inserto sarebbe più facile se potessero fornire nomi di prodotti e averli mappati ai loro ID e persistessero magicamente sul back end: { name: "Bob", FavoriteProducts: [ "Plastic Spiders", "Candy", "Pumpkins"] } . Questo sembra abbastanza innocuo, ma questa è una semplificazione grossolana di molti più dati e molti più endpoint, tabelle di ricerca, tabelle di codici, ecc.

Non abbiamo ancora avuto il nostro primo consumatore, quindi non sappiamo se questo sarà effettivamente un problema, ma ha detto che dalla sua esperienza di scripting, vuole fare il minor numero possibile di chiamate API.

Non sono completamente d'accordo, penso che dovremmo sforzarci di rendere la vita dei nostri clienti più facile, soprattutto perché è un mondo competitivo là fuori. Ma ho anche lavorato duramente per creare un'API RESTful con buone prestazioni e ben documentata tramite Swagger che è consumabile dai generatori di client Swagger (come NSwag) che possono leggere i documenti e sputare un client in quasi tutte le lingue. Penso che ci sia una linea da bilanciare quando si tratta di aggiungere un sacco di codice back-end extra e debito tecnico perché qualcuno non vuole effettuare 2 chiamate API.

Immagino che GraphQL avrebbe potuto renderlo più semplice, ma penso che questo capo avrebbe detto che sarebbe troppo difficile per i clienti scripting imparare questa nuova lingua, e non vorrebbe passare il tempo per imparare perché ha posto il veto ad Angular per questo progetto per quella ragione esatta. Inoltre, non pensavo che questo sarebbe stato un problema. Abbiamo riscritto una grande app legacy che ha archiviato tutti i suoi dati in una singola tabella su un'API RESTful con tabelle di ricerca e convalida dei dati corrette. Quindi ho pensato che avrebbe complicato un po 'il consumo e ho pensato che sarebbe andato bene.

    
posta Victorio Berra 24.10.2018 - 17:00
fonte

5 risposte

9

Se hai mai utilizzato le API RESTful, ne hai trovato almeno uno in cui devi effettuare più chiamate API per ottenere tutti i dati che desideri. Semplicemente arriva con il territorio. I vantaggi di una API granulare sono che puoi ottenere esattamente ciò di cui hai bisogno e niente che non sia. Il costo è costituito da più chiamate, che possono diventare negative se è necessario creare un grafico di oggetti profondi.

Il rovescio della medaglia è RETURN TUTTO . Prodotti preferiti, colori, vendite imminenti, dettagli sulla spedizione in Madagascar, ecc. È molto piacevole da leggere, ma può essere difficile da setacciare quando si desidera solo il nome e l'indirizzo del cliente. Può anche avere problemi di prestazioni, specialmente con il ritorno di tanti dati.

Quindi cosa fai?

La mia prima raccomandazione sarebbe quella di applicare un'API piuttosto semplice come quella che hai. La maggior parte degli sviluppatori non sarà colto di sorpresa da questo. Inoltre, se non hai clienti che ti dicono quello che vogliono, come puoi sapere cosa vogliono? Puoi indovinare, ma come qualcuno che ha sviluppato un software per un po 'ti può dire, indovinare ciò che un cliente vuole funziona solo una volta. Il più delle volte ti capita di sbagliare (o almeno non del tutto corretto).

Se il tuo capo è insistente, potresti fornire un tipo di compromesso consentendo agli utenti API di richiedere quali dati ricevono. Supponiamo che tu abbia il seguente endpoint e risposta:

/customers/1 -> { name: "bob", favoriteProducts: [ 1, 3 ] }

Ora dì che aggiungi un parametro per dire che vuoi recuperare le informazioni complete sul prodotto:

/customers/1?favoriteProducts=full -> { name: "bob", favoriteProducts: [ { id: 1, name: "plastic spiders", ... }, { id: 3, name: "pumpkins", ... }] }

È possibile aggiungere tutte le opzioni di configurazione che hanno senso. Assicurati di documentarli completamente in modo che non ci siano sorprese.

    
risposta data 24.10.2018 - 17:32
fonte
3

Non stai adattando la tua API ai clienti. Il tuo capo desidera che tu personalizzi l'API in base alla sua intuizione selvaggia su ciò che i clienti potrebbero desiderare.

Come cliente di API (sviluppatore di software, quindi sono il tuo cliente, non le persone a cui il tuo capo vuole vendere): il peggiore di sempre è un'API che cerca di essere intelligente. Non scrivere un'API che cerchi di essere intelligente. Gli ID univoci sono un modo eccellente per accedere a un'API.

Se i clienti dicono ai loro sviluppatori che non gli piace l'API, allora puoi implementare le cose - dopo che il tuo capo si è assicurato che il cliente paghi. Ricorda la regola ferrea di un business di successo: il cliente ha sempre ragione, se il cliente paga.

    
risposta data 24.10.2018 - 17:57
fonte
1

Non penso che ci sia molto da guadagnare opponendosi al capo qui. È lui che prende le decisioni aziendali e il cui compito è anticipare le esigenze dei suoi clienti.

Se seguendo i modelli suggeriti dal tuo capo renderebbe il tuo front-end standard più difficile da creare, mantenere e / o danneggiare le sue prestazioni, dovresti prendere in considerazione la possibilità di creare due versioni di ogni endpoint dell'API. Una versione "machine-friendly" su misura per i requisiti del frontend e una versione "user-friendly" adattata alle esigenze degli sceneggiatori presso il cliente.

La creazione di questa API separata oltre a quella attuale probabilmente non funzionerà più per ora perché non è necessario modificare nulla sul client già funzionante. Ma tieni presente che aumenterà la manutenzione e la documentazione a lungo termine. Potresti essere in grado di ridurre l'overhead condividendo il maggior numero possibile di codice tra loro. È possibile implementare un endpoint chiamando l'altro.

    
risposta data 24.10.2018 - 17:35
fonte
1

For example, when you hit /api/customers you may get back related data in the form of Ids: { name: "Bob", FavoriteProducts: [ 1, 2, 5] }.

This works great for the front-end. There are many pages that load the related data on demand, sometimes we show a customer summary for example and don't use the FavoriteProducts, sometimes we show a huge table of customers so all that related data would take forever to load.

Il tuo capo ha un caso d'uso qui e anche la tua preoccupazione per le prestazioni è valida. Non penso che siano in conflitto e indirizzandoli entrambi renderanno le API migliori.

Per l'API, devo dire che se faccio un GET /api/customers/ preferisco vedere una risposta come { name: "Bob", FavoriteProducts: [ "Plastic Spiders", "Candy", "Pumpkins"] }

Per quanto riguarda le prestazioni, so che hai fatto un punto di riferimento tra i commenti, penso che tu debba profilare il tuo in modo diverso. La ragione di ciò è che i problemi di prestazioni devono essere risolti, non devono modellare la forma dell'API (naturalmente, ovviamente).

Un modo per vedere questo è inserire risposte di esempio nei file e fare in modo che un server serva questi file statici in modo da poter vedere la differenza tra i due stili API. Cioè :

GET /api/customers   <-- returns fav product IDs
GET /api/favorite_products/1
GET /api/favorite_products/2
GET /api/favorite_products/5

vs.

GET /api/customers <-- this one returns related fav products

Non ci ho provato ma sono sicuro che il secondo sarà più veloce a causa di meno round trip. Questo è ciò che la maggior parte dei clienti vorrebbe. Anche se non ho bisogno dei prodotti preferiti, non mi disturba, è solo una chiamata.

Ovviamente, se implementato con tutte le ulteriori ricerche, ci sarà un hit dalle prestazioni e dovrà essere affrontato. Non è impossibile rimuovere la maggior parte del carico extra, ad es. memorizzando i dati in modo diverso, utilizzando l'archivio dei valori-chiave in-memory, la memorizzazione nella cache ecc.

    
risposta data 24.10.2018 - 18:58
fonte
0

Opzione C. Il meglio di entrambi i mondi.

Per aiutare a pensare a questo problema, vorrei esprimere questa idea in termini di relazioni tra entità, che puoi considerare come tabelle di database se è più semplice.

Il modello

Basato su questo esempio ...

{ name: "Bob", FavoriteProducts: [ 1, 2, 5] }.

... Sto inferendo le seguenti entità:

  1. Customer , con una chiave primaria di CustomerID
  2. Product , con una chiave primaria di IDProdotto
  3. CustomerProduct , con una chiave composta di CustomerID + ProductID, che se presi separatamente fungono anche da chiavi esterne alle rispettive tabelle.

Il modo in cui vuoi farlo

Vuoi due chiamate API.

  1. Una chiamata restituisce una singola riga da Customer e più righe da CustomerProduct
  2. Una chiamata restituisce una singola riga da Product

Il modo in cui il tuo capo vuole farlo

  1. Una chiamata che restituisce dati da Customer , CustomerProduct e Product .

Opzione C. La mia raccomandazione

Questo è proprio come il tuo-- due chiamate-- ma dividendo le entità in modo diverso.

  1. Una chiamata per ottenere un singolo Customer
  2. Una chiamata per ottenere l'intero elenco CustomerProduct di quel cliente e tutti i record associati da Product

Questo è un modo molto più naturale di dividere il lavoro e molto più semplice da usare per un cliente: o vogliono i prodotti o meno, e gli ID da soli sono inutili.

Ciò ridurrà anche il numero di chiamate che il server web dovrà gestire e ridurrà il carico sul database, poiché il database sarà in grado di utilizzare una ricerca indice singola seguita da una scansione dell'indice per ottenere l'intero elenco. Se il cliente richiedesse uno per uno ciascun prodotto, ciò sarebbe impossibile.

Infine, questo progetto eliminerà alcuni brutti bug di concorrenza / coerenza che potrebbero verificarsi. Ad esempio, cosa succede se, nel mezzo di recuperare l'elenco dei prodotti di un cliente, qualcosa nella lista è cambiato, o uno dei prodotti è stato interrotto? Sebbene rari, questi problemi potrebbero farti diventare pazzo, perché sono difficili da riprodurre. Ottenendo l'elenco e i relativi record tutto in una volta, il problema viene completamente evitato.

    
risposta data 25.10.2018 - 02:59
fonte

Leggi altre domande sui tag