Skip to content

Commit

Permalink
Add new IHalDocumentMapper interface with additional context. (#7)
Browse files Browse the repository at this point in the history
* Add new IHalDocumentMapper interface with additional context.
* Add specs for registering IHalDocumentMapper implementations
* Add some specs for OpenApi host initialisation
* Fixed further Roslyn analyzer recommendations.
  • Loading branch information
jongeorge1 authored Nov 15, 2019
1 parent 57c1edb commit 8f15a1e
Show file tree
Hide file tree
Showing 20 changed files with 658 additions and 31 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ private void AddProblemDetails()
this.AddProblemDetailsExtension("Policy Name", this.PolicyName);
}

if (this.Requests != null && this.Requests.Length > 0)
if (this.Requests?.Length > 0)
{
this.AddProblemDetailsExtension("Requests", string.Join(Environment.NewLine, this.Requests.Select(r => $"{r.OperationId}: {r.Method} {r.Path}")));
}
Expand Down
2 changes: 1 addition & 1 deletion Solutions/Menes.Abstractions/Menes/Hal/HalDocument.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public HalDocument(IJsonSerializerSettingsProvider serializerSettingsProvider)
/// <summary>
/// Gets the serializer settings for the HAL document.
/// </summary>
public JsonSerializerSettings SerializerSettings { get; private set; }
public JsonSerializerSettings SerializerSettings { get; }

/// <summary>
/// Gets the properites for the HalDocument.
Expand Down
16 changes: 16 additions & 0 deletions Solutions/Menes.Abstractions/Menes/Hal/IHalDocumentMapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,20 @@ public interface IHalDocumentMapper<T> : IHalDocumentMapper
/// <returns>The <see cref="HalDocument"/> for the resource.</returns>
HalDocument Map(T resource);
}

/// <summary>
/// Implemented by types which can map a resource to a HAL document and require additional context for the mapping.
/// </summary>
/// <typeparam name="TResource">The type of the resource to map.</typeparam>
/// <typeparam name="TContext">The type of the object that provides additional context to the mapping.</typeparam>
public interface IHalDocumentMapper<TResource, TContext> : IHalDocumentMapper
{
/// <summary>
/// Map a resource to a HAL document.
/// </summary>
/// <param name="resource">The resource to map.</param>
/// <param name="context">The additional context information.</param>
/// <returns>The <see cref="HalDocument"/> for the resource.</returns>
HalDocument Map(TResource resource, TContext context);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,8 @@ public static async Task RemoveForbiddenLinksAsync(this IOpenApiAccessChecker th
AddHalDocumentLinksToMap(
target,
linkMap,
!options.HasFlag(HalDocumentLinkRemovalOptions.NonRecursive),
options.HasFlag(HalDocumentLinkRemovalOptions.Unsafe));
(options & HalDocumentLinkRemovalOptions.NonRecursive) == 0,
(options & HalDocumentLinkRemovalOptions.Unsafe) != 0);

// Build a second map of operation descriptors (needed to invoke the access policy check) to our OpenApiWebLinks.
var operationDescriptorMap = linkMap
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -519,7 +519,8 @@ private object ConvertValue(OpenApiSchema schema, string value)
this.logger.LogError(
"Failed to convert value with [{schema}]",
schema.GetLoggingInformation());
throw new NotImplementedException();

throw new OpenApiServiceMismatchException($"Unable to convert value to match [{schema.GetLoggingInformation()}]");
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,8 @@ private string ConvertValue(OpenApiSchema schema, object value)
this.logger.LogError(
"Failed to convert value with [{schema}]",
schema.GetLoggingInformation());
throw new NotImplementedException();

throw new OpenApiServiceMismatchException($"Failed to convert value to match [{schema.GetLoggingInformation()}]");
}

private void BuildHeaders(HttpResponse httpResponse, OpenApiResponse response)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ public static IServiceCollection AddOpenApiHosting<TRequest, TResponse>(this ISe
/// Add an <see cref="IHalDocumentMapper"/> to the service collection.
/// </summary>
/// <typeparam name="TResource">The type of the resource mapped by the HAL document mapper.</typeparam>
/// <typeparam name="TMapper">The type fo the mapper.</typeparam>
/// <typeparam name="TMapper">The type of the mapper.</typeparam>
/// <param name="services">The service collection to which to add the mapper.</param>
/// <returns>The service collection, configured with the HAL document mapper.</returns>
public static IServiceCollection AddHalDocumentMapper<TResource, TMapper>(this IServiceCollection services)
Expand All @@ -165,6 +165,23 @@ public static IServiceCollection AddHalDocumentMapper<TResource, TMapper>(this I
return services;
}

/// <summary>
/// Add an <see cref="IHalDocumentMapper"/> to the service collection.
/// </summary>
/// <typeparam name="TResource">The type of the resource mapped by the HAL document mapper.</typeparam>
/// <typeparam name="TContext">The type of the additional context required by the HAL document mapper.</typeparam>
/// <typeparam name="TMapper">The type of the mapper.</typeparam>
/// <param name="services">The service collection to which to add the mapper.</param>
/// <returns>The service collection, configured with the HAL document mapper.</returns>
public static IServiceCollection AddHalDocumentMapper<TResource, TContext, TMapper>(this IServiceCollection services)
where TMapper : class, IHalDocumentMapper<TResource, TContext>
{
services.AddSingleton<TMapper>();
services.AddSingleton<IHalDocumentMapper>(s => s.GetRequiredService<TMapper>());
services.AddSingleton<IHalDocumentMapper<TResource, TContext>>(s => s.GetRequiredService<TMapper>());
return services;
}

/// <summary>
/// Adds the /swagger endpoint to your host.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,7 @@ public void Configure(IWebJobsBuilder builder)
services.AddHalDocumentMapper<PetResource, PetResourceMapper>();
services.AddHalDocumentMapper<PetListResource, PetListResourceMapper>();

services.AddOpenApiHttpRequestHosting<SimpleOpenApiContext>(hostConfig =>
{
LoadDocuments(hostConfig);
});
_ = services.AddOpenApiHttpRequestHosting<SimpleOpenApiContext>(LoadDocuments);

// We can add all the services here
// We will only actually *provide* services that are in the YAML file(s) we load below
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
Feature: OpenApi Hosting Initialisation
In order to use Menes in my application
As a developer
I want to be able to add Menes services and related components to my service collection

Background:
Given I have created a service collection to register my services against

Scenario: Adding AspNetCore OpenApi hosting adds the IOpenApiHost for HttpRequest and IActionResult
When I add AspNetCore OpenApi hosting to the service collection
And I build the service provider from the service collection
Then a service is available as a Singleton for type IOpenApiHost{HttpRequest, IActionResult}

Scenario: Adding OpenApi hosting enables auditing to console by default
Given I have added AspNetCore OpenApi hosting to the service collection
And I have built the service provider from the service collection
Then an audit log builder service is available for auditing operations which return OpenApiResults
And an audit log builder service is available for auditing operations which return a POCO
And an audit log sink service is available for console logging
And auditing is enabled

Scenario Outline: OpenApi host initialisation maps standard Menes exception types to their corresponding HTTP status codes
Given I have added AspNetCore OpenApi hosting to the service collection
And I have built the service provider from the service collection
When I request an instance of the OpenApi host
Then the exception of type '<Exception Type>' is mapped to response code '<Mapped Response Code>'

Examples:
| Exception Type | Mapped Response Code |
| Menes.Exceptions.OpenApiBadRequestException, Menes.Abstractions | 400 |
| Menes.Exceptions.OpenApiUnauthorizedException, Menes.Abstractions | 401 |
| Menes.Exceptions.OpenApiForbiddenException, Menes.Abstractions | 403 |
| Menes.Exceptions.OpenApiNotFoundException, Menes.Abstractions | 404 |

Scenario: OpenApi host initialisation adds link maps from registered IHalDocumentMapper types
Given I have added AspNetCore OpenApi hosting to the service collection
And I have registered a HalDocumentMapper for a resource type to the service collection
And I have registered a HalDocumentMapper for a resource and context type to the service collection
And I have built the service provider from the service collection
When I request an instance of the OpenApi host
Then the HalDocumentMapper for resource type has configured its links
And the HalDocumentMapper for resource and context types has configured its links

Scenario: Registering HAL document mappers with resource type parameters adds them to the container with the concrete type, the IHalDocumentMapper interface and the generic IHalDocumentMapper interface
When I register a HalDocumentMapper for a resource type to the service collection
And I build the service provider from the service collection
Then it should be available as a Singleton with the service type matching the concrete type of the mapper
And It should be available as a Singleton with a service type of IHalDocumentMapper
And it should be available as a Singleton with a service type of IHalDocumentMapper{TResource}

Scenario: Registering HAL document mappers with resource and context type parameters adds them to the container with the concrete type, the IHalDocumentMapper interface and the generic IHalDocumentMapper interface
When I register a HalDocumentMapper for a resource and context type to the service collection
And I build the service provider from the service collection
Then it should be available as a Singleton with the service type matching the concrete type of the mapper with context
And It should be available as a Singleton with a service type of IHalDocumentMapper
And it should be available as a Singleton with a service type of IHalDocumentMapper{TResource, TContext}
Loading

0 comments on commit 8f15a1e

Please sign in to comment.