Skip to content

Commit 54575d7

Browse files
authored
Merge branch 'unstable' into master
2 parents 94b6a62 + f8a7ac2 commit 54575d7

25 files changed

+399
-158
lines changed
Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
using System.Collections.Generic;
2+
using System.Threading.Tasks;
3+
using JsonApiDotNetCore.Internal;
4+
using JsonApiDotNetCore.Models;
5+
using JsonApiDotNetCore.Services;
6+
using Microsoft.AspNetCore.Mvc;
7+
using Microsoft.Extensions.Logging;
8+
9+
namespace JsonApiDotNetCore.Controllers
10+
{
11+
public class BaseJsonApiController<T, TId>
12+
: JsonApiControllerMixin
13+
where T : class, IIdentifiable<TId>
14+
{
15+
private readonly IResourceQueryService<T, TId> _queryService;
16+
private readonly IResourceCmdService<T, TId> _cmdService;
17+
private readonly IJsonApiContext _jsonApiContext;
18+
19+
protected BaseJsonApiController(
20+
IJsonApiContext jsonApiContext,
21+
IResourceService<T, TId> resourceService)
22+
{
23+
_jsonApiContext = jsonApiContext.ApplyContext<T>();
24+
_queryService = resourceService;
25+
_cmdService = resourceService;
26+
}
27+
28+
protected BaseJsonApiController(
29+
IJsonApiContext jsonApiContext,
30+
IResourceQueryService<T, TId> queryService)
31+
{
32+
_jsonApiContext = jsonApiContext.ApplyContext<T>();
33+
_queryService = queryService;
34+
}
35+
36+
protected BaseJsonApiController(
37+
IJsonApiContext jsonApiContext,
38+
IResourceCmdService<T, TId> cmdService)
39+
{
40+
_jsonApiContext = jsonApiContext.ApplyContext<T>();
41+
_cmdService = cmdService;
42+
}
43+
44+
public virtual async Task<IActionResult> GetAsync()
45+
{
46+
if (_queryService == null) throw new JsonApiException(405, "Query requests are not supported");
47+
48+
var entities = await _queryService.GetAsync();
49+
50+
return Ok(entities);
51+
}
52+
53+
public virtual async Task<IActionResult> GetAsync(TId id)
54+
{
55+
if (_queryService == null) throw new JsonApiException(405, "Query requests are not supported");
56+
57+
var entity = await _queryService.GetAsync(id);
58+
59+
if (entity == null)
60+
return NotFound();
61+
62+
return Ok(entity);
63+
}
64+
65+
public virtual async Task<IActionResult> GetRelationshipsAsync(TId id, string relationshipName)
66+
{
67+
if (_queryService == null) throw new JsonApiException(405, "Query requests are not supported");
68+
69+
var relationship = await _queryService.GetRelationshipsAsync(id, relationshipName);
70+
if (relationship == null)
71+
return NotFound();
72+
73+
return Ok(relationship);
74+
}
75+
76+
public virtual async Task<IActionResult> GetRelationshipAsync(TId id, string relationshipName)
77+
{
78+
if (_queryService == null) throw new JsonApiException(405, "Query requests are not supported");
79+
80+
var relationship = await _queryService.GetRelationshipAsync(id, relationshipName);
81+
82+
return Ok(relationship);
83+
}
84+
85+
public virtual async Task<IActionResult> PostAsync([FromBody] T entity)
86+
{
87+
if (_cmdService == null) throw new JsonApiException(405, "Command requests are not supported");
88+
89+
if (entity == null)
90+
return UnprocessableEntity();
91+
92+
if (!_jsonApiContext.Options.AllowClientGeneratedIds && !string.IsNullOrEmpty(entity.StringId))
93+
return Forbidden();
94+
95+
entity = await _cmdService.CreateAsync(entity);
96+
97+
return Created($"{HttpContext.Request.Path}/{entity.Id}", entity);
98+
}
99+
100+
public virtual async Task<IActionResult> PatchAsync(TId id, [FromBody] T entity)
101+
{
102+
if (_cmdService == null) throw new JsonApiException(405, "Command requests are not supported");
103+
104+
if (entity == null)
105+
return UnprocessableEntity();
106+
107+
var updatedEntity = await _cmdService.UpdateAsync(id, entity);
108+
109+
if (updatedEntity == null)
110+
return NotFound();
111+
112+
return Ok(updatedEntity);
113+
}
114+
115+
public virtual async Task<IActionResult> PatchRelationshipsAsync(TId id, string relationshipName, [FromBody] List<DocumentData> relationships)
116+
{
117+
if (_cmdService == null) throw new JsonApiException(405, "Command requests are not supported");
118+
119+
await _cmdService.UpdateRelationshipsAsync(id, relationshipName, relationships);
120+
121+
return Ok();
122+
}
123+
124+
public virtual async Task<IActionResult> DeleteAsync(TId id)
125+
{
126+
if (_cmdService == null) throw new JsonApiException(405, "Command requests are not supported");
127+
128+
var wasDeleted = await _cmdService.DeleteAsync(id);
129+
130+
if (!wasDeleted)
131+
return NotFound();
132+
133+
return NoContent();
134+
}
135+
}
136+
}

src/JsonApiDotNetCore/Controllers/HttpMethodRestrictionFilter.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ public override async Task OnActionExecutionAsync(
1919
var method = context.HttpContext.Request.Method;
2020

2121
if(CanExecuteAction(method) == false)
22-
throw new JsonApiException("405", $"This resource does not support {method} requests.");
22+
throw new JsonApiException(405, $"This resource does not support {method} requests.");
2323

2424
await next();
2525
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
using System.Collections.Generic;
2+
using System.Threading.Tasks;
3+
using JsonApiDotNetCore.Models;
4+
using JsonApiDotNetCore.Services;
5+
using Microsoft.AspNetCore.Mvc;
6+
using Microsoft.Extensions.Logging;
7+
8+
namespace JsonApiDotNetCore.Controllers
9+
{
10+
public class JsonApiCmdController<T>
11+
: JsonApiCmdController<T, int> where T : class, IIdentifiable<int>
12+
{
13+
public JsonApiCmdController(
14+
IJsonApiContext jsonApiContext,
15+
IResourceService<T, int> resourceService)
16+
: base(jsonApiContext, resourceService)
17+
{ }
18+
}
19+
20+
public class JsonApiCmdController<T, TId>
21+
: BaseJsonApiController<T, TId> where T : class, IIdentifiable<TId>
22+
{
23+
public JsonApiCmdController(
24+
IJsonApiContext jsonApiContext,
25+
IResourceService<T, TId> resourceService)
26+
: base(jsonApiContext, resourceService)
27+
{ }
28+
29+
[HttpPost]
30+
public override async Task<IActionResult> PostAsync([FromBody] T entity)
31+
=> await base.PostAsync(entity);
32+
33+
[HttpPatch("{id}")]
34+
public override async Task<IActionResult> PatchAsync(TId id, [FromBody] T entity)
35+
=> await base.PatchAsync(id, entity);
36+
37+
[HttpPatch("{id}/relationships/{relationshipName}")]
38+
public override async Task<IActionResult> PatchRelationshipsAsync(
39+
TId id, string relationshipName, [FromBody] List<DocumentData> relationships)
40+
=> await base.PatchRelationshipsAsync(id, relationshipName, relationships);
41+
42+
[HttpDelete("{id}")]
43+
public override async Task<IActionResult> DeleteAsync(TId id) => await base.DeleteAsync(id);
44+
}
45+
}

src/JsonApiDotNetCore/Controllers/JsonApiController.cs

Lines changed: 20 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -19,109 +19,49 @@ public JsonApiController(
1919
}
2020

2121
public class JsonApiController<T, TId>
22-
: JsonApiControllerMixin where T : class, IIdentifiable<TId>
22+
: BaseJsonApiController<T, TId> where T : class, IIdentifiable<TId>
2323
{
24-
private readonly ILogger _logger;
25-
private readonly IResourceService<T, TId> _resourceService;
26-
private readonly IJsonApiContext _jsonApiContext;
27-
2824
public JsonApiController(
2925
IJsonApiContext jsonApiContext,
3026
IResourceService<T, TId> resourceService,
31-
ILoggerFactory loggerFactory)
32-
{
33-
_jsonApiContext = jsonApiContext.ApplyContext<T>();
34-
_resourceService = resourceService;
35-
_logger = loggerFactory.CreateLogger<JsonApiController<T, TId>>();
36-
}
27+
ILoggerFactory loggerFactory)
28+
: base(jsonApiContext, resourceService)
29+
{ }
3730

3831
public JsonApiController(
3932
IJsonApiContext jsonApiContext,
4033
IResourceService<T, TId> resourceService)
41-
{
42-
_jsonApiContext = jsonApiContext.ApplyContext<T>();
43-
_resourceService = resourceService;
44-
}
34+
: base(jsonApiContext, resourceService)
35+
{ }
4536

4637
[HttpGet]
47-
public virtual async Task<IActionResult> GetAsync()
48-
{
49-
var entities = await _resourceService.GetAsync();
50-
return Ok(entities);
51-
}
38+
public override async Task<IActionResult> GetAsync() => await base.GetAsync();
5239

5340
[HttpGet("{id}")]
54-
public virtual async Task<IActionResult> GetAsync(TId id)
55-
{
56-
var entity = await _resourceService.GetAsync(id);
57-
58-
if (entity == null)
59-
return NotFound();
60-
61-
return Ok(entity);
62-
}
41+
public override async Task<IActionResult> GetAsync(TId id) => await base.GetAsync(id);
6342

6443
[HttpGet("{id}/relationships/{relationshipName}")]
65-
public virtual async Task<IActionResult> GetRelationshipsAsync(TId id, string relationshipName)
66-
{
67-
var relationship = await _resourceService.GetRelationshipsAsync(id, relationshipName);
68-
if(relationship == null)
69-
return NotFound();
70-
71-
return Ok(relationship);
72-
}
44+
public override async Task<IActionResult> GetRelationshipsAsync(TId id, string relationshipName)
45+
=> await base.GetRelationshipsAsync(id, relationshipName);
7346

7447
[HttpGet("{id}/{relationshipName}")]
75-
public virtual async Task<IActionResult> GetRelationshipAsync(TId id, string relationshipName)
76-
{
77-
var relationship = await _resourceService.GetRelationshipAsync(id, relationshipName);
78-
return Ok(relationship);
79-
}
48+
public override async Task<IActionResult> GetRelationshipAsync(TId id, string relationshipName)
49+
=> await base.GetRelationshipAsync(id, relationshipName);
8050

8151
[HttpPost]
82-
public virtual async Task<IActionResult> PostAsync([FromBody] T entity)
83-
{
84-
if (entity == null)
85-
return UnprocessableEntity();
86-
87-
if (!_jsonApiContext.Options.AllowClientGeneratedIds && !string.IsNullOrEmpty(entity.StringId))
88-
return Forbidden();
89-
90-
entity = await _resourceService.CreateAsync(entity);
91-
92-
return Created($"{HttpContext.Request.Path}/{entity.Id}", entity);
93-
}
52+
public override async Task<IActionResult> PostAsync([FromBody] T entity)
53+
=> await base.PostAsync(entity);
9454

9555
[HttpPatch("{id}")]
96-
public virtual async Task<IActionResult> PatchAsync(TId id, [FromBody] T entity)
97-
{
98-
if (entity == null)
99-
return UnprocessableEntity();
100-
101-
var updatedEntity = await _resourceService.UpdateAsync(id, entity);
102-
103-
if(updatedEntity == null)
104-
return NotFound();
105-
106-
return Ok(updatedEntity);
107-
}
56+
public override async Task<IActionResult> PatchAsync(TId id, [FromBody] T entity)
57+
=> await base.PatchAsync(id, entity);
10858

10959
[HttpPatch("{id}/relationships/{relationshipName}")]
110-
public virtual async Task<IActionResult> PatchRelationshipsAsync(TId id, string relationshipName, [FromBody] List<DocumentData> relationships)
111-
{
112-
await _resourceService.UpdateRelationshipsAsync(id, relationshipName, relationships);
113-
return Ok();
114-
}
60+
public override async Task<IActionResult> PatchRelationshipsAsync(
61+
TId id, string relationshipName, [FromBody] List<DocumentData> relationships)
62+
=> await base.PatchRelationshipsAsync(id, relationshipName, relationships);
11563

11664
[HttpDelete("{id}")]
117-
public virtual async Task<IActionResult> DeleteAsync(TId id)
118-
{
119-
var wasDeleted = await _resourceService.DeleteAsync(id);
120-
121-
if (!wasDeleted)
122-
return NotFound();
123-
124-
return NoContent();
125-
}
65+
public override async Task<IActionResult> DeleteAsync(TId id) => await base.DeleteAsync(id);
12666
}
12767
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
using System.Collections.Generic;
2+
using System.Threading.Tasks;
3+
using JsonApiDotNetCore.Models;
4+
using JsonApiDotNetCore.Services;
5+
using Microsoft.AspNetCore.Mvc;
6+
using Microsoft.Extensions.Logging;
7+
8+
namespace JsonApiDotNetCore.Controllers
9+
{
10+
public class JsonApiQueryController<T>
11+
: JsonApiQueryController<T, int> where T : class, IIdentifiable<int>
12+
{
13+
public JsonApiQueryController(
14+
IJsonApiContext jsonApiContext,
15+
IResourceService<T, int> resourceService)
16+
: base(jsonApiContext, resourceService)
17+
{ }
18+
}
19+
20+
public class JsonApiQueryController<T, TId>
21+
: BaseJsonApiController<T, TId> where T : class, IIdentifiable<TId>
22+
{
23+
public JsonApiQueryController(
24+
IJsonApiContext jsonApiContext,
25+
IResourceService<T, TId> resourceService)
26+
: base(jsonApiContext, resourceService)
27+
{ }
28+
29+
[HttpGet]
30+
public override async Task<IActionResult> GetAsync() => await base.GetAsync();
31+
32+
[HttpGet("{id}")]
33+
public override async Task<IActionResult> GetAsync(TId id) => await base.GetAsync(id);
34+
35+
[HttpGet("{id}/relationships/{relationshipName}")]
36+
public override async Task<IActionResult> GetRelationshipsAsync(TId id, string relationshipName)
37+
=> await base.GetRelationshipsAsync(id, relationshipName);
38+
39+
[HttpGet("{id}/{relationshipName}")]
40+
public override async Task<IActionResult> GetRelationshipAsync(TId id, string relationshipName)
41+
=> await base.GetRelationshipAsync(id, relationshipName);
42+
}
43+
}

src/JsonApiDotNetCore/Data/DefaultEntityRepository.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,7 @@ public virtual IQueryable<TEntity> Include(IQueryable<TEntity> entities, string
170170
if(relationship != null)
171171
return entities.Include(relationship.InternalRelationshipName);
172172

173-
throw new JsonApiException("400", $"Invalid relationship {relationshipName} on {entity.EntityName}",
173+
throw new JsonApiException(400, $"Invalid relationship {relationshipName} on {entity.EntityName}",
174174
$"{entity.EntityName} does not have a relationship named {relationshipName}");
175175
}
176176

0 commit comments

Comments
 (0)