Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

POST to ServiceStack Service and retrieve Location Header

Tags:

servicestack

I am trying to POST to my ServiceStack service and retrieve the Location header from the response of my CREATED entity. I am not sure whether using IReturn is valid but I am not sure how to access the Response headers from my client. Can someone help me understand how to interact with the HttpResult properly? There is a test case at the bottom of the code to demonstrate what I want to do. Here's the codz:

    public class ServiceStackSpike
{
    public class AppHost : AppHostHttpListenerBase
    {
        public AppHost() : base("TODOs Tests", typeof(Todo).Assembly) { }

        public override void Configure(Container container)
        {
            //noop
        }
    }


    [Route("/todos", "POST")]
    public class Todo:IReturn<HttpResult>
    {
        public long Id { get; set; }
        public string Content { get; set; }
        public int Order { get; set; }
        public bool Done { get; set; }
    }


    public class TodosService : Service
    {
        public object Post(Todo todo)
        {
            //do stuff here
            var result = new HttpResult(todo,HttpStatusCode.Created);
            result.Headers[HttpHeaders.Location] = "/tada";
            return result;
        }


    }


    public class NewApiTodosTests : IDisposable
    {
        const string BaseUri = "http://localhost:82/";

        AppHost appHost;

        public NewApiTodosTests()
        {
            appHost = new AppHost();
            appHost.Init();
            appHost.Start(BaseUri);                
        }


        [Fact]
        public void Run()
        {
            var restClient = new JsonServiceClient(BaseUri);


            var todo = restClient.Post(new Todo { Content = "New TODO", Order = 1 });
            Assert.Equal(todo.Headers[HttpHeaders.Location], "/tada"); //=>fail
        }

        public void Dispose()
        {
            appHost.Dispose();
            appHost = null;
        }
    }

}
like image 266
SonOfNun Avatar asked Nov 19 '12 19:11

SonOfNun


1 Answers

See the Customizing HTTP Responses ServiceStack wiki page for all the different ways of customizing the HTTP Response.

A HttpResult is just one way customize the HTTP Response. You generally want to include the Absolute Url if you're going to redirect it, e.g:

public object Post(Todo todo)
{
    var todo = ...;
    return new HttpResult(todo, HttpStatusCode.Created) { 
        Location = base.Request.AbsoluteUri.CombineWith("/tada")
    };
}

Note HTTP Clients will never see a HttpResult DTO. HttpResult is not a DTO itself, it's only purpose is to capture and modify the customized HTTP Response you want.

All ServiceStack Clients will return is the HTTP Body, which in this case is the Todo Response DTO. The Location is indeed added to the HTTP Response headers, and to see the entire HTTP Response returned you should use a HTTP sniffer like Fiddler, WireShark or Chrome's WebInspector.

If you want to access it using ServiceStack's HTTP Clients, you will need to add a Response Filter that gives you access to the HttpWebResponse, e.g:

restClient.ResponseFilter = httpRes => {
      Assert.Equal(httpRes.Headers[HttpHeaders.Location], "/tada"); 
 };

Todo todo = restClient.Post(new Todo { Content = "New TODO", Order = 1 });

Inspecting Response Headers using Web Request Extensions

Another lightweight alternative if you just want to inspect the HTTP Response is to use ServiceStack's Convenient WebRequest extension methods, e.g:

var url = "http://path/to/service";
var json = url.GetJsonFromUrl(httpRes => {
      Assert.Equal(httpRes.Headers[HttpHeaders.Location], "/tada"); 
});
like image 141
mythz Avatar answered Oct 23 '22 23:10

mythz