Skip to content

Commit 1268c3f

Browse files
committed
feat(controller): PATCH and DELETE
1 parent b042d4b commit 1268c3f

File tree

9 files changed

+115
-68
lines changed

9 files changed

+115
-68
lines changed

src/JsonApiDotNetCore/Controllers/JsonApiController.cs

Lines changed: 51 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,17 @@
99

1010
namespace JsonApiDotNetCore.Controllers
1111
{
12-
public class JsonApiController<T> : Controller where T : class, IIdentifiable<int>
12+
public class JsonApiController<T> : JsonApiController<T, int> where T : class, IIdentifiable<int>
13+
{
14+
public JsonApiController(
15+
ILoggerFactory loggerFactory,
16+
DbContext context,
17+
IJsonApiContext jsonApiContext)
18+
: base(loggerFactory, context, jsonApiContext)
19+
{ }
20+
}
21+
22+
public class JsonApiController<T, TId> : Controller where T : class, IIdentifiable<TId>
1323
{
1424
private readonly DbContext _context;
1525
private readonly DbSet<T> _dbSet;
@@ -25,8 +35,8 @@ public JsonApiController(
2535
_dbSet = context.GetDbSet<T>();
2636
_jsonApiContext = jsonApiContext;
2737

28-
_logger = loggerFactory.CreateLogger<JsonApiController<T>>();
29-
_logger.LogInformation($@"JsonApiController activated with ContextGraph:
38+
_logger = loggerFactory.CreateLogger<JsonApiController<T, TId>>();
39+
_logger.LogTrace($@"JsonApiController activated with ContextGraph:
3040
{JsonConvert.SerializeObject(jsonApiContext.ContextGraph)}");
3141
}
3242

@@ -42,15 +52,14 @@ public JsonApiController(
4252
[HttpGet]
4353
public virtual IActionResult Get()
4454
{
45-
_logger.LogInformation("");
4655
var entities = _dbSet.ToList();
4756
return Ok(entities);
4857
}
4958

5059
[HttpGet("{id}")]
51-
public virtual IActionResult Get(int id)
60+
public virtual IActionResult Get(TId id)
5261
{
53-
var entity = _dbSet.FirstOrDefault(e => e.Id == id);
62+
var entity = _dbSet.FirstOrDefault(e => e.Id.Equals(id));
5463

5564
if(entity == null)
5665
return NotFound();
@@ -59,7 +68,7 @@ public virtual IActionResult Get(int id)
5968
}
6069

6170
[HttpGet("{id}/{relationshipName}")]
62-
public virtual IActionResult GetRelationship(int id, string relationshipName)
71+
public virtual IActionResult GetRelationship(TId id, string relationshipName)
6372
{
6473
relationshipName = _jsonApiContext.ContextGraph.GetRelationshipName<T>(relationshipName);
6574

@@ -68,7 +77,7 @@ public virtual IActionResult GetRelationship(int id, string relationshipName)
6877

6978
var entity = _dbSet
7079
.Include(relationshipName)
71-
.FirstOrDefault(e => e.Id == id);
80+
.FirstOrDefault(e => e.Id.Equals(id));
7281

7382
if(entity == null)
7483
return NotFound();
@@ -99,26 +108,47 @@ public virtual IActionResult Post([FromBody] T entity)
99108
[HttpPatch("{id}")]
100109
public virtual IActionResult Patch(int id, [FromBody] T entity)
101110
{
111+
if(entity == null)
112+
return BadRequest();
102113

103-
return Ok("Patch Id");
104-
}
114+
var oldEntity = _dbSet.FirstOrDefault(e => e.Id.Equals(id));
115+
if(oldEntity == null)
116+
return NotFound();
105117

106-
[HttpPatch("{id}/{relationship}")]
107-
public virtual IActionResult PatchRelationship(int id, string relation)
108-
{
109-
return Ok("Patch Id/relationship");
118+
var requestEntity = _jsonApiContext.RequestEntity;
119+
120+
requestEntity.Attributes.ForEach(attr => {
121+
attr.SetValue(oldEntity, attr.GetValue(entity));
122+
});
123+
124+
_context.SaveChanges();
125+
126+
return Ok(oldEntity);
110127
}
111128

129+
// [HttpPatch("{id}/{relationship}")]
130+
// public virtual IActionResult PatchRelationship(int id, string relation)
131+
// {
132+
// return Ok("Patch Id/relationship");
133+
// }
134+
112135
[HttpDelete("{id}")]
113-
public virtual IActionResult Delete(int id)
136+
public virtual IActionResult Delete(TId id)
114137
{
115-
return Ok("Delete Id");
138+
var entity = _dbSet.FirstOrDefault(e => e.Id.Equals(id));
139+
if(entity == null)
140+
return NotFound();
141+
142+
_dbSet.Remove(entity);
143+
_context.SaveChanges();
144+
145+
return Ok();
116146
}
117147

118-
[HttpDelete("{id}/{relationship}")]
119-
public virtual IActionResult Delete(int id, string relation)
120-
{
121-
return Ok("Delete Id/relationship");
122-
}
148+
// [HttpDelete("{id}/{relationship}")]
149+
// public virtual IActionResult Delete(int id, string relation)
150+
// {
151+
// return Ok("Delete Id/relationship");
152+
// }
123153
}
124154
}

src/JsonApiDotNetCore/Formatters/JsonApiInputFormatter.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,8 @@ public Task<InputFormatterResult> ReadAsync(InputFormatterContext context)
3636
try
3737
{
3838
var body = GetRequestBody(context.HttpContext.Request.Body);
39-
var contextGraph = context.HttpContext.RequestServices.GetService<IJsonApiContext>().ContextGraph;
40-
var model = JsonApiDeSerializer.Deserialize(body, contextGraph);
39+
var jsonApiContext = context.HttpContext.RequestServices.GetService<IJsonApiContext>();
40+
var model = JsonApiDeSerializer.Deserialize(body, jsonApiContext);
4141

4242
return InputFormatterResult.SuccessAsync(model);
4343
}

src/JsonApiDotNetCore/Formatters/JsonApiOutputFormatter.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ public async Task WriteAsync(OutputFormatterWriteContext context)
2727
throw new ArgumentNullException(nameof(context));
2828

2929
var response = context.HttpContext.Response;
30-
30+
3131
using (var writer = context.WriterFactory(response.Body, Encoding.UTF8))
3232
{
3333
var contextGraph = context.HttpContext.RequestServices.GetService<IJsonApiContext>().ContextGraph;

src/JsonApiDotNetCore/Internal/AttrAttribute.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,5 +20,16 @@ public object GetValue(object entity)
2020
.GetProperty(InternalAttributeName)
2121
.GetValue(entity);
2222
}
23+
24+
public void SetValue(object entity, object newValue)
25+
{
26+
var propertyInfo = entity
27+
.GetType()
28+
.GetProperty(InternalAttributeName);
29+
30+
var convertedValue = Convert.ChangeType(newValue, propertyInfo.PropertyType);
31+
32+
propertyInfo.SetValue(entity, convertedValue);
33+
}
2334
}
2435
}

src/JsonApiDotNetCore/Serialization/JsonApiDeSerializer.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,19 +5,21 @@
55
using JsonApiDotNetCore.Extensions;
66
using JsonApiDotNetCore.Internal;
77
using JsonApiDotNetCore.Models;
8+
using JsonApiDotNetCore.Services;
89
using Newtonsoft.Json;
910

1011
namespace JsonApiDotNetCore.Serialization
1112
{
1213
public static class JsonApiDeSerializer
1314
{
14-
public static object Deserialize(string requestBody, IContextGraph contextGraph)
15+
public static object Deserialize(string requestBody, IJsonApiContext context)
1516
{
1617
var document = JsonConvert.DeserializeObject<Document>(requestBody);
1718

1819
var entityTypeName = document.Data.Type.ToProperCase();
1920

20-
var contextEntity = contextGraph.GetContextEntity(entityTypeName);
21+
var contextEntity = context.ContextGraph.GetContextEntity(entityTypeName);
22+
context.RequestEntity = contextEntity;
2123

2224
var entity = Activator.CreateInstance(contextEntity.EntityType);
2325

src/JsonApiDotNetCore/Services/IJsonApiContext.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,6 @@ namespace JsonApiDotNetCore.Services
55
public interface IJsonApiContext
66
{
77
IContextGraph ContextGraph { get; set; }
8+
ContextEntity RequestEntity { get; set; }
89
}
910
}

src/JsonApiDotNetCore/Services/JsonApiContext.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ namespace JsonApiDotNetCore.Services
44
{
55
public class JsonApiContext : IJsonApiContext
66
{
7+
public ContextEntity RequestEntity { get; set; }
78
public IContextGraph ContextGraph { get; set; }
89
}
910
}
Lines changed: 41 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,41 @@
1-
# Welcome to ASP.NET Core
2-
3-
We've made some big updates in this release, so it’s **important** that you spend a few minutes to learn what’s new.
4-
5-
You've created a new ASP.NET Core project. [Learn what's new](https://go.microsoft.com/fwlink/?LinkId=518016)
6-
7-
## This application consists of:
8-
9-
* Sample pages using ASP.NET Core MVC
10-
* [Bower](https://go.microsoft.com/fwlink/?LinkId=518004) for managing client-side libraries
11-
* Theming using [Bootstrap](https://go.microsoft.com/fwlink/?LinkID=398939)
12-
13-
## How to
14-
15-
* [Add a Controller and View](https://go.microsoft.com/fwlink/?LinkID=398600)
16-
* [Add an appsetting in config and access it in app.](https://go.microsoft.com/fwlink/?LinkID=699562)
17-
* [Manage User Secrets using Secret Manager.](https://go.microsoft.com/fwlink/?LinkId=699315)
18-
* [Use logging to log a message.](https://go.microsoft.com/fwlink/?LinkId=699316)
19-
* [Add packages using NuGet.](https://go.microsoft.com/fwlink/?LinkId=699317)
20-
* [Add client packages using Bower.](https://go.microsoft.com/fwlink/?LinkId=699318)
21-
* [Target development, staging or production environment.](https://go.microsoft.com/fwlink/?LinkId=699319)
22-
23-
## Overview
24-
25-
* [Conceptual overview of what is ASP.NET Core](https://go.microsoft.com/fwlink/?LinkId=518008)
26-
* [Fundamentals of ASP.NET Core such as Startup and middleware.](https://go.microsoft.com/fwlink/?LinkId=699320)
27-
* [Working with Data](https://go.microsoft.com/fwlink/?LinkId=398602)
28-
* [Security](https://go.microsoft.com/fwlink/?LinkId=398603)
29-
* [Client side development](https://go.microsoft.com/fwlink/?LinkID=699321)
30-
* [Develop on different platforms](https://go.microsoft.com/fwlink/?LinkID=699322)
31-
* [Read more on the documentation site](https://go.microsoft.com/fwlink/?LinkID=699323)
32-
33-
## Run & Deploy
34-
35-
* [Run your app](https://go.microsoft.com/fwlink/?LinkID=517851)
36-
* [Run tools such as EF migrations and more](https://go.microsoft.com/fwlink/?LinkID=517853)
37-
* [Publish to Microsoft Azure Web Apps](https://go.microsoft.com/fwlink/?LinkID=398609)
38-
39-
We would love to hear your [feedback](https://go.microsoft.com/fwlink/?LinkId=518015)
1+
# Task List
2+
3+
- [x] Add inbound serialization formatting
4+
- [x] Add POST
5+
- [x] Add PATCH
6+
- [ ] Add DELETE
7+
- [ ] Add Relationships
8+
- [ ] Add support for authorization/context-scoping middleware
9+
- [ ] BadRequest should be 422 in POST
10+
- [ ] Add integration tests to example project
11+
12+
## Usage
13+
14+
- Add Middleware
15+
- Define Models
16+
- Define Controllers
17+
18+
## Defining Models
19+
20+
## Defining Controllers
21+
22+
```
23+
```
24+
25+
#### Non-Integer Type Keys
26+
27+
If your model is using a type other than `int` for the primary key,
28+
you should explicitly declare it in the controller generic:
29+
30+
```
31+
[Route("api/[controller]")]
32+
public class ThingsController : JsonApiController<Person, Guid>
33+
{
34+
public ThingsController(
35+
ILoggerFactory loggerFactory,
36+
AppDbContext context,
37+
IJsonApiContext jsonApiContext)
38+
: base(loggerFactory, context, jsonApiContext)
39+
{ }
40+
}
41+
```

src/JsonApiDotNetCoreExample/appsettings.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@
55
"Logging": {
66
"IncludeScopes": false,
77
"LogLevel": {
8-
"Default": "Debug",
9-
"System": "Information",
10-
"Microsoft": "Information"
8+
"Default": "Trace",
9+
"System": "Trace",
10+
"Microsoft": "Trace"
1111
}
1212
}
1313
}

0 commit comments

Comments
 (0)