Skip to content

Commit

Permalink
Merge branch 'master' into personal/poadhikari/negative_tests_added
Browse files Browse the repository at this point in the history
  • Loading branch information
Pooja Adhikari committed Dec 13, 2018
2 parents b163532 + 090e818 commit aa7443e
Show file tree
Hide file tree
Showing 44 changed files with 615 additions and 1,152 deletions.
16 changes: 16 additions & 0 deletions Directory.Build.props
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<Project>
<PropertyGroup>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<WarningsAsErrors />
<DebugType>Full</DebugType>
<LangVersion>7.3</LangVersion>
<HighEntropyVA>true</HighEntropyVA>
<EnableSourceLink Condition="$([MSBuild]::IsOSPlatform('osx'))">false</EnableSourceLink>
<EnableSourceControlManagerQueries>$(EnableSourceLink)</EnableSourceControlManagerQueries>
</PropertyGroup>
<PropertyGroup Condition=" '$(EnableSourceLink)' == 'true' ">
<PublishRepositoryUrl>true</PublishRepositoryUrl>
<EmbedUntrackedSources>true</EmbedUntrackedSources>
<AllowedOutputExtensionsInPackageBuildOutputFolder>$(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb</AllowedOutputExtensionsInPackageBuildOutputFolder>
</PropertyGroup>
</Project>
8 changes: 7 additions & 1 deletion docs/Roadmap.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,14 @@ Extensions are not yet supported. Documents with extensions will get stored and
## Profiling
Profiling is not supported yet, but the project aims to support storing profiles and validating against stored profiles.

## Batch/Transaction
Currently there is no support for batch/transaction (https://www.hl7.org/fhir/http.html#transaction). This is something we are investigating and expect to support in future releases.

## Conditional operations
Conditional operations (update, delete, create) are currently not supported. This partially ties to supporting transactions. Our roadmap includes support for conditional operations.

## FHIR Versions
The FHIR Server currently supports FHIR 3.0.1 but the intention is to support multiple versions in the future.

## Azure Data Factory Connector
Users of the Microsoft FHIR Server will want to use analytics and machine learning tools in Azure to gain insights from the data stored in the FHIR Server. [Azure Data Factory](https://azure.microsoft.com/en-us/services/data-factory/) is the natural choice for facilitating the export and transformation of data for downstream analytics. See an [example of using Data Factory with the Microsoft FHIR Server](https://github.com/hansenms/FhirDemo). This example was based on accessing the data in the FHIR Server directly through the FHIR API. One of the Microsoft FHIR Server for Azure project's goals is to provide a more direct and efficient integration with Data Factory. Specifically, the goal is to provide a first class connector to allow the FHIR Server to serve as source and sink for Data Factory.
Users of the Microsoft FHIR Server will want to use analytics and machine learning tools in Azure to gain insights from the data stored in the FHIR Server. [Azure Data Factory](https://azure.microsoft.com/en-us/services/data-factory/) is the natural choice for facilitating the export and transformation of data for downstream analytics. See an [example of using Data Factory with the Microsoft FHIR Server](https://github.com/hansenms/FhirDemo). This example was based on accessing the data in the FHIR Server directly through the FHIR API. One of the Microsoft FHIR Server for Azure project's goals is to provide a more direct and efficient integration with Data Factory. Specifically, the goal is to provide a first class connector to allow the FHIR Server to serve as source and sink for Data Factory.
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,6 @@
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<CodeAnalysisRuleSet>..\..\CustomAnalysisRules.ruleset</CodeAnalysisRuleSet>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<WarningsAsErrors />
<DebugType>Full</DebugType>
<LangVersion>latest</LangVersion>
<HighEntropyVA>true</HighEntropyVA>
<PublishRepositoryUrl>true</PublishRepositoryUrl>
<EmbedUntrackedSources>true</EmbedUntrackedSources>
<AllowedOutputExtensionsInPackageBuildOutputFolder>$(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb</AllowedOutputExtensionsInPackageBuildOutputFolder>
</PropertyGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
using Hl7.Fhir.Model;
using Microsoft.Health.Fhir.Api.Features.ActionResults;
using Microsoft.Health.Fhir.Api.Features.Headers;
using Microsoft.Health.Fhir.Core.Features.Persistence;
using Microsoft.Health.Fhir.Core.Features.Routing;
using Microsoft.Net.Http.Headers;
using NSubstitute;
Expand Down Expand Up @@ -91,9 +92,9 @@ public void WhenAddingSameHeaderTwice_ThenOnlyOneHeaderIsPresent()
[Fact]
public void WhenAddingStringEtag_ThenStringETagIsReturned()
{
var fhirResult = FhirResult.Create(_mockResource).SetETagHeader("etag");
var fhirResult = FhirResult.Create(_mockResource).SetETagHeader(WeakETag.FromVersionId("etag"));

Assert.Equal("etag", fhirResult.Headers[HeaderNames.ETag]);
Assert.Equal("W/\"etag\"", fhirResult.Headers[HeaderNames.ETag]);
}
}
}
63 changes: 29 additions & 34 deletions src/Microsoft.Health.Fhir.Api/Controllers/FhirController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
using Hl7.Fhir.Model;
using MediatR;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
Expand All @@ -24,15 +23,12 @@
using Microsoft.Health.Fhir.Api.Features.Headers;
using Microsoft.Health.Fhir.Api.Features.Routing;
using Microsoft.Health.Fhir.Api.Features.Security;
using Microsoft.Health.Fhir.Core.Extensions;
using Microsoft.Health.Fhir.Core.Features;
using Microsoft.Health.Fhir.Core.Features.Context;
using Microsoft.Health.Fhir.Core.Features.Persistence;
using Microsoft.Health.Fhir.Core.Features.Routing;
using Microsoft.Health.Fhir.Core.Messages.Create;
using Microsoft.Health.Fhir.Core.Messages.Delete;
using Microsoft.Health.Fhir.Core.Messages.Get;
using Microsoft.Health.Fhir.Core.Messages.Search;
using Microsoft.Health.Fhir.Core.Messages.Upsert;
using Microsoft.Health.Fhir.Core.Models;
using Microsoft.Health.Fhir.ValueSets;
using Microsoft.Net.Http.Headers;
Expand Down Expand Up @@ -149,8 +145,9 @@ public IActionResult CustomError(int? statusCode = null)
[Authorize(PolicyNames.WritePolicy)]
public async Task<IActionResult> Create([FromBody] Resource resource)
{
var response = await _mediator.Send<UpsertResourceResponse>(new CreateResourceRequest(resource), HttpContext.RequestAborted);
return FhirResult.Create(response.Outcome.Resource, HttpStatusCode.Created)
Resource response = await _mediator.CreateResourceAsync(resource, HttpContext.RequestAborted);

return FhirResult.Create(response, HttpStatusCode.Created)
.SetETagHeader()
.SetLastModifiedHeader()
.SetLocationHeader(_urlResolver);
Expand All @@ -175,21 +172,22 @@ public async Task<IActionResult> Update([FromBody] Resource resource)
weakETag = WeakETag.FromWeakETag(suppliedWeakETag);
}

var response = await _mediator.Send<UpsertResourceResponse>(new UpsertResourceRequest(resource, weakETag), HttpContext.RequestAborted);
switch (response.Outcome.Outcome)
SaveOutcome response = await _mediator.UpsertResourceAsync(resource, weakETag, HttpContext.RequestAborted);

switch (response.Outcome)
{
case SaveOutcomeType.Created:
return FhirResult.Create(response.Outcome.Resource, HttpStatusCode.Created)
return FhirResult.Create(response.Resource, HttpStatusCode.Created)
.SetETagHeader()
.SetLastModifiedHeader()
.SetLocationHeader(_urlResolver);
case SaveOutcomeType.Updated:
return FhirResult.Create(response.Outcome.Resource, HttpStatusCode.OK)
return FhirResult.Create(response.Resource, HttpStatusCode.OK)
.SetETagHeader()
.SetLastModifiedHeader();
}

return FhirResult.Create(response.Outcome.Resource, HttpStatusCode.BadRequest);
return FhirResult.Create(response.Resource, HttpStatusCode.BadRequest);
}

/// <summary>
Expand All @@ -203,8 +201,9 @@ public async Task<IActionResult> Update([FromBody] Resource resource)
[Authorize(PolicyNames.ReadPolicy)]
public async Task<IActionResult> Read(string type, string id)
{
var response = await _mediator.Send(new GetResourceRequest(type, id), HttpContext.RequestAborted);
return FhirResult.Create(response.Resource)
Resource response = await _mediator.GetResourceAsync(new ResourceKey(type, id), HttpContext.RequestAborted);

return FhirResult.Create(response)
.SetETagHeader()
.SetLastModifiedHeader();
}
Expand All @@ -226,9 +225,9 @@ public async Task<IActionResult> SystemHistory(
[FromQuery(Name = KnownQueryParameterNames.Count)] int? count,
string ct)
{
var response = await _mediator.Send(new SearchResourceHistoryRequest(since, at, count, ct), HttpContext.RequestAborted);
Bundle response = await _mediator.SearchResourceHistoryAsync(since, at, count, ct, HttpContext.RequestAborted);

return FhirResult.Create(response.Bundle);
return FhirResult.Create(response);
}

/// <summary>
Expand All @@ -250,9 +249,9 @@ public async Task<IActionResult> TypeHistory(
[FromQuery(Name = KnownQueryParameterNames.Count)] int? count,
string ct)
{
var response = await _mediator.Send(new SearchResourceHistoryRequest(type, since, at, count, ct), HttpContext.RequestAborted);
Bundle response = await _mediator.SearchResourceHistoryAsync(type, since, at, count, ct, HttpContext.RequestAborted);

return FhirResult.Create(response.Bundle);
return FhirResult.Create(response);
}

/// <summary>
Expand All @@ -276,9 +275,9 @@ public async Task<IActionResult> History(
[FromQuery(Name = KnownQueryParameterNames.Count)] int? count,
string ct)
{
var response = await _mediator.Send(new SearchResourceHistoryRequest(type, id, since, at, count, ct), HttpContext.RequestAborted);
Bundle response = await _mediator.SearchResourceHistoryAsync(type, id, since, at, count, ct, HttpContext.RequestAborted);

return FhirResult.Create(response.Bundle);
return FhirResult.Create(response);
}

/// <summary>
Expand All @@ -293,8 +292,9 @@ public async Task<IActionResult> History(
[Authorize(PolicyNames.ReadPolicy)]
public async Task<IActionResult> VRead(string type, string id, string vid)
{
var response = await _mediator.Send(new GetResourceRequest(type, id, vid), HttpContext.RequestAborted);
return FhirResult.Create(response.Resource, HttpStatusCode.OK)
var response = await _mediator.GetResourceAsync(new ResourceKey(type, id, vid), HttpContext.RequestAborted);

return FhirResult.Create(response, HttpStatusCode.OK)
.SetETagHeader()
.SetLastModifiedHeader();
}
Expand Down Expand Up @@ -322,7 +322,7 @@ public async Task<IActionResult> Delete(string type, string id, [FromQuery]bool
return Forbid();
}

DeleteResourceResponse response = await _mediator.Send(new DeleteResourceRequest(type, id, hardDelete), HttpContext.RequestAborted);
var response = await _mediator.DeleteResourceAsync(new ResourceKey(type, id), hardDelete, HttpContext.RequestAborted);

return FhirResult.NoContent().SetETagHeader(response.WeakETag);
}
Expand Down Expand Up @@ -425,16 +425,16 @@ public async Task<IActionResult> SearchCompartmentByResourceType(string compartm

private async Task<IActionResult> PerformCompartmentSearch(string compartmentType, string compartmentId, string resourceType, IReadOnlyList<Tuple<string, string>> queries)
{
var response = await _mediator.Send(new CompartmentResourceRequest(compartmentType, compartmentId, resourceType, queries), HttpContext.RequestAborted);
Bundle response = await _mediator.SearchResourceCompartmentAsync(compartmentType, compartmentId, resourceType, queries, HttpContext.RequestAborted);

return FhirResult.Create(response.Bundle);
return FhirResult.Create(response);
}

private async Task<IActionResult> PerformSearch(string type, IReadOnlyList<Tuple<string, string>> queries)
{
var response = await _mediator.Send(new SearchResourceRequest(type, queries), HttpContext.RequestAborted);
Bundle response = await _mediator.SearchResourceAsync(type, queries, HttpContext.RequestAborted);

return FhirResult.Create(response.Bundle);
return FhirResult.Create(response);
}

/// <summary>
Expand All @@ -447,14 +447,9 @@ private async Task<IActionResult> PerformSearch(string type, IReadOnlyList<Tuple
[Route(KnownRoutes.Metadata, Name = RouteNames.Metadata)]
public async Task<IActionResult> Metadata(bool system = false)
{
if (system)
{
var sysResponse = await _mediator.Send(new GetSystemCapabilitiesRequest(), HttpContext.RequestAborted);
return FhirResult.Create(sysResponse.CapabilityStatement);
}
CapabilityStatement response = await _mediator.GetCapabilitiesAsync(system, HttpContext.RequestAborted);

var response = await _mediator.Send(new GetCapabilitiesRequest(), HttpContext.RequestAborted);
return FhirResult.Create(response.CapabilityStatement);
return FhirResult.Create(response);
}
}
}
10 changes: 0 additions & 10 deletions src/Microsoft.Health.Fhir.Api/Features/Headers/FhirHeaders.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,16 +50,6 @@ public static FhirResult SetETagHeader(this FhirResult fhirResult, WeakETag weak
return fhirResult;
}

public static FhirResult SetETagHeader(this FhirResult fhirResult, string eTag)
{
if (!string.IsNullOrWhiteSpace(eTag))
{
fhirResult.Headers.Add(HeaderNames.ETag, eTag);
}

return fhirResult;
}

public static FhirResult SetLastModifiedHeader(this FhirResult fhirResult)
{
var resource = fhirResult.Resource;
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,7 @@
<PropertyGroup>
<TargetFramework>netcoreapp2.1</TargetFramework>
<CodeAnalysisRuleSet>..\..\CustomAnalysisRules.ruleset</CodeAnalysisRuleSet>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<WarningsAsErrors />
<DocumentationFile>bin\$(Configuration)\$(TargetFramework)\Microsoft.Health.Fhir.Api.xml</DocumentationFile>
<!-- Due to the bug in VS, The DebugType needs to be set to Full for CodeCoverage to work property. Remove after the fix is deployed.-->
<DebugType>Full</DebugType>
<LangVersion>latest</LangVersion>
<HighEntropyVA>true</HighEntropyVA>
<PublishRepositoryUrl>true</PublishRepositoryUrl>
<EmbedUntrackedSources>true</EmbedUntrackedSources>
<AllowedOutputExtensionsInPackageBuildOutputFolder>$(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb</AllowedOutputExtensionsInPackageBuildOutputFolder>
</PropertyGroup>

<ItemGroup>
Expand Down
18 changes: 16 additions & 2 deletions src/Microsoft.Health.Fhir.Api/Modules/MediationModule.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@
// -------------------------------------------------------------------------------------------------

using System;
using System.Linq;
using EnsureThat;
using MediatR;
using MediatR.Pipeline;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Health.Extensions.DependencyInjection;
using Microsoft.Health.Fhir.Core.Features.Conformance;
using Microsoft.Health.Fhir.Core.Features.Persistence;

namespace Microsoft.Health.Fhir.Api.Modules
Expand All @@ -23,17 +25,29 @@ public void Load(IServiceCollection services)
{
EnsureArg.IsNotNull(services, nameof(services));

var coreAssembly = typeof(IFhirRepository).Assembly;
var coreAssembly = typeof(IDataStore).Assembly;

services.AddMediatR(GetType().Assembly, coreAssembly);
services.AddTransient(typeof(IPipelineBehavior<,>), typeof(RequestPreProcessorBehavior<,>));
services.AddTransient(typeof(IPipelineBehavior<,>), typeof(RequestPostProcessorBehavior<,>));

Predicate<Type> isPipelineBehavior = y => y.IsGenericType && y.GetGenericTypeDefinition() == typeof(IPipelineBehavior<,>);

services.TypesInSameAssemblyAs<IFhirRepository>()
services.TypesInSameAssemblyAs<IDataStore>()
.Transient()
.AsImplementedInterfaces(isPipelineBehavior);

// Allows handlers to provide capabilities
var openRequestInterfaces = new Type[]
{
typeof(IRequestHandler<,>),
typeof(INotificationHandler<>),
};

services.TypesInSameAssemblyAs<IDataStore>()
.Where(y => y.Type.IsGenericType && openRequestInterfaces.Contains(y.Type.GetGenericTypeDefinition()))
.Transient()
.AsImplementedInterfaces(x => x == typeof(IProvideCapability));
}
}
}
1 change: 0 additions & 1 deletion src/Microsoft.Health.Fhir.Api/Modules/PersistenceModule.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ public void Load(IServiceCollection services)
{
EnsureArg.IsNotNull(services, nameof(services));

services.AddScoped<IFhirRepository, FhirRepository>();
services.AddSingleton<IRawResourceFactory, RawResourceFactory>();
services.AddSingleton<IResourceWrapperFactory, ResourceWrapperFactory>();
services.AddSingleton<IClaimsIndexer, ClaimsIndexer>();
Expand Down
Loading

0 comments on commit aa7443e

Please sign in to comment.