question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

RFC: Separate Concerns of JsonApiContext

See original GitHub issue

Start Date: N/A Status: WIP RFC PR: N/A

Summary

Refactor the JsonApiContext into classes with singular responsibilities.

Motivation

The JsonApiContext is a god container whose members are set in various places during the request cycle. Because of the large set of responsibilities this class takes on, it can make testing difficult. Its role, in general, is to ensure ambient data is available whenever necessary.

This was more of an issue during the early stages of development when the architecture was still in flux. Now that the internal APIs are solidifying, we can begin separating this class into single responsibility implementations.

Note: The primary benefit that still exists of the JsonApiContext is that it reduces the number of constructor dependencies required for each class.

Detailed Design

TODO: map all the consumption points and identify separation strategies

Controllers (#255)

ApplyContext<TController>. This method is responsible for:

  • Setting the controller type on the context
    • Move into ActionFilter
  • Setting RequestEntity
    • Move into ActionFilter
    • May create a scoped IResourceRequest that provides Get(/* ... */) and Set(/* ... */) methods to replace this functionality.
  • Parsing Query Params
    • Move into ActionFilter
  • Setting the list of IncludedRelationships
  • Determining if it is a RelationshipPath
  • Creating a PageManager

https://github.com/json-api-dotnet/JsonApiDotNetCore/blob/e7c65db8cf9bcd064eb7001703b8a2238095ee4f/src/JsonApiDotNetCore/Controllers/BaseJsonApiController.cs#L94

We should be able to remove the direct dependency by moving the functionality into an ActionFilter without any other modifications. However, the functionality defined above still needs to be factored out of the context where possible.

Deserializer

Proposed Approach:

  • Introduce JsonApiDeSerializerFactory that produces either:
    • JsonApiOperationsDeserializer
    • JsonApiDeSerializer (consider aliasing to a more descriptive name)
  • Optionally depend on JsonApiOptions directly
  • Depend on the ContextGraph directly
  • Extract out a DocumentRequest type that includes:
    • The original Documents or Document
    • The attributes to update
    • The relationships to update
public JsonApiDeSerializer(ContextGraph contextGraph, JsonApiOptions options = null)
{
    _contextGraph = contextGraph;
    _options = options ?? JsonApiOptions.Default;
}

Phased Implementation

The intent is to make changes in such a way that users of the library can gradually depend on the new structure without forced breaking changes. The rollout of this change will span 4 releases as outlined below:

  1. Allow internal consuming classes to depend on the new interfaces in a non-breaking way. For example, if we can find a way to remove the requirement that the controller call ApplyContext<T>, then there is no need for the controller to even depend on the JsonApiContext. In this case, we would keep the original constructor but provide an implementation that does not require the context:
public BaseJsonApiController(
            IJsonApiContext jsonApiContext,
            IGetAllService<T, TId> getAll = null,
            /* ... */
) { /* ... */ }

public BaseJsonApiController(
            IGetAllService<T, TId> getAll = null,
            /* ... */
) { /* ... */ }
  1. Obsolete the APIs dependent upon IJsonApiContext.
[Obsolete(/* ... */, error: false)] 
  1. Publish a breaking change release (v3 ?) that sets the ObsoleteAttribute error to true
[Obsolete(/* ... */, error: true)] 
  1. Drop the APIs in the following major release

App vs. Request vs. Operations

This needs its own issue

The JsonApiContext stores three kinds of information

  • Application: state that does not change for the life of the application
    • JsonApiOptions
    • ContextGraph
  • Request: state that applies to the entire request
    • BasePath
    • IsRelationshipPath
    • IsBulkOperationRequest
    • ControllerType
    • DocumentMeta
  • Operational: per-operation data
    • IncludedRelationships
    • AttributesToUpdate
    • RelationshipsToUpdate
    • HasManyRelationshipPointers
    • HasOneRelationshipPointers
    • QuerySet

Issue Analytics

  • State:closed
  • Created 5 years ago
  • Comments:15 (15 by maintainers)

github_iconTop GitHub Comments

1reaction
wayne-ocommented, Oct 3, 2019

I think that this will open up the project to a LOT mroe people!!

On Thu, Oct 3, 2019 at 3:33 PM Maurits Moeys notifications@github.com wrote:

@wayne-o https://github.com/wayne-o we’re currently getting pretty close to reaching that level. We’re moving towards a framework that still has the constraints in the repo/service/controller layers that are more or less implied by json:api spec but in which you’re completely free to pick any serialization format you like.

Example of such constraint: json:api allows for creation of a resource while simultaneously relating it to an already existing resource, but is not possible to create two resources in one request and relate them.

These constraints on the framework are more or less high-level design choices that are derived from json:api spec, and therefore can be expressed in but not limited to the json:api format. My goal is to adhere to these constraints but remove the dependency on json:api format of the payload.

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/json-api-dotnet/JsonApiDotNetCore/issues/253?email_source=notifications&email_token=AABLPDGF2LXDKLXSI5LS2G3QMX7E3A5CNFSM4EZNAKQ2YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEAIM6AA#issuecomment-537972480, or mute the thread https://github.com/notifications/unsubscribe-auth/AABLPDACPYWA2PI62STIPJTQMX7E3ANCNFSM4EZNAKQQ .

1reaction
jaredcnancecommented, Jun 11, 2018

@wayne-o that’s correct and would be my suggestion for now. #241 will make this much better once it is implemented. Any suggestions you have are more than welcome.

Read more comments on GitHub >

github_iconTop Results From Across the Web

JSON:API — Latest Specification (v1.1)
The rules for profile usage are dictated by RFC 6906. ... names in the include query parameter are space-separated instead of dot-separated.
Read more >
RFC: Using the JSON API specification for Neos services
All property names meant to be available externally are named separately and provided by a getter of the Dto. This can be enhanced...
Read more >
Handling API errors with Problem JSON
Celonis Senior Software Engineer David Hettler explains how Celonis leverages Problem JSON to solve API error handling once and for all.
Read more >
PEP RFC: Python Package Index (Warehouse) JSON API v1
Greetings! @cooperlees @sumanah and I would like to propose a PEP that formalizes the existing JSON API. The PEP introduces a JSON Schema ......
Read more >
JSON-LD 1.1
JSON is a useful data serialization and messaging format. This specification defines JSON-LD 1.1, a JSON-based format to serialize Linked ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found