scott-mcdonald / JsonApiFramework

JsonApiFramework is a fast, extensible, and portable .NET framework for the reading and writing of JSON API documents. Currently working on ApiFramework 1.0 which is a new framework that supports the many enhancements documented in the 2.0 milestone of this project while being media type agnostic but will support media types like {json:api} and GraphQL for serialization/deserialization purposes.
Other
96 stars 11 forks source link

BC break in v1.8.0+ related to hypermedia links #57

Closed evsheffield closed 6 years ago

evsheffield commented 6 years ago

It seems that there may have been a backwards-compatible break introduced in 1.8.0 that causes issues generating hypermedia links for certain configurations. For example, here is a setup that worked in 1.7.0 but seems incompatible with later versions:

Document Context resource type configuration

protected override void OnServiceModelCreating(IServiceModelBuilder serviceModelBuilder)
{
    var inodeConfiguration = serviceModelBuilder.Resource<ReportINodeSummary>();
    inodeConfiguration.Hypermedia().SetApiCollectionPathSegment("api/inodes");
    inodeConfiguration.ResourceIdentity(x => x.Id).SetApiType("inodes");
    ...
}

Document Creation

var document = new ReportingDocumentContext(currentUri)
        .NewDocument(currentUri)
            .Links()
                .AddSelfLink()
            .LinksEnd()
            .ResourceCollection(inodeSummaries)
            .ResourceCollectionEnd()
            .WriteDocument();

In v1.8.0 and above, this results in the following error: System.InvalidOperationException: Sequence contains no elements, which seems to be linked to the presence of AddSelfLink().

   at System.Linq.Enumerable.Last[TSource](IEnumerable`1 source)
      at JsonApiFramework.Server.Hypermedia.Internal.DocumentPathContext.GetPrimaryClrResourceType()
      at JsonApiFramework.Server.Hypermedia.HypermediaAssembler.CreateStandardDocumentLink(IHypermediaContext hypermediaContext, IDocumentPathContext documentPathContext, ILinkContext linkContext)
      at JsonApiFramework.Server.Hypermedia.HypermediaAssembler.CreateDocumentLink(IHypermediaContext hypermediaContext, IDocumentPathContext documentPathContext, DocumentType documentType, ILinkContext linkContext)
      at JsonApiFramework.Server.Internal.DocumentBuilder.ResolveDocumentHypermedia()
      at JsonApiFramework.Server.Internal.DocumentBuilder.WriteDocument()

However, it seems that adding the following configuration for a new type to OnServiceModelCreating (adapted from your example repository) clears up the issue.

var apiEntryPointConfiguration = serviceModelBuilder.Resource<ApiEntryPoint>();
apiEntryPointConfiguration.Hypermedia().SetApiCollectionPathSegment("api");
apiEntryPointConfiguration.ResourceIdentity().SetApiType("api-entry-point");

I'm unsure if this is a bug or simply my lack of understanding of DocumentContext and resource configuration requirements of the latest versions. Any guidance would be much appreciated!

scott-mcdonald commented 6 years ago

@evsheffield Sorry about the breaking change as I tried to avoid such things. First question I have, is the path segment "api" at the root of all your Web API routes?

evsheffield commented 6 years ago

Hi @scott-mcdonald, thanks for the quick reply! Yes, the "api" path segment is at the root of all of our API routes.

scott-mcdonald commented 6 years ago

@evsheffield A couple of comments.

Let me know if this resolves your problem.

scott-mcdonald commented 6 years ago

@evsheffield Also, upgrade to v1.9 as well which is the latest version and the version the current Samples project is built off of that I mentioned in the previous post.

evsheffield commented 6 years ago

@scott-mcdonald I made sure we are on the latest version and configured "api" as a root segment in the UrlBuilderConfiguration instead of manually in each collection path as you recommended and that did the trick. 👍 Thanks so much for your help!