wis3guy / HalClient.Net

A library that simplifies interaction with API's that respond with the "application\hal+json" media type.
Microsoft Public License
19 stars 21 forks source link

App stops working with 1.2.5822 #9

Closed gjorchard closed 8 years ago

gjorchard commented 8 years ago

Yesterday I tried moving from 1.2.5784 to 1.2.5822 and my application stopped working with a response from the webservice not being parsed correctly.

Below is response from the webservice. In the response from HalClient the href associated with v1:eventSubscriptionSets is null. I believe the hrefs with the other "v1" fields are also null.

For now I have gone back to 1.2.5784.

{ "_links": { "curies": { "href": "/api/v1/rels/{rel}", "name": "v1", "templated": true }, "self": { "href": "api/v1/" }, "v1:calls": { "href": "/api/v1/calls" }, "v1:eventSubscriptionSets": { "href": "/api/v1/subscriptions/ws/{webSocketId}/subscriptionsets", "templated": true }, "v1:presenceStatusExtension": { "href": "/api/v1/presencestatus/tenants/{tenant.tenantId}/extensions/{extension}", "templated": true }, "v1:presenceStatusSubscriptionSet": { "href": "/api/v1/presencestatus/ws/{webSocketId}/subscriptionsets/{subscriptionSetId}", "templated": true }, "v1:tenants": { "href": "/api/v1/tenants" } } }

wis3guy commented 8 years ago

This is actually not a bug, but a conscious design decision. Admittedly this caused an undocumented breaking change so i totally understand your conclusion.

The reason the Href property is set to null, is that the particular link is templated. This means a client cannot follow the link without first resolving the template first. Blindly following templated uri's could result in useless http requests being made to templated url's (resulting in 400 responses).

To counter this i introduced the ILinkObject.Template property, which will be filled by the parser for templated links (only). That way, a http client would throw an ArgumentNull exception in case the nulled Href was blindly followed. At the same time, i introduced the ILinkObject.ResolveTemplated() factory method, which allows you to create a non-templated link from a templated instance.

You likely already have some kind of guarding code in place which makes sure that any templated link is resolved before you attempt to follow it. This code should be slightly refactored into something like this:

using (var client = factory.CreateClient())
{
    var resource = await client.GetAsync(new Uri("http://example.com/api/v1/"));
    var eventSubscriptionSetsLink = resource.Links["v1:eventSubscriptionSets"].Single();

    // in case the link is *not* templated, the eventSubscriptionSetsLink.Href property *is* set.
    // in case the link *is* templated, the Href property is *not* set but the Template property *is* set.

    eventSubscriptionSetsLink = eventSubscriptionSetsLink.Templated
        ? templatedLink.ResolveTemplated(x => x.AddParameter("webSocketId", "1234567890").Resolve())
        : eventSubscriptionSetsLink;

    // follow the resolved link and process the response ...
}

See also: https://github.com/wis3guy/HalClient.Net#working-with-ilinkobject-instances