Skip to content

Generic resource definitions #806

Closed
@bart-degreed

Description

@bart-degreed

Current situation

The current way how resource definitions work is that JADNC provides a generic base class, which users can derive from for a specific resource type. JADNC contains scanning logic that picks up such non-generic (resource-bound) classes and calls into them from various places.

Example:

public class OrderLineDefinition : ResourceDefinition<OrderLine>
{
    // ...
}

When no resource-bound class is found for a specific resource, then resource callbacks are skipped for that resource type. This is accomplished via a non-generic IResourceDefinition interface, which is a type intended for internal use only to track which callbacks are available. It put me on the wrong track when I started using JADNC: I expected this was something for me to implement (similar to services and repositories), but it is not.

Proposal

I'd like to make resource definitions a first-class pluggable extensibility point, similar to services and repositories, so that resource definitions are always called into. We would provide an interface along with a default generic implementation (that contains no logic). Users can then implement the interface themselves and register their generic type -and- derive from our default generic implementation and register that -and- declare resource-bound definitions, which may derive from their own generic base class.

Example:

namespace JADNC
{
    public interface IResourceDefinition<TResource>
    {
        // ...
    }

    public class JsonApiResourceDefinition<TResource> : IResourceDefinition<TResource>
    {
        // ...
    }
}

namespace ApiDeveloper
{
    public class CustomResourceDefinition<TResource> : JsonApiResourceDefinition<TResource>
    {
        // ...
    }

    public class OrderLineResourceDefinition : CustomResourceDefinition<OrderLine>
    {
        // ...
    }
}

Use case

The use case I have in mind for this is authorization. Assume the system stores whether users have read/write access per resource type. While it is possible to annotate controller methods with attributes, this would not be sufficient. It would only work for primary requests like /articles and /articles/1, but not secondary requests like /articles/1/author. The controller would need to contain custom logic that inspects the relationship parameter and runs the permission check for that too. It is even debatable whether a permission check on articles should be done in that case, because the request is not targeting an article.

But it gets worse: a request like /articles?include=author would not get checked for access to the author resource. The current way to deal with that would be to override ResourceDefinition.OnApplyIncludes for all resource types in the project. A similar override for ResourceDefinition.OnApplyFilter is needed to properly check a request like /articles?filter=any(revisions) to ensure the caller has read permission on the revisions table.

If it were possible to plug in a generic resource definition, it could handle the permission check for all resource types in the project. Resource-bound classes would then call into the base class to ensure authorization is always applied.

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions