Come consumare le API standard instradate in modo pulito?

2

Facciamo un esempio di un endpoint API generico che appare come segue:

https://api.imgur.com/3/gallery/{section}/{sort}/{window}/{showViral}/{page}

Le condizioni su questo endpoint sono le seguenti:

  1. Gli argomenti sono facoltativi. I valori predefiniti verranno utilizzati se non forniti.
  2. Tutti gli argomenti precedenti devono essere forniti per utilizzare un argomento. Quindi, in questo esempio, se dovessi ottenere i post della pagina n. 2, devo fornire i valori di sezione, ordinamento, finestra e showViral.

Sto cercando di creare un wrapper C # attorno a questi endpoint. Il mio metodo ha un aspetto simile al seguente:

public static async Task<List<Image>> GetGallery(Section? section = null, Sort? sort = null, Window? window = null, bool? showViral = null, int? page = null)
{
    string uri = "gallery";
    if (section != null)
    {
        uri += "/" + section.ToString().ToLower();
        if(sort != null)
        {
            uri += "/" + sort.ToString().ToLower();
            if(window != null)
            {
                uri += "/" + window.ToString().ToLower();
                if (showViral != null)
                {
                    uri += "/" + showViral.ToString();
                    if (page != null)
                    {
                        uri += "/" + page;
                    }
                }
            }
        }
    }
    JObject response = await NetworkHelper.ExecuteRequest(uri);
    return response["data"].ToObject<List<Image>>();
}

Non sono davvero contento di questa implementazione. Questo codice sembra molto brutto. Qualche idea su come posso migliorare questo?

    
posta akshay2000 11.09.2015 - 13:31
fonte

3 risposte

3

Una soluzione semplice con LINQ:

string CreatePath(params string[] segments)
{
    var includedSegments = segments.TakeWhile(segment => segment != null));
    return String.Join("/", includedSegments);
}

Quindi devi solo passare gli argomenti del segmento di stringa in ordine, convertiti in stringa. In alternativa puoi eseguire la conversione delle stringhe all'interno:

string CreatePath(params object[] segments)
{
    var includedSegments = segments.TakeWhile(segment => segment != null)).Select(segment => segment.ToString());
    return String.Join("/", includedSegments);
}
    
risposta data 11.09.2015 - 17:35
fonte
2

Puoi scrivere una soluzione fluente. Ha bisogno di alcune interfacce, ma l'utilizzo per un client è molto semplice e guidato, poiché il completamento automatico suggerisce automaticamente due possibilità in ogni punto: Immagini o sottocriteri, ad es. Sort (...);

Quindi per il cliente, l'utilizzo sarebbe simile a questo:

var g = // get gallerygetter from somewhere 

// get all images
var images = g.Get().Images;

// subsets
var images = g.Get().Section(section).Sort(sort).Images;

var images = g.Get()
    .Section(section)
    .Sort(sort)
    .Window(window)
    .ShowViral(showViral)
    .Page(page)
    .Images;

Ora ovviamente, per supportare un uso così piacevole, hai bisogno di alcune interfacce. Ma puoi implementare tutti quelli in una singola classe.

public interface IGallerySectionSortWindowShowViralPage : IGallery
{ 
    IGallery Page(int x);
}

public interface IGallerySectionSortWindowShowViral : IGallery
{
    IGallerySectionSortWindowShowViralPage ShowViral(bool x);
}

public interface IGallerySectionSortWindow : IGallery
{
    IGallerySectionSortWindowShowViral Window(Window w);
}

public interface IGallerySectionSort : IGallery
{
    IGallerySectionSortWindow Sort(Sort s);
}

public interface IGallerySection : IGallery
{
    IGallerySectionSort Section(Section s);
}

public IGallery
{
    Task<List<Image>> Images { get; }
}

public IGalleryGetter : IGallery
{
    IGallerySection Get();
}

public Gallery 
    : IGallery
    , IGalleryGetter
    , IGallerySection
    , IGallerySectionSort
    , IGallerySectionSortWindow
    , IGallerySectionSortWindowShowViral 
    , IGallerySectionSortWindowShowViralPage
{
    private string uri = "gallery";

    public Task<List<Image>> Images 
    {
        JObject response = await NetworkHelper.ExecuteRequest(uri);
        return response["data"].ToObject<List<Image>>();
    }

    public IGallerySection Get()
    {
        return this;
    }

    public IGallerySectionSort Section(Section section)
    {
        uri += "/" + section.ToString().ToLower();
        return this;
    }

    public IGallerySectionSortWindow Sort(Sort sort)
    {
        uri += "/" + sort.ToString().ToLower();
        return this;
    }

    public IGallerySectionSortWindowShowViral Window(Window window)
    {
        uri += "/" + window.ToString().ToLower();
        return this;
    }

    public IGallerySectionSortWindowShowViralPage ShowViral(bool show_viral)
    {
        uri += "/" + show_viral.ToString().ToLower();
        return this;
    }

    public IGallery Page(int page)
    {
        uri += "/" + page.ToString().ToLower();
        return this;
    } 

}
    
risposta data 11.09.2015 - 14:19
fonte
2

Puoi migliorare questo metodo separando il metodo di unione dei percorsi.

public static string BuildPath(params object[] paths) {
    string result = "";
    if (paths != null) {        
        foreach(var path in paths) {
            if (path == null) break;
            result += "/" + path;
        }
    }
    return result;
}

Quindi la tua implementazione avrà più senso, perché è one-liner

string uri = BuildPath("gallery", section, sort, window, showViral, page);

Ho fatto questo in un violinista qui: link . Si noti che questo è l'imitazione del comportamento del codice e non esegue la codifica del percorso URL.

    
risposta data 11.09.2015 - 16:34
fonte

Leggi altre domande sui tag