Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
86311d9
feat(*): interface segregation
jaredcnance Jun 12, 2017
f8a7ac2
Merge branch 'feat/cqrs' into unstable
jaredcnance Jun 12, 2017
54575d7
Merge branch 'unstable' into master
jaredcnance Jun 14, 2017
40ffa82
Merge pull request #133 from Research-Institute/master
jaredcnance Jun 14, 2017
60f7713
Merge pull request #134 from Research-Institute/master
jaredcnance Jun 14, 2017
46f2d07
feat(serialization): improve support for complex attrs
jaredcnance Jun 13, 2017
3de6d21
fix(typeHelper): handle complex types
jaredcnance Jun 23, 2017
deb57df
feat(services): complete interface segregation
jaredcnance Jun 25, 2017
fc7f702
chore(examples): move projects under examples directory
jaredcnance Jun 25, 2017
504dfa1
feat(reports): add reports example
jaredcnance Jun 25, 2017
18ae7c8
Merge branch 'feat/#125' into unstable
jaredcnance Jun 25, 2017
d804628
chore(#117): remove deprecated constructor
jaredcnance Jun 25, 2017
59fc512
feat(#129): optionally disable links
jaredcnance Jun 25, 2017
c131839
feat(#130): disable query params
jaredcnance Jun 27, 2017
c08fbe0
feat(#128): immutable attributes
jaredcnance Jun 28, 2017
ee0025f
feat(#139): handle empty strings in type helper
jaredcnance Jun 28, 2017
a894f69
feat(#138): improved exception handling
jaredcnance Jun 28, 2017
6ed2a4f
test(base-controller): add unit tests
jaredcnance Jul 2, 2017
e792b8e
Merge pull request #140 from Research-Institute/unstable
jaredcnance Jul 2, 2017
b46d299
add documentation
jaredcnance Jul 2, 2017
93b063e
add documentation
jaredcnance Jul 2, 2017
6e92a9f
fix(#126): implicitly add db context to context graph
jaredcnance Jul 2, 2017
ad8787e
fix(ctx-graph-builder): set link flags to prevent ordering issues
jaredcnance Jul 2, 2017
File filter

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
feat(*): interface segregation
  • Loading branch information
jaredcnance committed Jun 12, 2017
commit 86311d96c1a5b29053eb3e63b3aef9d5d8309b6c
136 changes: 136 additions & 0 deletions src/JsonApiDotNetCore/Controllers/BaseJsonApiController.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using JsonApiDotNetCore.Internal;
using JsonApiDotNetCore.Models;
using JsonApiDotNetCore.Services;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;

namespace JsonApiDotNetCore.Controllers
{
public class BaseJsonApiController<T, TId>
: JsonApiControllerMixin
where T : class, IIdentifiable<TId>
{
private readonly IResourceQueryService<T, TId> _queryService;
private readonly IResourceCmdService<T, TId> _cmdService;
private readonly IJsonApiContext _jsonApiContext;

protected BaseJsonApiController(
IJsonApiContext jsonApiContext,
IResourceService<T, TId> resourceService)
{
_jsonApiContext = jsonApiContext.ApplyContext<T>();
_queryService = resourceService;
_cmdService = resourceService;
}

protected BaseJsonApiController(
IJsonApiContext jsonApiContext,
IResourceQueryService<T, TId> queryService)
{
_jsonApiContext = jsonApiContext.ApplyContext<T>();
_queryService = queryService;
}

protected BaseJsonApiController(
IJsonApiContext jsonApiContext,
IResourceCmdService<T, TId> cmdService)
{
_jsonApiContext = jsonApiContext.ApplyContext<T>();
_cmdService = cmdService;
}

public virtual async Task<IActionResult> GetAsync()
{
if (_queryService == null) throw new JsonApiException(405, "Query requests are not supported");

var entities = await _queryService.GetAsync();

return Ok(entities);
}

public virtual async Task<IActionResult> GetAsync(TId id)
{
if (_queryService == null) throw new JsonApiException(405, "Query requests are not supported");

var entity = await _queryService.GetAsync(id);

if (entity == null)
return NotFound();

return Ok(entity);
}

public virtual async Task<IActionResult> GetRelationshipsAsync(TId id, string relationshipName)
{
if (_queryService == null) throw new JsonApiException(405, "Query requests are not supported");

var relationship = await _queryService.GetRelationshipsAsync(id, relationshipName);
if (relationship == null)
return NotFound();

return Ok(relationship);
}

public virtual async Task<IActionResult> GetRelationshipAsync(TId id, string relationshipName)
{
if (_queryService == null) throw new JsonApiException(405, "Query requests are not supported");

var relationship = await _queryService.GetRelationshipAsync(id, relationshipName);

return Ok(relationship);
}

public virtual async Task<IActionResult> PostAsync([FromBody] T entity)
{
if (_cmdService == null) throw new JsonApiException(405, "Command requests are not supported");

if (entity == null)
return UnprocessableEntity();

if (!_jsonApiContext.Options.AllowClientGeneratedIds && !string.IsNullOrEmpty(entity.StringId))
return Forbidden();

entity = await _cmdService.CreateAsync(entity);

return Created($"{HttpContext.Request.Path}/{entity.Id}", entity);
}

public virtual async Task<IActionResult> PatchAsync(TId id, [FromBody] T entity)
{
if (_cmdService == null) throw new JsonApiException(405, "Command requests are not supported");

if (entity == null)
return UnprocessableEntity();

var updatedEntity = await _cmdService.UpdateAsync(id, entity);

if (updatedEntity == null)
return NotFound();

return Ok(updatedEntity);
}

public virtual async Task<IActionResult> PatchRelationshipsAsync(TId id, string relationshipName, [FromBody] List<DocumentData> relationships)
{
if (_cmdService == null) throw new JsonApiException(405, "Command requests are not supported");

await _cmdService.UpdateRelationshipsAsync(id, relationshipName, relationships);

return Ok();
}

public virtual async Task<IActionResult> DeleteAsync(TId id)
{
if (_cmdService == null) throw new JsonApiException(405, "Command requests are not supported");

var wasDeleted = await _cmdService.DeleteAsync(id);

if (!wasDeleted)
return NotFound();

return NoContent();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public override async Task OnActionExecutionAsync(
var method = context.HttpContext.Request.Method;

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

await next();
}
Expand Down
45 changes: 45 additions & 0 deletions src/JsonApiDotNetCore/Controllers/JsonApiCmdController.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using JsonApiDotNetCore.Models;
using JsonApiDotNetCore.Services;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;

namespace JsonApiDotNetCore.Controllers
{
public class JsonApiCmdController<T>
: JsonApiCmdController<T, int> where T : class, IIdentifiable<int>
{
public JsonApiCmdController(
IJsonApiContext jsonApiContext,
IResourceService<T, int> resourceService)
: base(jsonApiContext, resourceService)
{ }
}

public class JsonApiCmdController<T, TId>
: BaseJsonApiController<T, TId> where T : class, IIdentifiable<TId>
{
public JsonApiCmdController(
IJsonApiContext jsonApiContext,
IResourceService<T, TId> resourceService)
: base(jsonApiContext, resourceService)
{ }

[HttpPost]
public override async Task<IActionResult> PostAsync([FromBody] T entity)
=> await base.PostAsync(entity);

[HttpPatch("{id}")]
public override async Task<IActionResult> PatchAsync(TId id, [FromBody] T entity)
=> await base.PatchAsync(id, entity);

[HttpPatch("{id}/relationships/{relationshipName}")]
public override async Task<IActionResult> PatchRelationshipsAsync(
TId id, string relationshipName, [FromBody] List<DocumentData> relationships)
=> await base.PatchRelationshipsAsync(id, relationshipName, relationships);

[HttpDelete("{id}")]
public override async Task<IActionResult> DeleteAsync(TId id) => await base.DeleteAsync(id);
}
}
100 changes: 20 additions & 80 deletions src/JsonApiDotNetCore/Controllers/JsonApiController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,109 +19,49 @@ public JsonApiController(
}

public class JsonApiController<T, TId>
: JsonApiControllerMixin where T : class, IIdentifiable<TId>
: BaseJsonApiController<T, TId> where T : class, IIdentifiable<TId>
{
private readonly ILogger _logger;
private readonly IResourceService<T, TId> _resourceService;
private readonly IJsonApiContext _jsonApiContext;

public JsonApiController(
IJsonApiContext jsonApiContext,
IResourceService<T, TId> resourceService,
ILoggerFactory loggerFactory)
{
_jsonApiContext = jsonApiContext.ApplyContext<T>();
_resourceService = resourceService;
_logger = loggerFactory.CreateLogger<JsonApiController<T, TId>>();
}
ILoggerFactory loggerFactory)
: base(jsonApiContext, resourceService)
{ }

public JsonApiController(
IJsonApiContext jsonApiContext,
IResourceService<T, TId> resourceService)
{
_jsonApiContext = jsonApiContext.ApplyContext<T>();
_resourceService = resourceService;
}
: base(jsonApiContext, resourceService)
{ }

[HttpGet]
public virtual async Task<IActionResult> GetAsync()
{
var entities = await _resourceService.GetAsync();
return Ok(entities);
}
public override async Task<IActionResult> GetAsync() => await base.GetAsync();

[HttpGet("{id}")]
public virtual async Task<IActionResult> GetAsync(TId id)
{
var entity = await _resourceService.GetAsync(id);

if (entity == null)
return NotFound();

return Ok(entity);
}
public override async Task<IActionResult> GetAsync(TId id) => await base.GetAsync(id);

[HttpGet("{id}/relationships/{relationshipName}")]
public virtual async Task<IActionResult> GetRelationshipsAsync(TId id, string relationshipName)
{
var relationship = await _resourceService.GetRelationshipsAsync(id, relationshipName);
if(relationship == null)
return NotFound();

return Ok(relationship);
}
public override async Task<IActionResult> GetRelationshipsAsync(TId id, string relationshipName)
=> await base.GetRelationshipsAsync(id, relationshipName);

[HttpGet("{id}/{relationshipName}")]
public virtual async Task<IActionResult> GetRelationshipAsync(TId id, string relationshipName)
{
var relationship = await _resourceService.GetRelationshipAsync(id, relationshipName);
return Ok(relationship);
}
public override async Task<IActionResult> GetRelationshipAsync(TId id, string relationshipName)
=> await base.GetRelationshipAsync(id, relationshipName);

[HttpPost]
public virtual async Task<IActionResult> PostAsync([FromBody] T entity)
{
if (entity == null)
return UnprocessableEntity();

if (!_jsonApiContext.Options.AllowClientGeneratedIds && !string.IsNullOrEmpty(entity.StringId))
return Forbidden();

entity = await _resourceService.CreateAsync(entity);

return Created($"{HttpContext.Request.Path}/{entity.Id}", entity);
}
public override async Task<IActionResult> PostAsync([FromBody] T entity)
=> await base.PostAsync(entity);

[HttpPatch("{id}")]
public virtual async Task<IActionResult> PatchAsync(TId id, [FromBody] T entity)
{
if (entity == null)
return UnprocessableEntity();

var updatedEntity = await _resourceService.UpdateAsync(id, entity);

if(updatedEntity == null)
return NotFound();

return Ok(updatedEntity);
}
public override async Task<IActionResult> PatchAsync(TId id, [FromBody] T entity)
=> await base.PatchAsync(id, entity);

[HttpPatch("{id}/relationships/{relationshipName}")]
public virtual async Task<IActionResult> PatchRelationshipsAsync(TId id, string relationshipName, [FromBody] List<DocumentData> relationships)
{
await _resourceService.UpdateRelationshipsAsync(id, relationshipName, relationships);
return Ok();
}
public override async Task<IActionResult> PatchRelationshipsAsync(
TId id, string relationshipName, [FromBody] List<DocumentData> relationships)
=> await base.PatchRelationshipsAsync(id, relationshipName, relationships);

[HttpDelete("{id}")]
public virtual async Task<IActionResult> DeleteAsync(TId id)
{
var wasDeleted = await _resourceService.DeleteAsync(id);

if (!wasDeleted)
return NotFound();

return NoContent();
}
public override async Task<IActionResult> DeleteAsync(TId id) => await base.DeleteAsync(id);
}
}
43 changes: 43 additions & 0 deletions src/JsonApiDotNetCore/Controllers/JsonApiQueryController.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using JsonApiDotNetCore.Models;
using JsonApiDotNetCore.Services;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;

namespace JsonApiDotNetCore.Controllers
{
public class JsonApiQueryController<T>
: JsonApiQueryController<T, int> where T : class, IIdentifiable<int>
{
public JsonApiQueryController(
IJsonApiContext jsonApiContext,
IResourceService<T, int> resourceService)
: base(jsonApiContext, resourceService)
{ }
}

public class JsonApiQueryController<T, TId>
: BaseJsonApiController<T, TId> where T : class, IIdentifiable<TId>
{
public JsonApiQueryController(
IJsonApiContext jsonApiContext,
IResourceService<T, TId> resourceService)
: base(jsonApiContext, resourceService)
{ }

[HttpGet]
public override async Task<IActionResult> GetAsync() => await base.GetAsync();

[HttpGet("{id}")]
public override async Task<IActionResult> GetAsync(TId id) => await base.GetAsync(id);

[HttpGet("{id}/relationships/{relationshipName}")]
public override async Task<IActionResult> GetRelationshipsAsync(TId id, string relationshipName)
=> await base.GetRelationshipsAsync(id, relationshipName);

[HttpGet("{id}/{relationshipName}")]
public override async Task<IActionResult> GetRelationshipAsync(TId id, string relationshipName)
=> await base.GetRelationshipAsync(id, relationshipName);
}
}
2 changes: 1 addition & 1 deletion src/JsonApiDotNetCore/Data/DefaultEntityRepository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ public virtual IQueryable<TEntity> Include(IQueryable<TEntity> entities, string
if(relationship != null)
return entities.Include(relationship.InternalRelationshipName);

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

Expand Down
Loading