-
Notifications
You must be signed in to change notification settings - Fork 23
[WIP] The big rewrite #96
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
+ is no longer allowed for sorting ascending
Payload has been replaced with Document. Serializer has been replaced with Formatter. Purged the last few instances of Model Manager and Metadata Manager Cleared up some Resharper warnings
also merged related resource tests into the FetchingResources test class.
It breaks for inheritance
This is a much more ergonomic solution than passing a JToken around.
Adding globalization for decimal, double and single for conversion.
… linkage Prior to this change, they were just being ignored.
I wanted to use this PR in my project to check if it worked. But I got lost at how to register all my model types, what I'd done:
where config is HTTPConfiguration
Do I need to extend IResourceObject in my Session model so JSONAPI recognizes the session like:
Because I get an error something like: Session type cannot be deserialized. So I have no idea how I can return my Session model as a SingleResourceDocument. |
@GlennGeelen So, first I must apologize for the state of this PR. We've been furiously trying to get our product out the door and until we finish I can only contribute to JSONAPI.NET that which directly impacts our launch. Secondly, after using the PR for a few weeks, I'm rather unhappy with the configuration and registration story. There is still far too much boilerplate required of the API developer, and writing document materializers is a real pain. I have some ideas for changes that will improve the situation, but I don't know when I'll have time to get to them. As to solving your problem given the current state of the branch, if you look at the samples in I should note that if you do want to use controllers with action methods, you can still do this. You can use an |
Ok, thanks @csantero for the examples and further explanation. |
Summary
This is a rewrite of the JSONAPI.NET to improve compatibility with the 1.0 spec and to give API authors greater control over what goes into a response document, as well as greater access to information from the request document. This organization of the codebase is now vastly improved, with many smaller files (RIP the monolithic media type formatter). The library now fully embraces dependency injection, allowing API authors to provide their own handlers for pretty much any component in the system.
Rationale
When JSONAPI.NET was first created, the JSON API spec looked very different from how it does today. Polymorphism wasn't really well defined, nor were things like pagination and sorting. It was possible to define resource "linkage" without including the linked resources in the compound document. It was possible to query resources using multiple comma-separated ids. Attributes were found directly on the resource object root, instead of inside an
attributes
object. As a result of the changes that led to JSON API 1.0, some of the fundamental assumptions in JSONAPI.NET started to get in the way, and I felt that in order to move forward, we would have to break with the past.Documents
One of the largest frustrations writing an API that uses JSONAPI.NET has been the lack of control over the response, as well as restricted access to data being sent in a PATCH or POST request. The problem is that
JsonApiFormatter
has been doing too much. Currently, it needs to know about all your registered types, and it determines how to serialize/deserialize them. This has the following consequences:MetadataManager
into controllers, but this would have been a hacky and brittle solution.My solution to these problems has been to introduce an intermediate data structure, called the Document, which is analogous to the JSON API document. There are three types of Document that
JsonApiFormatter
knows how to serialize or deserialize:ISingleResourceDocument
,IResourceCollectionDocument
, andIErrorDocument
. It is now the controller action's responsibility to build these documents.JsonApiController
andIDocumentMaterializer
The generic
ApiController<T>
has been renamed toJsonApiController<T>
, and the EntityFramework-specificApiController<T, TDbContext>
has been removed.JsonApiController
defines the same actions it did before, but now it is no longer necessary to override those actions to provide your own functionality. These action methods now all delegate to methods on a new interface calledIDocumentMaterializer<T>
, which is the new main point of extensibility in JSONAPI.NET.Your implementation of
IDocumentMaterializer<T>
is responsible for building document instances that the controller actions will return to theJsonApiFormatter
. If you are using Entity Framework, there is anEntityFrameworkDocumentMaterializer<T>
that should work for many use-cases. If you aren't using EF, or you need more control, you can write your ownIDocumentMaterializer<T>
implementation.SingleResourceDocumentBuilder
,ResourceCollectionDocumentBuilder
, andDefaultQueryableResourceCollectionDocumentBuilder
are tools that can help you build your own document based on a registered POCO object.Of course, you don't have to use
JsonApiController
if you don't want to. As long as your controller actions returnISingleResourceDocument
,IResourceCollectionDocument
, orIErrorDocument
, thenJsonApiFormatter
can work with it. For POST and PATCH, your actions will have to take a parameter ofISingleResourceDocument
orIResourceCollectionDocument
.Configuration and Dependency injection
Previously, JSONAPI.NET has shied away from using ASP.NET Web API's DI system to supply controller constructor parameters, because we didn't want to step on the user's toes as they may have configured their own
IDependencyResolver
. Since the changes in this PR require services to be injected into controllers via the constructor, it's no longer possible to avoid DI inside this library. Therefore, JSONAPI.NET will start including integration packages for the most popular DI frameworks. My own project uses Autofac, so that is the first framework I have added support for. An example setup for configuring JSONAPI.NET with Autofac is in theJSONAPI.TodoMVC.API
project. I am happy to accept pull requests that add support for other DI frameworks.Registry Naming conventions
IModelManager
still exists, in modified form. First off, it has been renamed toIResourceTypeRegistry
. Second, the default implementation,ResourceTypeRegistry
no longer concerns itself with how to name resource types and fields, but rather delegates to anINamingConventions
service to do this.DefaultNamingConventions
will dasherize all property names, unless those properties have aJsonProperty
attribute. If you prefer camel-cased field names or something else, you can now provide your ownINamingConventions
.Link templates
You can still specify link templates for relationship properties, but now there are two kinds: relationship links, and related resource links. You can now specify an
ILinkConventions
which decides how to format these URLs. The default implementation follows the JSON API recommendations for formatting relationship and related resource URLs.SerializeAsAttribute
It's gone. Deciding what links or related resources to include for a particular resource's relationship is now a concern of document builders, not something to be set at compile-time by decorating properties with attributes.
Action filters
JsonApiQueryableAttribute
is gone, because action filters are not meant to returnIQueryable<T>
anymore. Its functionality has been moved toDefaultQueryableResourceCollectionDocumentBuilder
.There are two new action filters,
FallbackDocumentBuilderAttribute
is responsible for the functionality that allows controller actions to return POCOs, and also ensures that the correct HTTP status code is set for error documents.JsonApiExceptionFilterAttribute
catches exceptions and converts them toIErrorDocument
.JsonApiHttpConfiguration
will make sure that both these action filters are registered globally, along with theJsonApiFormatter
Still to do
DefaultQueryableResourceCollectionDocumentBuilder
needs to send pagination links.BaseUrlService
works with endpoints that have a path root. Such as/api/todos
instead of just/todos