JsonApiDotNetCore

A framework for building JSON:API compliant REST APIs using .NET Core and Entity Framework Core. Includes support for Atomic Operations.

Read more Getting started Contribute on GitHub
project logo
people working at desk

Objectives

The goal of this library is to simplify the development of APIs that leverage the full range of features provided by the JSON:API specification. You just need to focus on defining the resources and implementing your custom business logic.

Eliminate boilerplate

We strive to eliminate as much boilerplate as possible by offering out-of-the-box features such as sorting, filtering and pagination.

Extensibility

This library has been designed around dependency injection, making extensibility incredibly easy.

Features

The following features are supported, from HTTP all the way down to the database

Filtering

Perform compound filtering using the filter query string parameter

Sorting

Order resources on one or multiple attributes using the sort query string parameter

Sparse fieldset selection

Get only the data that you need using the fields query string parameter

Relationship inclusion

Side-load related resources of nested relationships using the include query string parameter

Security

Configure permissions, such as view/create/change/sort/filter of attributes and relationships

Validation

Validate incoming requests using built-in ASP.NET Core ModelState validation, which works seamlessly with partial updates

Customizable

Use various extensibility points to intercept and run custom code, besides just model annotations

Example usage

Expose resources with attributes and relationships

Resource

public class Article : Identifiable
{
    [Attr]
    [Required, MaxLength(30)]
    public string Title { get; set; }

    [Attr(Capabilities = AttrCapabilities.AllowFilter)]
    public string Summary { get; set; }

    [Attr(PublicName = "websiteUrl")]
    public string Url { get; set; }

    [Attr(Capabilities = AttrCapabilities.AllowView)]
    public DateTimeOffset LastModifiedAt { get; set; }

    [HasOne]
    public Person Author { get; set; }

    [HasMany]
    public ICollection<Revision> Revisions { get; set; }  

    [HasManyThrough(nameof(ArticleTags))]
    [NotMapped]
    public ICollection<Tag> Tags { get; set; }
    public ICollection<ArticleTag> ArticleTags { get; set; }
}
                     

Request


GET /articles?filter=contains(summary,'web')&sort=-lastModifiedAt&fields=title,summary&include=author HTTP/1.1

                     

Response


{
  "meta": {
    "totalResources": 1
  },
  "links": {
    "self": "/articles?filter=contains(summary,'web')&sort=-lastModifiedAt&fields=title,summary&include=author",
    "first": "/articles?filter=contains(summary,'web')&sort=-lastModifiedAt&fields=title,summary&include=author",
    "last": "/articles?filter=contains(summary,'web')&sort=-lastModifiedAt&fields=title,summary&include=author"
  },
  "data": [
    {
      "type": "articles",
      "id": "1",
      "attributes": {
        "title": "JsonApiDotNetCore rocks!",
        "summary": "Using JsonApiDotNetCore makes the web a better accessible place."
      },
      "relationships": {
        "author": {
          "links": {
            "self": "/articles/1/relationships/author",
            "related": "/articles/1/author"
          },
          "data": {
            "type": "people",
            "id": "1"
          }
        }
      },
      "links": {
        "self": "/articles/1"
      }
    }
  ],
  "included": [
    {
      "type": "people",
      "id": "1",
      "attributes": {
        "name": "John Doe"
      },
      "relationships": {
        "articles": {
          "links": {
            "self": "/people/1/relationships/articles",
            "related": "/people/1/articles"
          }
        }
      },
      "links": {
        "self": "/people/1"
      }
    }
  ]
}