Pregunta

I'm building a ReST API that supports linked resource expansion, and I can't work out how to use ServiceStack's native binding capabilities to translate a URL into a populated 'request DTO' object.

For example, say my API allowed you to retrieve information about a band using this request:

GET /bands/123

< 200 OK
< Content-Type: application/json
{
    "href": "/bands/123",
    "name": "Van Halen",
    "genre": "Rock",
    "albums" {
        "href" : "/bands/1/albums",
    }
}

If you wanted to expand the band's album list, you could do this:

GET /bands/1?expand=albums

< 200 OK
< Content-Type: application/json
{
    "href": "/bands/123",
    "name": "Van Halen",
    "genre": "Rock",
    "albums" {
        "href" : "/bands/1/albums",
        "items": [
            { "href" : "/bands/1/albums/17892" },
            { "href" : "/bands/1/albums/28971" }
        ]
    }
}

I'm using ServiceStack, and I'd like to perform this inline expansion by re-using existing service methods.

My ServiceStack response DTOs look like this:

public class BandDto {
    public string Href { get; set; }
    public string Name { get; set; }
    public AlbumListDto Albums { get; set; }
}

public class AlbumListDto {
    public string Href { get; set; }
    public IList<AlbumDto> Items { get; set;}
}

public class AlbumDto {
    public string Href { get; set; }
    public string Name { get; set; }
    public int ReleaseYear { get; set; }
}

My ServiceStack request/route objects are like this:

[Route("/bands/{BandId}", "GET")]
public class Band : IReturn<BandDto> { 
    public string Expand { get; set; }
    public int BandId { get; set; }
}

[Route("/bands/{BandId}/albums", "GET")]
public class BandAlbums : IReturn<AlbumListDto> { 
    public int BandId { get; set; }
}

and the actual services that handle the requests are like this:

public class BandAlbumService : Service {
    public object Get(BandAlbums request) {
         return(musicDb.GetAlbumsByBand(request.BandId));
    }
}


public class BandService : Service {

    private IMusicDatabase db;
    private BandAlbumService bandAlbumService;

    public BandService(IMusicDatabase musicDb, BandAlbumService bandAlbumService) {
        this.db = musicDb;
        this.bandAlbumService = bandAlbumService;
    }

    public object Get(Band request) {
        var result = musicDb.GetBand(request.BandId);

        if (request.Expand.Contains("albums")) {
            // OK, I already have the string /bands/123/albums
            // How do I translate this into a BandAlbums object
            // so I can just invoke BandAlbumService.Get(albums)

            var albumsRequest = Translate(result.Albums.Href);
            result.Albums = bandAlbumService.Get(albumsRequest);
    }
}

In the example above, say I have calculated the string /bands/123/albums as the HREF of Van Halen's album list.

How can I now use ServiceStack's built-in binding capabilities to translate the string /bands/123/albums into a BandAlbums 'request' object that I can pass directly into the BandAlbumService, get back a populated BandAlbumsDto object and include it in my response object?

(and yes, I'm aware this probably isn't an optimal approach in terms of minimising database hits. I'm going to worry about that later.)

¿Fue útil?

Solución

RestPath should be able to help you:

I think this should work:

var restPath = EndpointHostConfig.Instance.Metadata.Routes.RestPaths.Single(x => x.RequestType == typeof(AlbumRequest));
var request = restPath.CreateRequest("/bands/123/albums")
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top