diff --git a/CONTRIBUTING.MD b/CONTRIBUTING.MD index 0e14787fec..8ce50e6c68 100644 --- a/CONTRIBUTING.MD +++ b/CONTRIBUTING.MD @@ -2,10 +2,14 @@ ## Workflow -1. Search through the issues to see if your particular issue has already been discovered and possibly addressed -2. Open an issue if you can't find anything helpful -3. Open a PR for proposed changes +1. Search through the issues to see if your particular issue has already been discovered and possibly addressed +2. Open an issue if you can't find anything helpful +3. Open a PR for proposed changes ## Commit Guidelines I have chosen to loosely follow the [Angular Commit Guidelines](https://github.com/angular/angular.js/blob/master/CONTRIBUTING.md#commit) + +# Documentation + +If you'd like to help us improve our documentation, please checkout our [GitHub pages repository](https://github.com/json-api-dotnet/json-api-dotnet.github.io) where we host our documentation. diff --git a/couscous.yml b/couscous.yml deleted file mode 100644 index 2acaad12d7..0000000000 --- a/couscous.yml +++ /dev/null @@ -1,116 +0,0 @@ -template: - # Name of the directory containing the website template (default is "website") - # directory: docs/Template-Dark - # Or if you are using a remote template, you can set the Git URL - url: https://github.com/jaredcnance/Template-Dark.git - # Name of the index file (default is "README.md") - index: index.md - -# List of directories to include in the processing (by default it's empty, so all markdown files are parsed) -# Paths are relative to the optional source path given when generating the website, repository root by default -include: - - docs - -# List of directories to exclude from the processing (default contains "vendor" and "website") -# Paths are relative to the optional include paths given when generating the website, repository root by default -exclude: - # This special entry will ask Couscous to read the exluded directories from your ".gitignore" file - - %gitignore% - -# scripts: - # Scripts to execute before generating the website - # before: - # - cp bin/couscous.phar website/ - # Scripts to execute after generating the website - # after: - # - rm website/couscous.phar - -# Set this variable to use a Custom Domain -# The content of this variable will be directly inserted into the CNAME file -# cname: docs.yourdomain.com - -# Set the target branch in which to deploy the generated website -branch: gh-pages - -# Base URL of the published website (no "/" at the end!) -# You are advised to set and use this variable to write your links in the HTML layouts -baseUrl: https://json-api-dotnet.github.io/JsonApiDotNetCore/ -github: - user: research-institute - repo: json-api-dotnet-core - -title: JSONAPI .Net Core -subTitle: killing boilerplate in dotnet web APIs - -# The left menu bar -menu: - sections: - intro: - name: Getting Started - items: - about: - text: About - relativeUrl: index.html - installation: - text: Installation - relativeUrl: installation.html - usage: - text: Step by Step - relativeUrl: usage.html - usage: - name: Usage - items: - models: - text: Models - relativeUrl: models.html - contextgraph: - text: Context Graph - relativeUrl: contextgraph.html - meta: - text: Meta - relativeUrl: meta.html - options: - text: Global Options - relativeUrl: options.html - errors: - text: Custom Errors - relativeUrl: errors.html - filtering: - text: Filtering - relativeUrl: filtering.html - includingrelationships: - text: Including Relationships - relativeUrl: includingrelationships.html - pagination: - text: Pagination - relativeUrl: pagination.html - routing: - text: Routing - relativeUrl: routing.html - sorting: - text: Sorting - relativeUrl: sorting.html - sparsefields: - text: Sparse Fieldsets - relativeUrl: sparsefieldsets.html - extensibility: - name: Extensibility - items: - layers: - text: The Layers - relativeUrl: layers.html - controllers: - text: Controllers - relativeUrl: controllers.html - services: - text: Resource Services - relativeUrl: resourceservices.html - repositories: - text: Entity Repositories - relativeUrl: entityrepositories.html - middleware: - text: Middleware - relativeUrl: middleware.html - customqueryformat: - text: Custom Query Formats - relativeUrl: customqueryformat.html \ No newline at end of file diff --git a/docs/ContextGraph.md b/docs/ContextGraph.md deleted file mode 100644 index f5b8394b83..0000000000 --- a/docs/ContextGraph.md +++ /dev/null @@ -1,58 +0,0 @@ ---- -currentMenu: contextgraph ---- - -# Context Graph - -The [ContextGraph](https://github.com/Research-Institute/json-api-dotnet-core/blob/master/src/JsonApiDotNetCore/Internal/ContextGraph.cs) is a map of all the json:api resources and their relationships that your API serves. -It is built at app startup and available as a singleton through Dependency Injection. - -When you call `services.AddJsonApi()`, the graph is constructed from the context. - -### Defining Non-EF Resources - -If you have models that are not members of a `DbContext`, -you can manually create this graph like so: - -```csharp -// Startup.cs -public void ConfigureServices(IServiceCollection services) -{ - // Add framework services. - var mvcBuilder = services.AddMvc(); - - services.AddJsonApi(options => { - options.Namespace = "api/v1"; - options.BuildContextGraph((builder) => { - builder.AddResource("my-models"); - }); - }, mvcBuilder); - // ... -} -``` - -### Changing Resource Names - -If a DbContext is specified when adding the services, the context will be used to define the resources and their names. By default, these names will be hyphenated. - -```csharp -public class AppDbContext : DbContext { - // this will be translated into "my-models" - public DbSet MyModels { get; set; } -} -``` - -However, you can specify a custom name like so: - -```csharp -public class AppDbContext : DbContext { - // this will be translated into "someModels" - [Resource("someModels")] - public DbSet MyModels { get; set; } -} -``` - - - - - diff --git a/docs/Controllers.md b/docs/Controllers.md deleted file mode 100644 index 0ec47b8774..0000000000 --- a/docs/Controllers.md +++ /dev/null @@ -1,93 +0,0 @@ ---- -currentMenu: controllers ---- - -# Controllers - -You need to create controllers that inherit from [JsonApiController<TEntity>](https://github.com/Research-Institute/json-api-dotnet-core/blob/master/src/JsonApiDotNetCore/Controllers/JsonApiController.cs). - -```csharp -public class ThingsController : JsonApiController -{ - public ThingsController( - IJsonApiContext jsonApiContext, - IResourceService resourceService, - ILoggerFactory loggerFactory) - : base(jsonApiContext, resourceService, loggerFactory) - { } -} -``` - -### Non-Integer Type Keys - -If your model is using a type other than `int` for the primary key, -you should explicitly declare it in the controller -and service generic type definitions: - -```csharp -public class ThingsController : JsonApiController - //---------------------- ^^^^ -{ - public ThingsController( - IJsonApiContext jsonApiContext, - IResourceService resourceService, - //--------------------- ^^^^ - ILoggerFactory loggerFactory) - : base(jsonApiContext, resourceService, loggerFactory) - { } -} -``` - -### Limiting Write Access - -It is possible to limit write resource access on the controller entirely using the following attributes: - -- `NoHttpPost`: disallow POST requests -- `NoHttpPatch`: disallow PATCH requests -- `NoHttpDelete`: disallow DELETE requests -- `HttpReadOnly`: all of the above - -```csharp -[HttpReadOnly] -public class ThingsController : JsonApiController -{ - public ThingsController( - IJsonApiContext jsonApiContext, - IResourceService resourceService, - ILoggerFactory loggerFactory) - : base(jsonApiContext, resourceService, loggerFactory) - { } -} -``` - -### Additional customizations - -If you need additional customization at the controller level, you can override the virtual -methods. Please be aware that this is not the place for advanced business logic -which should be performed at the [service](resourceservices.html) or [repository](entityrepositories.html) layers. Here is an example override at the controller layer: - -```csharp -public class TodoItemsController : JsonApiController -{ - public TodoItemsController( - IJsonApiContext jsonApiContext, - IResourceService resourceService, - ILoggerFactory loggerFactory) - : base(jsonApiContext, resourceService, loggerFactory) - { } - - [HttpGet] - public override async Task GetAsync() - { - // custom code - if(RequestIsValid() == false) - return BadRequest(); - - // return result from base class - return await base.GetAsync(); - } - - // some custom validation logic - private bool RequestIsValid() => true; -} -``` diff --git a/docs/CustomQueryFormat.md b/docs/CustomQueryFormat.md deleted file mode 100644 index b23993d333..0000000000 --- a/docs/CustomQueryFormat.md +++ /dev/null @@ -1,13 +0,0 @@ ---- -currentMenu: customqueryformat ---- - -# Custom Query Formats - -For information on the default query parameter formats, see the documentation for each query method. - -In order to customize the query formats, you need to implement the `IQueryParser` interface and inject it like so: - -```csharp -services.AddScoped(); -``` \ No newline at end of file diff --git a/docs/EntityRepositories.md b/docs/EntityRepositories.md deleted file mode 100644 index 62d156e427..0000000000 --- a/docs/EntityRepositories.md +++ /dev/null @@ -1,44 +0,0 @@ ---- -currentMenu: repositories ---- - -# Entity Repositories - -If you want to use EF, but need additional data access logic (such as authorization), you can implement custom methods for accessing the data by creating an implementation of -[IEntityRepository<Entity, TId>](https://github.com/Research-Institute/json-api-dotnet-core/blob/master/src/JsonApiDotNetCore/Data/IEntityRepository.cs). If you only need minor changes you can override the -methods defined in [DefaultEntityRepository<TEntity, TId>](https://github.com/Research-Institute/json-api-dotnet-core/blob/master/src/JsonApiDotNetCore/Data/DefaultEntityRepository.cs). - -The repository should then be -add to the service collection in `Startup.cs` like so: - -```csharp -public IServiceProvider ConfigureServices(IServiceCollection services) { - services.AddScoped, MyAuthorizedEntityRepository>(); - // ... -} -``` - -A sample implementation that performs data authorization might look like: - -```csharp -public class MyAuthorizedEntityRepository : DefaultEntityRepository -{ - private readonly ILogger _logger; - private readonly IAuthenticationService _authenticationService; - - public MyAuthorizedEntityRepository( - ILoggerFactory loggerFactory, - IJsonApiContext jsonApiContext, - IAuthenticationService authenticationService) - : base(loggerFactory, jsonApiContext) - { - _logger = loggerFactory.CreateLogger(); - _authenticationService = authenticationService; - } - - public override IQueryable Get() - { - return base.Get().Where(e => e.UserId == _authenticationService.UserId); - } -} -``` diff --git a/docs/Errors.md b/docs/Errors.md deleted file mode 100644 index 59f4f6da21..0000000000 --- a/docs/Errors.md +++ /dev/null @@ -1,38 +0,0 @@ ---- -currentMenu: errors ---- - -# Custom Errors - -By default, errors will only contain the properties defined by the internal [Error](https://github.com/Research-Institute/json-api-dotnet-core/blob/master/src/JsonApiDotNetCore/Internal/Error.cs) class. However, you can create your own by inheriting from `Error` and either throwing it in a `JsonApiException` or returning the error from your controller. - -```csharp -// custom error definition -public class CustomError : Error { - public CustomError(string status, string title, string detail, string myProp) - : base(status, title, detail) - { - MyCustomProperty = myProp; - } - public string MyCustomProperty { get; set; } -} - -// throwing a custom error -public void MyMethod() { - var error = new CustomError("507", "title", "detail", "custom"); - throw new JsonApiException(error); -} - -// returning from controller -[HttpPost] -public override async Task PostAsync([FromBody] MyEntity entity) -{ - if(_db.IsFull) - return Error(new CustomError("507", "Database is full.", "Theres no more room.", "Sorry.")); - - if(model.Validations.IsValid == false) - return Errors(model.Validations.GetErrors()); - - // ... -} -``` \ No newline at end of file diff --git a/docs/Filtering.md b/docs/Filtering.md deleted file mode 100644 index c258fe4f73..0000000000 --- a/docs/Filtering.md +++ /dev/null @@ -1,50 +0,0 @@ ---- -currentMenu: filtering ---- - -# Filtering - -You can filter resources by attributes using the `filter` query parameter. -By default, all attributes are filterable. -The filtering strategy we have selected, uses the following form: - -``` -?filter[attribute]=value -``` - -For operations other than equality, the query can be prefixed with an operation -identifier): - -``` -?filter[attribute]=eq:value -?filter[attribute]=lt:value -?filter[attribute]=gt:value -?filter[attribute]=le:value -?filter[attribute]=ge:value -?filter[attribute]=like:value -``` - -### Custom Filters - -You can customize the filter implementation by overriding the method in the `DefaultEntityRepository` like so: - -```csharp -public class MyEntityRepository : DefaultEntityRepository -{ - public MyEntityRepository( - AppDbContext context, - ILoggerFactory loggerFactory, - IJsonApiContext jsonApiContext) - : base(context, loggerFactory, jsonApiContext) - { } - - public override IQueryable Filter(IQueryable entities, FilterQuery filterQuery) - { - // use the base filtering method - entities = base.Filter(entities, filterQuery); - - // implement custom method - return ApplyMyCustomFilter(entities, filterQuery); - } -} -``` diff --git a/docs/IncludingRelationships.md b/docs/IncludingRelationships.md deleted file mode 100644 index e11657ebdf..0000000000 --- a/docs/IncludingRelationships.md +++ /dev/null @@ -1,54 +0,0 @@ ---- -currentMenu: includingrelationships ---- - -# Including Relationships - -JADNC supports [request include params](http://jsonapi-resources.com/v0.9/guide/resources.html#Included-relationships-side-loading-resources) out of the box, for side loading related resources. - -Here’s an example from the spec: - -```http -GET /articles/1?include=comments HTTP/1.1 -Accept: application/vnd.api+json -``` - -Will get you the following payload: - -```json -{ - "data": { - "type": "articles", - "id": "1", - "attributes": { - "title": "JSON API paints my bikeshed!" - }, - "relationships": { - "comments": { - "links": { - "self": "http://example.com/articles/1/relationships/comments", - "related": "http://example.com/articles/1/comments" - }, - "data": [ - { "type": "comments", "id": "5" }, - { "type": "comments", "id": "12" } - ] - } - } - }, - "included": [{ - "type": "comments", - "id": "5", - "attributes": { - "body": "First!" - } - }, { - "type": "comments", - "id": "12", - "attributes": { - "body": "I like XML better" - } - }] -} -``` - diff --git a/docs/Index.md b/docs/Index.md deleted file mode 100644 index 64b0861155..0000000000 --- a/docs/Index.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -currentMenu: about ---- - -# JSON API .Net Core - -A framework for building [json:api](http://jsonapi.org/) compliant web servers. It allows you to eliminate a significant amount of boilerplate while offering out-of-the-box features such as sorting, filtering and pagination. This library provides all the required middleware to build a complete server. All you need to focus on is defining the resources and implementing your custom business logic. This library has been designed around dependency injection making extensibility incredibly easy. \ No newline at end of file diff --git a/docs/Installation.md b/docs/Installation.md deleted file mode 100644 index 367d5d3a2e..0000000000 --- a/docs/Installation.md +++ /dev/null @@ -1,29 +0,0 @@ ---- -currentMenu: installation ---- - -# Installation - -- CLI -``` -$ dotnet add package jsonapidotnetcore -``` - -- Visual Studio -``` -Install-Package JsonApiDotnetCore -``` - -- *.csproj -```xml - - - - -``` - -Click [here](https://www.nuget.org/packages/JsonApiDotnetCore/) for the latest NuGet version. - -For pre-releases (develop branch), add the [MyGet](https://www.myget.org/feed/Details/research-institute) package feed -(https://www.myget.org/F/research-institute/api/v3/index.json) -to your nuget configuration. \ No newline at end of file diff --git a/docs/Layers.md b/docs/Layers.md deleted file mode 100644 index 5c71030274..0000000000 --- a/docs/Layers.md +++ /dev/null @@ -1,57 +0,0 @@ ---- -currentMenu: layers ---- - -# The Layers - -By default, data retrieval is distributed across 3 layers: - -1. [JsonApiController](https://github.com/Research-Institute/json-api-dotnet-core/blob/master/src/JsonApiDotNetCore/Controllers/JsonApiController.cs) (required) -2. [IResourceService](https://github.com/Research-Institute/json-api-dotnet-core/blob/master/src/JsonApiDotNetCore/Services/IResourceService.cs) (default [EntityResourceService](https://github.com/Research-Institute/json-api-dotnet-core/blob/master/src/JsonApiDotNetCore/Services/EntityResourceService.cs)) -3. [IEntityRepository](https://github.com/Research-Institute/json-api-dotnet-core/blob/master/src/JsonApiDotNetCore/Data/IEntityRepository.cs) (default [DefaultEntityRepository](https://github.com/Research-Institute/json-api-dotnet-core/blob/master/src/JsonApiDotNetCore/Data/DefaultEntityRepository.cs)) - -Customization can be done at any of these layers. However, it is recommended that you make your customizations at the service or the repository layer when possible to keep the controllers free of unnecessary logic. You can use the following as a general rule of -thumb for where to put business logic: - -- **Controller**: simple validation logic that should result in the return of specific HTTP status codes such as model validation -- **IResourceService**: advanced BL and replacement of data access mechanisms -- **IEntityRepository**: custom logic that builds on the EF APIs, such as Authorization of data - -## Replacing Services / Repositories - -Replacing services is done on a per resource basis and can be done through simple DI -in your Startup.cs file: - -```csharp -public IServiceProvider ConfigureServices(IServiceCollection services) -{ - // custom service - services.AddScoped, CustomPersonService>(); - - // custom repository - services.AddScoped, AuthorizedTodoItemRepository>(); - - // ... -} -``` - -## Not Using Entity Framework? - -Out of the box, the library uses your `DbContext` to create a "ContextGraph" or map of all your models and their relationships. If, however, you have models that are not members of a `DbContext`, you can manually create this graph like so: - -```csharp -// Startup.cs -public void ConfigureServices(IServiceCollection services) -{ - // Add framework services. - var mvcBuilder = services.AddMvc(); - - services.AddJsonApi(options => { - options.Namespace = "api/v1"; - options.BuildContextGraph((builder) => { - builder.AddResource("my-models"); - }); - }, mvcBuilder); - // ... -} -``` diff --git a/docs/Meta.md b/docs/Meta.md deleted file mode 100644 index 10b1a23e9a..0000000000 --- a/docs/Meta.md +++ /dev/null @@ -1,29 +0,0 @@ ---- -currentMenu: meta ---- - -# Meta - -Meta objects can be assigned in two ways: - - Resource meta - - Request Meta - -Resource meta can be defined by implementing `IHasMeta` on the model class: - -```csharp -public class Person : Identifiable, IHasMeta -{ - // ... - - public Dictionary GetMeta(IJsonApiContext context) - { - return new Dictionary { - { "copyright", "Copyright 2015 Example Corp." }, - { "authors", new string[] { "Jared Nance" } } - }; - } -} -``` - -Request Meta can be added by injecting a service that implements `IRequestMeta`. -In the event of a key collision, the Request Meta will take precendence. diff --git a/docs/Middleware.md b/docs/Middleware.md deleted file mode 100644 index 681136ca9b..0000000000 --- a/docs/Middleware.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -currentMenu: middleware ---- - -# Configure Middleware and Services - -Add the following to your `Startup.ConfigureServices` method. -Replace `AppDbContext` with your DbContext. - -```csharp -services.AddJsonApi(); -``` - -Add the middleware to the `Startup.Configure` method. -Note that under the hood, this will call `app.UseMvc()` -so there is no need to add that as well. - -```csharp -app.UseJsonApi(); -``` \ No newline at end of file diff --git a/docs/Models.md b/docs/Models.md deleted file mode 100644 index 73d9afdc43..0000000000 --- a/docs/Models.md +++ /dev/null @@ -1,106 +0,0 @@ ---- -currentMenu: models ---- - -# Defining Models - -Models must implement [IIdentifiable<TId>](https://github.com/Research-Institute/json-api-dotnet-core/blob/master/src/JsonApiDotNetCore/Models/IIdentifiable.cs). -The easiest way to do this is to inherit [Identifiable<TId>](https://github.com/Research-Institute/json-api-dotnet-core/blob/master/src/JsonApiDotNetCore/Models/Identifiable.cs) where `TId` is the type of the primary key, like so: - -```csharp -public class Person : Identifiable -{ } -``` - -You can use the non-generic `Identifiable` if your primary key is an integer: - -```csharp -public class Person : Identifiable -{ } -``` - -If you need to hang annotations or attributes on the `Id` property, you can override the virtual member: - -```csharp -public class Person : Identifiable -{ - [Key] - [Column("person_id")] - public override int Id { get; set; } -} -``` - -If your model must inherit from another class, you can always implement the interface yourself. -In the following example, ApplicationUser inherits IdentityUser which already contains an Id property of -type string. - -```csharp -public class ApplicationUser -: IdentityUser, IIdentifiable -{ - [NotMapped] - public string StringId { get => this.Id; set => Id = value; } -} -``` - -## Specifying Public Attributes - -If you want an attribute on your model to be publicly available, -add the `AttrAttribute` and provide the outbound name. - -```csharp -public class Person : Identifiable -{ - [Attr("first-name")] - public string FirstName { get; set; } -} -``` - -### Immutability - -Attributes can be marked as immutable which will prevent `PATCH` requests -from updating them: - -```csharp -public class Person : Identifiable -{ - [Attr("first-name", immutable: true)] - public string FirstName { get; set; } -} -``` - -## Relationships - -In order for navigation properties to be identified in the model, -they should be labeled with the appropriate attribute (either `HasOne` or `HasMany`). - -```csharp -public class Person : Identifiable -{ - [Attr("first-name")] - public string FirstName { get; set; } - - [HasMany("todo-items")] - public virtual List TodoItems { get; set; } -} -``` - -Dependent relationships should contain a property in the form `{RelationshipName}Id`. -For example, a `TodoItem` may have an `Owner` and so the Id attribute should be `OwnerId` like so: - -```csharp -public class TodoItem : Identifiable -{ - [Attr("description")] - public string Description { get; set; } - - public int OwnerId { get; set; } - - [HasOne("owner")] - public virtual Person Owner { get; set; } -} -``` - -## Resource Names - -See [ContextGraph](contextGraph.html) for details on how the resource names are determined. \ No newline at end of file diff --git a/docs/Operations.md b/docs/Operations.md deleted file mode 100644 index 697f9171b2..0000000000 --- a/docs/Operations.md +++ /dev/null @@ -1,33 +0,0 @@ ---- -currentMenu: operations ---- - -# Operations - -Operations is currently an unofficial proposal. It allows you to perform bulk operations in a single transaction. - -### Enabling - -To enable the operations extension, modify you `Startup.ConfigureServices` method: - -```csharp -services.AddJsonApi(opt => opt.EnableExtension(JsonApiExtension.Operations)); -``` - -### Controllers - -To create a bulk operations controller, inherit `JsonApiOperationsController`: - -```csharp -[Route("api/bulk")] -public class OperationsController : JsonApiOperationsController -{ - public OperationsController(IOperationsProcessor processor) - : base(processor) - { } -} -``` - -### Example - -There is a working example in the `/src/examples/OperationsExample` directory of the repository. \ No newline at end of file diff --git a/docs/Options.md b/docs/Options.md deleted file mode 100644 index 3f94f4031e..0000000000 --- a/docs/Options.md +++ /dev/null @@ -1,111 +0,0 @@ ---- -currentMenu: options ---- - -# Global Options - -## Client Generated Ids - -By default, the server will respond with a `403 Forbidden` HTTP Status Code if a `POST` request is -received with a client generated id. However, this can be allowed by setting the `AllowClientGeneratedIds` -flag in the options: - -```csharp -public IServiceProvider ConfigureServices(IServiceCollection services) { - services.AddJsonApi( - opt => opt.AllowClientGeneratedIds = true); - // ... -} -``` - -## Pagination - -If you would like pagination implemented by default, you can specify the page size -when setting up the services: - -```csharp -public IServiceProvider ConfigureServices(IServiceCollection services) { - services.AddJsonApi( - opt => opt.DefaultPageSize = 10); - // ... -} -``` - -### Total Record Count - -The total number of records can be added to the document meta by setting it in the options: - -```csharp -public IServiceProvider ConfigureServices(IServiceCollection services) { - services.AddJsonApi(opt => - { - opt.DefaultPageSize = 5; - opt.IncludeTotalRecordCount = true; - }); - // ... -} -``` - -## Relative Links - -All links are absolute by default. However, you can configure relative links: - -```csharp -public IServiceProvider ConfigureServices(IServiceCollection services) { - services.AddJsonApi( - opt => opt.RelativeLinks = true); - // ... -} -``` - - -```http -GET /api/v1/articles/4309 HTTP/1.1 -Accept: application/vnd.api+json -``` - -```json -{ - "type": "articles", - "id": "4309", - "attributes": { - "name": "Voluptas iure est molestias." - }, - "relationships": { - "author": { - "links": { - "self": "/api/v1/articles/4309/relationships/author", - "related": "/api/v1/articles/4309/author" - } - } - } -} -``` - -## Custom Query Parameters - -If you would like to use custom query params (parameters not reserved by the json:api specification), you can set `AllowCustomQueryParameters = true`. The default behavior is to return an `HTTP 400 Bad Request` for unknown query parameters. - -```csharp -public IServiceProvider ConfigureServices(IServiceCollection services) { - services.AddJsonApi( - opt => opt.AllowCustomQueryParameters = true); - // ... -} -``` - -## Custom Serializer Settings - -We use Json.Net for all serialization needs. If you want to change the default serializer settings, you can: - -```csharp -public IServiceProvider ConfigureServices(IServiceCollection services) { - services.AddJsonApi( - opt => opt.SerializerSettings = new JsonSerializerSettings() - { - NullValueHandling = NullValueHandling.Ignore, - ContractResolver = new DasherizedResolver() - }); - // ... -} -``` \ No newline at end of file diff --git a/docs/Pagination.md b/docs/Pagination.md deleted file mode 100644 index 7d70773757..0000000000 --- a/docs/Pagination.md +++ /dev/null @@ -1,23 +0,0 @@ ---- -currentMenu: pagination ---- - -# Pagination - -Resources can be paginated. -The following query would set the page size to 10 and get page 2. - -``` -?page[size]=10&page[number]=2 -``` - -If you would like pagination implemented by default, you can specify the page size -when setting up the services: - -```C# -public IServiceProvider ConfigureServices(IServiceCollection services) { - services.AddJsonApi( - opt => opt.DefaultPageSize = 10); - // ... -} -``` diff --git a/docs/ResourceServices.md b/docs/ResourceServices.md deleted file mode 100644 index 17e7763835..0000000000 --- a/docs/ResourceServices.md +++ /dev/null @@ -1,126 +0,0 @@ ---- -currentMenu: services ---- - -# Resource Services - -The [IResourceService](https://github.com/json-api-dotnet/JsonApiDotNetCore/blob/master/src/JsonApiDotNetCore/Services/Contract/IResourceService.cs) acts as a service layer between the controller and the data access -layer. This allows you to customize it however you want and not be dependent upon Entity -Framework. This is also a good place to implement custom business logic. - -### Supplementing Default Behavior - -A simple example would be to send notifications when an entity gets created: - -```csharp -public class TodoItemService : EntityResourceService { - - private readonly INotificationService _notificationService; - - public TodoItemService( - IJsonApiContext jsonApiContext, - IEntityRepository repository, - ILoggerFactory loggerFactory, - // Get the notification service via DI - INotificationService notificationService) - : base(jsonApiContext, repository, loggerFactory) - { - _notificationService = notificationService; - } - - public override async Task CreateAsync(TEntity entity) - { - // call the base implementation which uses Entity Framework - var newEntity = await base.CreateAsync(entity); - - // custom code - _notificationService.Notify($"Entity created: { newEntity.Id }"); - - // don't forget to return the new entity - return entity; - } -} -``` - -### Not Using Entity Framework? - -As previously discussed, this library uses Entity Framework by default. -If you'd like to use another ORM that does not implement `IQueryable`, -you can inject a custom service like so: - -```csharp -// Startup.cs -public void ConfigureServices(IServiceCollection services) -{ - // add the service override for MyModel - services.AddScoped, MyModelService>(); - - // add your own DAO - services.AddScoped(); - // ... -} - - -// MyModelService.cs -public class MyModelService : IResourceService -{ - private readonly IMyModelDAL _dal; - public MyModelService(IMyModelDAL dal) - { - _dal = dal; - } - - public Task> GetAsync() - { - return await _dal.GetModelAsync(); - } -} -``` - -### Limited Requirements - -In some cases it may be necessary to only expose a few methods on the resource. -For this reason, we have created a hierarchy of service interfaces that can be used to get the -exact implementation you require. Below is a table outlining these interfaces: - -![interfaces](service_table.png) - - - In order to take advantage of these interfaces you first need to inject the service for each implemented interface. - Using Autofac, as an example, this is simply: - -```csharp -public class MyResourceService : ICreateService, IDeleteService { - // ... -} -``` - -```csharp -public class Startup { - public IServiceProvider ConfigureServices(IServiceCollection services) { - builder.RegisterType().AsImplementedInterfaces(); - } -} -``` - -Then in the controller, you should inherit the base controller and pass the services into -the named, optional base parameters: - -```csharp -public class MyResourcesController : BaseJsonApiController { - - public MyResourcesController( - IJsonApiContext jsonApiContext, - ICreateService create, - IDeleteService delete - ) : base(jsonApiContext, create: create, delete: delete) { } - - [HttpPost] - public override async Task PostAsync([FromBody] MyResource entity) - => await base.PostAsync(entity); - - [HttpDelete("{id}")] - public override async TaskDeleteAsync(int id) - => await base.DeleteAsync(id); -} -``` diff --git a/docs/Routing.md b/docs/Routing.md deleted file mode 100644 index 008438dd39..0000000000 --- a/docs/Routing.md +++ /dev/null @@ -1,65 +0,0 @@ ---- -currentMenu: routing ---- - -# Routing - -By default the library will configure routes for each controller. -Based on the [recommendations](http://jsonapi.org/recommendations/) -outlined in the JSONAPI spec, routes are hyphenated. - -```http -GET /api/compound-models HTTP/1.1 -Accept: application/vnd.api+json -``` - -## Namespacing and Versioning URLs - -You can add a namespace to the URL by specifying it in `ConfigureServices`: - -```csharp -public IServiceProvider ConfigureServices(IServiceCollection services) { - services.AddJsonApi( - opt => opt.Namespace = "api/v1"); -} -``` - -## Disable Convention - -You can disable the dasherized convention and specify your own template -by using the `DisableRoutingConvention` Attribute. - -```csharp -[Route("[controller]")] -[DisableRoutingConvention] -public class CamelCasedModelsController : JsonApiController { - public CamelCasedModelsController( - IJsonApiContext jsonApiContext, - IResourceService resourceService, - ILoggerFactory loggerFactory) - : base(jsonApiContext, resourceService, loggerFactory) - { } -} -``` - -It is important to note that your routes *must* still end with the model name in the same format -as the resource name. This is so that we can build accurrate resource links in the json:api document. -For example, if you define a resource as `MyModels` the controller route must match: - -```csharp -public IServiceProvider ConfigureServices(IServiceCollection services) { - services.AddJsonApi(options => { - options.BuildContextGraph((builder) => { - // resource definition - builder.AddResource("myModels"); - }); - }); -} - -// controller definition -[Route("api/myModels")] -[DisableRoutingConvention] -public class TodoItemsController : JsonApiController { - //... -} -``` diff --git a/docs/Sorting.md b/docs/Sorting.md deleted file mode 100644 index 6a5367d8d9..0000000000 --- a/docs/Sorting.md +++ /dev/null @@ -1,12 +0,0 @@ ---- -currentMenu: sorting ---- - -# Sorting - -Resources can be sorted by an attribute: - -``` -?sort=attribute // ascending -?sort=-attribute // descending -``` diff --git a/docs/SparseFieldsets.md b/docs/SparseFieldsets.md deleted file mode 100644 index 16e66a2c89..0000000000 --- a/docs/SparseFieldsets.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -currentMenu: sparsefields ---- - -# Sparse Fieldsets - -We currently support top-level field selection. -What this means is you can restrict which fields are returned by a query using the `fields` query parameter, but this does not yet apply to included relationships. - -- Currently valid: -```http -GET /articles?fields[articles]=title,body HTTP/1.1 -Accept: application/vnd.api+json -``` - -- Not yet supported: -```http -GET /articles?include=author&fields[articles]=title,body&fields[people]=name HTTP/1.1 -Accept: application/vnd.api+json -``` \ No newline at end of file diff --git a/docs/Usage.md b/docs/Usage.md deleted file mode 100644 index 07ac168a21..0000000000 --- a/docs/Usage.md +++ /dev/null @@ -1,144 +0,0 @@ ---- -currentMenu: usage ---- - -# Usage - -The most basic use case leverages Entity Framework. -The shortest path to a running API looks like: - -- Create a new web app -- Install -- Define models -- Define the DbContext -- Define controllers -- Add Middleware and Services -- Seed the database -- Run Migrations -- Start the app - -This page will walk you through the **simplest** use case. More detailed examples can be found in the detailed usage subsections. - - -### Create a New Web App - -``` -$ mkdir MyApp -$ cd MyApp -$ dotnet new webapi -``` - -### Install - -See [Installation](installation.html) - -### Models - -Define your domain models such that they implement `IIdentifiable`. -The easiest way to do this is to inherit `Identifiable`: - -```csharp -public class Person : Identifiable -{ - [Attr("name")] - public string Name { get; set; } -} -``` - -### DbContext - -Nothing special here, just an ordinary DbContext - -```csharp -public class AppDbContext : DbContext -{ - public AppDbContext(DbContextOptions options) - : base(options) { } - - public DbSet People { get; set; } -} -``` - -### Controllers - -You need to create controllers that inherit from `JsonApiController` or `JsonApiController` -where `TEntity` is the model that inherits from `Identifiable`. - -```csharp -public class PeopleController : JsonApiController -{ - public PeopleController( - IJsonApiContext jsonApiContext, - IResourceService resourceService, - ILoggerFactory loggerFactory) - : base(jsonApiContext, resourceService, loggerFactory) - { } -} -``` - -### Middleware and Services - -Finally, add the services by adding the following to your -`Startup.ConfigureServices`: - -```csharp -public IServiceProvider ConfigureServices(IServiceCollection services) -{ - // add the db context like you normally would - services.AddDbContext(options => - { // use whatever provider you want, this is just an example - options.UseNpgsql(GetDbConnectionString()); - }, ServiceLifetime.Transient); - - // add jsonapi dotnet core - services.AddJsonApi(); - // ... -} -``` - -Add the middleware to the `Startup.Configure` method. -Note that under the hood, this will call `app.UseMvc()` -so there is no need to add that as well. - -```csharp -public void Configure(IApplicationBuilder app) -{ - app.UseJsonApi(); -} -``` - -### Seeding the Database - -One way to seed the database is in your Configure method: - -```csharp -public void Configure( - IApplicationBuilder app, - AppDbContext context) -{ - context.Database.EnsureCreated(); - if(context.People.Count == 0) - { - context.People.Add(new Person { - Name = "John Doe" - }); - context.SaveChanges(); - } - // ... - app.UseJsonApi(); -} -``` - -### Run Migrations - -``` -$ dotnet ef migrations add AddPeople -$ dotnet ef database update -``` - -### Start the App - -``` -$ dotnet run -$ curl http://localhost:5000/people -``` diff --git a/docs/service_table.png b/docs/service_table.png deleted file mode 100644 index d6ae611370..0000000000 Binary files a/docs/service_table.png and /dev/null differ