Skip to content

Commit

Permalink
[NoTicket] - Extended the HalClient to allow navigation of the links …
Browse files Browse the repository at this point in the history
…of embedded resources.
  • Loading branch information
eoin55 committed May 16, 2016
1 parent 19ca0f1 commit dd58ae5
Show file tree
Hide file tree
Showing 5 changed files with 297 additions and 1 deletion.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

![Build Status](https://ci.appveyor.com/api/projects/status/github/eoin55/HoneyBear.HalClient?branch=master&svg=true)
[![Coverage Status](https://coveralls.io/repos/eoin55/HoneyBear.HalClient/badge.svg?branch=master&service=github)](https://coveralls.io/github/eoin55/HoneyBear.HalClient?branch=master)
[![NuGet version](https://badge.fury.io/nu/honeybear.halclient.svg)](https://badge.fury.io/nu/honeybear.halclient)
[![NuGet Version](https://img.shields.io/nuget/v/HoneyBear.HalClient.svg)](https://www.nuget.org/packages/HoneyBear.HalClient/)

A lightweight fluent .NET client for navigating and consuming HAL APIs.

Expand Down
137 changes: 137 additions & 0 deletions Src/HoneyBear.HalClient.Unit.Tests/HalClientTestContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,17 @@ public void ArrangePagedResource()
ArrangeGet($"/v1/order?userRef={UserRef}", CreatePagedResourceJson());
}

public void ArrangePagedResourceWithEmbeddedArrayOfResources()
{
ArrangeGet($"/v1/order?userRef={UserRef}", CreatePagedResourceWithEmbeddedArrayOfResourcesJson());
}

public void ArrangePagedResourceWithLinkedArrayOfResources()
{
ArrangeGet($"/v1/order?userRef={UserRef}", CreatePagedResourceWithLinkedArrayOfResourcesJson());
ArrangeGet($"/v1/orderitem?orderRef={OrderRef}", CreatePagedResourceWithArrayOfResourcesJson());
}

public void ArrangeDefaultPagedResource()
{
ArrangeGet("/v1/order", CreateDefaultPagedResourceJson());
Expand Down Expand Up @@ -191,6 +202,17 @@ public void AssertThatEmbeddedPagedResourceIsPresent()
_order.AsSource().OfLikeness<Order>().ShouldEqual(resource);
}

public void AssertThatResourceArrayIsPresent()
{
var resource = _result.Items<OrderItem>().Data().First();
var expected =
_orderItem
.AsSource()
.OfLikeness<OrderItem>()
.WithCollectionInnerLikeness(d => d.SerialNumbers, s => s.SerialNumbers);
expected.ShouldEqual(resource);
}

public void AssertThatSingleEmbeddedResourceIsPresent()
{
var resource = _result.Items<OrderItem>().Data().First();
Expand Down Expand Up @@ -446,6 +468,121 @@ private object CreatePagedResourceJson() =>
}
};

private object CreatePagedResourceWithEmbeddedArrayOfResourcesJson() =>
new
{
_paged.PageNumber,
_paged.PageSize,
_paged.KnownPagesAvailable,
_paged.TotalItemsCount,
_links =
new
{
curies = _curies,
self = new {href = $"/v1/order?userRef={UserRef}"}
},
_embedded =
new
{
retail_order =
new[]
{
new
{
_order.OrderRef,
_order.OrderNumber,
_order.Status,
_order.Total,
_links =
new
{
curies = _curies,
self = new {href = $"/v1/order/{OrderRef}"}
},
_embedded =
new
{
retail_orderitem_query = CreatePagedResourceWithArrayOfResourcesJson()
}
}
}
}
};

private object CreatePagedResourceWithLinkedArrayOfResourcesJson() =>
new
{
_paged.PageNumber,
_paged.PageSize,
_paged.KnownPagesAvailable,
_paged.TotalItemsCount,
_links =
new
{
curies = _curies,
self = new {href = $"/v1/order?userRef={UserRef}"}
},
_embedded =
new
{
retail_order =
new[]
{
new
{
_order.OrderRef,
_order.OrderNumber,
_order.Status,
_order.Total,
_links =
new
{
curies = _curies,
self = new {href = $"/v1/order/{OrderRef}"},
retail_orderitem_query = new {href = $"/v1/orderitem?orderRef={OrderRef}"}
}
}
}
}
};

private object CreatePagedResourceWithArrayOfResourcesJson() =>
new
{
_paged.PageNumber,
_paged.PageSize,
_paged.KnownPagesAvailable,
_paged.TotalItemsCount,
_links =
new
{
curies = _curies,
self = new {href = $"/v1/orderitem?orderRef={OrderRef}"}
},
_embedded =
new
{
retail_orderitem =
new[]
{
new
{
_orderItem.OrderItemRef,
_orderItem.Status,
_orderItem.Total,
_orderItem.Quantity,
_orderItem.SerialNumbers,
_links =
new
{
curies = _curies,
self = new {href = $"/v1/orderitem/{_orderItem.OrderItemRef}"}
}
}
}
}
};

private object CreateDefaultPagedResourceJson() =>
new
{
Expand Down
60 changes: 60 additions & 0 deletions Src/HoneyBear.HalClient.Unit.Tests/HalClientUnitTests.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
using System;
using System.Linq;
using System.Net.Http;
using HoneyBear.HalClient.Models;
using HoneyBear.HalClient.Unit.Tests.ProxyResources;
using NUnit.Framework;

namespace HoneyBear.HalClient.Unit.Tests
Expand Down Expand Up @@ -92,6 +94,64 @@ public void Navigate_to_paged_embedded_resource()
_context.AssertThatEmbeddedPagedResourceIsPresent();
}

[Test]
public void Navigate_to_paged_embedded_resource_and_navigate_to_embedded_resource_array()
{
_context
.ArrangeHomeResource()
.ArrangePagedResourceWithEmbeddedArrayOfResources();

Func<IHalClient, IHalClient> act =
sut =>
{
var order =
sut
.Root(HalClientTestContext.RootUri)
.Get("order-queryby-user", new {userRef = HalClientTestContext.UserRef}, HalClientTestContext.Curie)
.Get("order", HalClientTestContext.Curie)
.Items<Order>()
.First();

sut
.Get(order, "orderitem-query", HalClientTestContext.Curie)
.Get("orderitem", HalClientTestContext.Curie);

return sut;
};
_context.Act(act);

_context.AssertThatResourceArrayIsPresent();
}

[Test]
public void Navigate_to_paged_embedded_resource_and_navigate_to_linked_resource_array()
{
_context
.ArrangeHomeResource()
.ArrangePagedResourceWithLinkedArrayOfResources();

Func<IHalClient, IHalClient> act =
sut =>
{
var order =
sut
.Root(HalClientTestContext.RootUri)
.Get("order-queryby-user", new {userRef = HalClientTestContext.UserRef}, HalClientTestContext.Curie)
.Get("order", HalClientTestContext.Curie)
.Items<Order>()
.First();

sut
.Get(order, "orderitem-query", HalClientTestContext.Curie)
.Get("orderitem", HalClientTestContext.Curie);

return sut;
};
_context.Act(act);

_context.AssertThatResourceArrayIsPresent();
}

[Test]
public void Create_resource()
{
Expand Down
57 changes: 57 additions & 0 deletions Src/HoneyBear.HalClient/HalClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,63 @@ public IHalClient Get(string rel, object parameters, string curie)
return BuildAndExecute(relationship, parameters, uri => _client.GetAsync(uri));
}

/// <summary>
/// Navigates the given link relation and stores the the returned resource(s).
/// </summary>
/// <param name="resource">The current <see cref="IResource"/>.</param>
/// <param name="rel">The link relation to follow.</param>
/// <returns>The updated <see cref="IHalClient"/>.</returns>
/// <exception cref="FailedToResolveRelationship" />
public IHalClient Get(IResource resource, string rel) => Get(resource, rel, null, null);

/// <summary>
/// Navigates the given link relation and stores the the returned resource(s).
/// </summary>
/// <param name="resource">The current <see cref="IResource"/>.</param>
/// <param name="rel">The link relation to follow.</param>
/// <param name="curie">The curie of the link relation.</param>
/// <returns>The updated <see cref="IHalClient"/>.</returns>
/// <exception cref="FailedToResolveRelationship" />
public IHalClient Get(IResource resource, string rel, string curie) => Get(resource, rel, null, curie);

/// <summary>
/// Navigates the given templated link relation and stores the the returned resource(s).
/// </summary>
/// <param name="resource">The current <see cref="IResource"/>.</param>
/// <param name="rel">The templated link relation to follow.</param>
/// <param name="parameters">An anonymous object containing the template parameters to apply.</param>
/// <returns>The updated <see cref="IHalClient"/>.</returns>
/// <exception cref="FailedToResolveRelationship" />
/// <exception cref="TemplateParametersAreRequired" />
public IHalClient Get(IResource resource, string rel, object parameters) => Get(resource, rel, parameters, null);

/// <summary>
/// Navigates the given templated link relation and stores the the returned resource(s).
/// </summary>
/// <param name="resource">The current <see cref="IResource"/>.</param>
/// <param name="rel">The templated link relation to follow.</param>
/// <param name="parameters">An anonymous object containing the template parameters to apply.</param>
/// <param name="curie">The curie of the link relation.</param>
/// <returns>The updated <see cref="IHalClient"/>.</returns>
/// <exception cref="FailedToResolveRelationship" />
/// <exception cref="TemplateParametersAreRequired" />
public IHalClient Get(IResource resource, string rel, object parameters, string curie)
{
var relationship = Relationship(rel, curie);

if (resource.Embedded.Any(e => e.Rel == relationship))
{
_current = resource.Embedded.Where(e => e.Rel == relationship);
return this;
}

var link = resource.Links.FirstOrDefault(l => l.Rel == relationship);
if (link == null)
throw new FailedToResolveRelationship(relationship);

return Execute(Construct(link, parameters), uri => _client.GetAsync(uri));
}

/// <summary>
/// Makes a HTTP POST request to the given link relation on the most recently navigated resource.
/// </summary>
Expand Down
42 changes: 42 additions & 0 deletions Src/HoneyBear.HalClient/IHalClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,48 @@ public interface IHalClient
/// <exception cref="TemplateParametersAreRequired" />
IHalClient Get(string rel, object parameters, string curie);

/// <summary>
/// Navigates the given link relation and stores the the returned resource(s).
/// </summary>
/// <param name="resource">The current <see cref="IResource"/>.</param>
/// <param name="rel">The link relation to follow.</param>
/// <returns>The updated <see cref="IHalClient"/>.</returns>
/// <exception cref="FailedToResolveRelationship" />
IHalClient Get(IResource resource, string rel);

/// <summary>
/// Navigates the given link relation and stores the the returned resource(s).
/// </summary>
/// <param name="resource">The current <see cref="IResource"/>.</param>
/// <param name="rel">The link relation to follow.</param>
/// <param name="curie">The curie of the link relation.</param>
/// <returns>The updated <see cref="IHalClient"/>.</returns>
/// <exception cref="FailedToResolveRelationship" />
IHalClient Get(IResource resource, string rel, string curie);

/// <summary>
/// Navigates the given templated link relation and stores the the returned resource(s).
/// </summary>
/// <param name="resource">The current <see cref="IResource"/>.</param>
/// <param name="rel">The templated link relation to follow.</param>
/// <param name="parameters">An anonymous object containing the template parameters to apply.</param>
/// <returns>The updated <see cref="IHalClient"/>.</returns>
/// <exception cref="FailedToResolveRelationship" />
/// <exception cref="TemplateParametersAreRequired" />
IHalClient Get(IResource resource, string rel, object parameters);

/// <summary>
/// Navigates the given templated link relation and stores the the returned resource(s).
/// </summary>
/// <param name="resource">The current <see cref="IResource"/>.</param>
/// <param name="rel">The templated link relation to follow.</param>
/// <param name="parameters">An anonymous object containing the template parameters to apply.</param>
/// <param name="curie">The curie of the link relation.</param>
/// <returns>The updated <see cref="IHalClient"/>.</returns>
/// <exception cref="FailedToResolveRelationship" />
/// <exception cref="TemplateParametersAreRequired" />
IHalClient Get(IResource resource, string rel, object parameters, string curie);

/// <summary>
/// Makes a HTTP POST request to the given link relation on the most recently navigated resource.
/// </summary>
Expand Down

0 comments on commit dd58ae5

Please sign in to comment.