Come creare un client generico per interrogare un'API e restituire diversi tipi in base alla chiamata API?

-1

Sto costruendo un repository che richiederà i dati da un'API. Inizialmente, ho avuto più metodi nel mio repository come GetOrders() , GetOrderItems() ecc.

La maggior parte di queste funzioni aveva quasi lo stesso corpo del metodo ad eccezione di:

  • Aveva un URL di endpoint diverso
  • Deserializza il JSON in oggetti diversi
  • Avere una diversa variabile di percorso JSON (ad esempio SuccessResponse.Body.Orders.Order)

Poiché il codice è quasi lo stesso, voglio metterlo in una classe, forse qualcosa chiamato {Company}ApiClient (è questo il nome giusto ??) che sarà responsabilmente per eseguire la chiamata API e restituire l'oggetto.

Come creo questa classe in modo che io possa avere lo stesso codice ma la classe può restituire un tipo diverso a seconda di ciò che sta restituendo dall'API? Sto assumendo che ho bisogno di usare i generici ma da quello che posso vedere, il tipo è specificato a livello di classe.

Qualche consiglio sarebbe fantastico!

    
posta Lock 04.05.2017 - 12:34
fonte

2 risposte

1

È possibile creare una classe astratta che definisce il comportamento predefinito per le richieste comuni e utilizza il tipo generico. In java:

public abstract class AbstractRepository<T> {
    ...
    //When constructed pass additional details if needed
    public AbstractRepository(Class<T> type, String baseURL, Client client) {
        this.type = type;
        this.baseURL = baseURL;
        this.client = client;
    }

    public T findById(final String id) {
        //This is where you actually make the call and if you need to 
        //provide the object type information to whatever means you are 
        //using to deserialize the return
        return client.get(id, ...);
    }

    public List<T> findAll() {
        return client.get(...);
    }

    public T update(final T obj) {
        return client.update(obj, ...);
    }

    public List<T> findAllByTerms(SearchTerms searchTerms) {
        return client.get(formatSearchTerms(searchTerms),...);
    }

    ...
}

Quindi estendi questa classe con i tuoi tipi

public class OrderRepository extends AbstractRepository<Order> {

    //Call super constructor, pass values if needed
    public OrderRepository(Client client) {
        super(Order.class, Order.BASE_URL, client);
    }

    //If you need 'special' searches for Order, add them in
    public Integer getTotalOrderCount() {
        return super.findAll().size();
    }

    public List<Order> findAllByOrderType() {
        SearchTerms searchTerms = new SearchTerms();
        searchTerms.add("type", OrderTypes.OVERSEAS);
        return super.finalAllByTerms(searchTerms);
    }
}

Quindi se vuoi che una classe client in cui tutte le chiamate siano avviate puoi farlo in alcuni modi, il mio modo ingenuo sarebbe di contenere tutti i tuoi repository e i loro metodi sarebbero proxy per loro:

public class ApiClient {
    private OrderRepository orderRepository;
    private OrderItemRepository orderItemRepository;

    public ApiClient() {
        //Just an holder
        Client client = new Client("user", "password");
        this.orderRepository = new OrderRepository(client);
        this.orderItemRepository = new OrderItemRepository(client);
    }

    public Order findOrderById(Itneger id) {
        return orderRepository.findById(id);
    }

    public List<Order> findAllOrders() {
        return orderRepository.findAll();
    }

    public OrderItem findOrderItemById(Integer id) {
        return orderItemRepository.findById(id);
    }

    ...
}
    
risposta data 05.05.2017 - 01:03
fonte
0

Sì, puoi utilizzare i generici (in c #)

public class Api<T> where T : new
{
     public T GetById(string id);
}

Se il tuo oggetto corrisponde alla deserializzazione predefinita, pronuncia da Json.Net, quindi lo creerà e lo popolerà correttamente attraverso il riflesso.

Tuttavia. Non consiglio questo approccio perché ha un paio di problemi.

1: Come già detto, devi essere in grado di creare e popolare l'oggetto in un modo generico. Se hai un nome strano o un parametro di costruzione hai problemi.

2: tutti i client hanno gli stessi metodi generici. GetById, GetAll ecc. Se vuoi qualcosa di specifico, GetByDateOfBirth di nuovo non puoi farlo.

Penso che probabilmente il httpClient predefinito abbia già il livello di genericità di cui hai bisogno. I tuoi client API come dici tu devono solo specificare l'URL, il percorso, il nome del metodo ecc.

    
risposta data 04.05.2017 - 12:51
fonte

Leggi altre domande sui tag