Qual è un buon modello di progettazione per implementare i servizi REST sui dispositivi mobili?

4

È facile implementare chiamate agli endpoint dell'API, quindi analizzare JSON e gestire i dati, ma quale è un buon modello di progettazione per questo?

Ecco alcuni modi in cui ho provato, ma mi sembra che ci dovrebbe essere un modo migliore:

  1. Crea una classe singleton che gestisca tutto il codice di rete e tutto il codice di analisi dei dati per l'intera applicazione per tutti gli endpoint. Quindi qualsiasi classe di controller può colpire il singleton
  2. Crea attività di endpoint di rete direttamente dai controller di visualizzazione - utilizzando i blocchi all'interno del controller di visualizzazione per gestire le risposte

Considera un'applicazione che può colpire un endpoint (GET) per scaricare un elenco di appuntamenti. Considerare anche un endpoint POST in cui è possibile inviare nuovi appuntamenti.

I dati devono essere pacchettizzati / non pacchettizzati in JSON e gli errori devono essere gestiti in modo appropriato.

Che cosa è un buon modello di progettazione per realizzare questo?

E prima di sviare questo post e dire che è troppo ampio o soggettivo, guarda questa pagina:

link

Some subjective questions are allowed, but “subjective” does not mean “anything goes”. All subjective questions are expected to be constructive.

Una buona risposta a questo problema comune è difficile da trovare.

    
posta Spentak 12.09.2014 - 19:16
fonte

2 risposte

3

Tratta l'API REST come qualsiasi altra origine dati e crea un'astrazione (ad esempio AppointmentRepository, ecc.) utilizzata dai controller. I miei esempi sono in Java, ma penso che ti verrà l'idea.

public interface AppointmentRepository {
    Appointment findById(String id) throws RepositoryAccessException;
    void create(Appointment appointment) throws RepositoryAccessException;
    void update(Appointment appointment) throws RepositoryAccessException;
    void delete(Appointment appointment) throws RepositoryAccessException;
}

public class RestAppointmentRepository {
    @Override
    public Appointment findById(String id) throws RepositoryAccessException {
        // make the API call
        // translate the JSON to an Appointment object
        return appointment;
    }
    // etc
}

Utilizzando un'astrazione in questo modo si disaccoppia il controller dalla fonte concreta di dati, in modo che i due possano cambiare senza influenzarsi a vicenda. Considerare se in futuro l'API REST modificherà la propria rappresentazione di un appuntamento, il che significa che il codice di mapping deve essere modificato. Quando il codice di mappatura è nascosto dietro un'astrazione, non è necessario apportare modifiche al controller per gestire la modifica dell'API REST.

Questo approccio consente anche di testare più facilmente il controller senza doversi preoccupare dell'API REST che restituisce i dati per supportare i test dell'unità. Oltre al test del percorso felice, è necessario verificare che il controller reagisca in modo appropriato quando l'API REST non è disponibile, ad esempio quando il metodo del repository genera un'eccezione. Prendi l'interfaccia del repository come dipendenza dal controller e prendi in giro il tuo test dell'unità in modo che tu possa definire facilmente il suo comportamento.

public AppointmentController extends ViewController {
    private final AppointmentRepository appointmentRepository;

    public AppointmentController(final AppointmentRepository appointmentRepository) {
        Preconditions.checkNotNull(appointmentRepository);
        this.appointmentRepository = appointmentRepository;
    }
}
...
// unit test
AppointmentController appointmentController = new AppointmentController(mockAppointmentRepository);
    
risposta data 12.09.2014 - 21:33
fonte
1

Direi che il secondo metodo (chiamate di endpoint diretto dal controller di visualizzazione) non è molto futuro per la possibilità di dover estendere la funzionalità a una chiamata api automatica / bulk separata dalla vista.

Ad esempio, cosa accadrebbe se venisse creato un nuovo requisito per pubblicare 100.000 appuntamenti tramite la tua app, in base a un input excel, per il quale l'esecuzione avrebbe dovuto essere eseguita in batch e pianificata per impedire i limiti delle chiamate api sul tuo endpoint di destinazione? Se il codice di chiamata e gestione è stato inserito nel controller di visualizzazione per un modulo (definire e postare un appuntamento SINGLE), dovresti estrarlo nella sua classe (probabile singleton), estenderlo per assicurarti che possa gestire il caso di massa e gestisci le risposte.

Poiché l'invio di richieste è gestito da una libreria e l'analisi JSON della risposta è (forse?) gestita da una libreria, il punto cruciale sta determinando se avvolgere tutta la logica di risposta alla chiamata per tutti gli endpoint in una classe, o ne hai uno per ogni sistema di destinazione.

Invece di guardare / pubblicare su una API appuntamento, considera un sistema master CRM che controlli sia la creazione di una fattura tramite l'integrazione ERP sia l'autorizzazione tramite l'integrazione di Product Server. In questo caso, due API SEPARATE vengono utilizzate dalla logica di integrazione, ma utilizzano ancora la stessa logica di libreria per richiedere e analizzare la risposta.

Il mio approccio è stato:

  1. Separa la logica di tutto il controller (e, meno importante, la vista) per ogni integrazione di sistema nel proprio spazio dei nomi all'interno dell'applicazione. Ad esempio) ERP_Example, PS_Example

  2. Estrarre il contenuto (attributi della richiesta) della chiamata di integrazione in una classe (possibilmente inline), quindi utilizzare la serializzazione JSON, controllata da una classe di integrazione statica dedicata specifica per il sistema per effettuare la chiamata, analizzare la risposta e instradare opportunamente la logica successo / errore.

Es.) ERP_InvoiceIntegration.class, PR_EntitlementIntegration.class

  1. Quindi, quando ho bisogno di eseguire il bulk delle chiamate, posso semplicemente creare:

ERP_BatchableInvoiceActioner.class, PR_BatchableEntitlementsActioner.class

per gestire il caso di massa e chiamare la classe di integrazione da ciascun batch, sapendo che la classe stessa instraderà correttamente successo / fallimento.

Sembra anche che questo modello sia in grado di gestire sia le chiamate sincrone che quelle asincrone, anche se non tanto nel caso in blocco, a seconda di.

Risposta più breve: Singleton per ogni target di integrazione, ma non per ogni chiamata API (get / post / etc) ...

    
risposta data 12.09.2014 - 21:10
fonte

Leggi altre domande sui tag