Skip to content

Commit f30f9b5

Browse files
Refactor API controllers and improve response handling
1 parent a543137 commit f30f9b5

27 files changed

+195
-247
lines changed

src/Modules/Grand.Module.Api/Attributes/EnableQueryAttribute.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using Microsoft.AspNetCore.Mvc;
33
using System.Linq.Dynamic.Core;
44
using Microsoft.AspNetCore.Http;
5+
using Grand.Module.Api.Constants;
56

67
namespace Grand.Module.Api.Attributes;
78

@@ -35,13 +36,12 @@ private IQueryable ApplyQueryOptions(IQueryable queryable, IQueryCollection quer
3536
queryable = queryable.Skip(skip);
3637

3738
if (query.TryGetValue("$top", out var topValue) && int.TryParse(topValue, out var top))
38-
queryable = queryable.Take(top);
39-
40-
if (query.TryGetValue("$count", out var countValue) && bool.TryParse(countValue, out var includeCount) && includeCount)
4139
{
42-
var totalCount = queryable.Count();
43-
response?.Headers?.Append("X-Total-Count", totalCount.ToString());
40+
top = Math.Min(top, Configurations.MaxLimit);
41+
queryable = queryable.Take(top);
4442
}
43+
else
44+
queryable = queryable.Take(Configurations.MaxLimit);
4545

4646
return queryable;
4747
}

src/Modules/Grand.Module.Api/Controllers/BaseApiController.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using Grand.Module.Api.Attributes;
2+
using Grand.Module.Api.Constants;
23
using Grand.Module.Api.Filters;
34
using Microsoft.AspNetCore.Authentication.JwtBearer;
45
using Microsoft.AspNetCore.Authorization;
@@ -9,6 +10,8 @@ namespace Grand.Module.Api.Controllers;
910
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
1011
[AuthorizeApiAdmin]
1112
[ServiceFilter(typeof(ModelValidationAttribute))]
13+
[Route($"{Configurations.RestRoutePrefix}/[controller]")]
14+
[ApiExplorerSettings(IgnoreApi = false, GroupName = "v1")]
1215
[Produces("application/json")]
1316
public abstract class BaseApiController : ControllerBase
1417
{

src/Modules/Grand.Module.Api/Controllers/BrandController.cs

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,11 @@
99
using Microsoft.AspNetCore.Mvc;
1010
using Swashbuckle.AspNetCore.Annotations;
1111
using System.Net;
12-
using Grand.Module.Api.Constants;
1312
using Microsoft.AspNetCore.Http;
1413
using Grand.Module.Api.Attributes;
1514

1615
namespace Grand.Module.Api.Controllers;
1716

18-
[Route($"{Configurations.RestRoutePrefix}/Brand")]
19-
[ApiExplorerSettings(IgnoreApi = false, GroupName = "v1")]
2017
public class BrandController : BaseApiController
2118
{
2219
private readonly IMediator _mediator;
@@ -44,7 +41,7 @@ public async Task<IActionResult> Get()
4441
[HttpGet("{key}")]
4542
[ProducesResponseType((int)HttpStatusCode.Forbidden)]
4643
[ProducesResponseType((int)HttpStatusCode.NotFound)]
47-
[ProducesResponseType((int)HttpStatusCode.OK)]
44+
[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(BrandDto))]
4845
public async Task<IActionResult> GetById([FromRoute] string key)
4946
{
5047
if (!await _permissionService.Authorize(PermissionSystemName.Brands)) return Forbid();
@@ -58,7 +55,7 @@ public async Task<IActionResult> GetById([FromRoute] string key)
5855
[SwaggerOperation("Add new entity to Brand", OperationId = "InsertBrand")]
5956
[HttpPost]
6057
[ProducesResponseType((int)HttpStatusCode.Forbidden)]
61-
[ProducesResponseType((int)HttpStatusCode.OK)]
58+
[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(BrandDto))]
6259
[ProducesResponseType((int)HttpStatusCode.BadRequest)]
6360
public async Task<IActionResult> Post([FromBody] BrandDto model)
6461
{
@@ -71,7 +68,7 @@ public async Task<IActionResult> Post([FromBody] BrandDto model)
7168
[SwaggerOperation("Update entity in Brand", OperationId = "UpdateBrand")]
7269
[HttpPut("{key}")]
7370
[ProducesResponseType((int)HttpStatusCode.Forbidden)]
74-
[ProducesResponseType((int)HttpStatusCode.OK)]
71+
[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(BrandDto))]
7572
[ProducesResponseType((int)HttpStatusCode.BadRequest)]
7673
[ProducesResponseType((int)HttpStatusCode.NotFound)]
7774
public async Task<IActionResult> Put([FromRoute] string key, [FromBody] BrandDto model)

src/Modules/Grand.Module.Api/Controllers/BrandLayoutController.cs

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,11 @@
77
using Microsoft.AspNetCore.Mvc;
88
using Swashbuckle.AspNetCore.Annotations;
99
using System.Net;
10-
using Grand.Module.Api.Constants;
1110
using Grand.Module.Api.Attributes;
11+
using Microsoft.AspNetCore.Http;
1212

1313
namespace Grand.Module.Api.Controllers;
1414

15-
[Route($"{Configurations.RestRoutePrefix}/BrandLayout")]
16-
[ApiExplorerSettings(IgnoreApi = false, GroupName = "v1")]
1715
public class BrandLayoutController : BaseApiController
1816
{
1917
private readonly IMediator _mediator;
@@ -28,9 +26,9 @@ public BrandLayoutController(IMediator mediator, IPermissionService permissionSe
2826
[SwaggerOperation("Get entity from BrandLayout by key", OperationId = "GetBrandLayoutById")]
2927
[HttpGet("{key}")]
3028
[ProducesResponseType((int)HttpStatusCode.Forbidden)]
31-
[ProducesResponseType((int)HttpStatusCode.OK)]
29+
[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(LayoutDto))]
3230
[ProducesResponseType((int)HttpStatusCode.NotFound)]
33-
public async Task<IActionResult> Get(string key)
31+
public async Task<IActionResult> Get([FromRoute] string key)
3432
{
3533
if (!await _permissionService.Authorize(PermissionSystemName.Maintenance)) return Forbid();
3634

@@ -44,7 +42,7 @@ public async Task<IActionResult> Get(string key)
4442
[HttpGet]
4543
[EnableQuery]
4644
[ProducesResponseType((int)HttpStatusCode.Forbidden)]
47-
[ProducesResponseType((int)HttpStatusCode.OK)]
45+
[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(IEnumerable<LayoutDto>))]
4846
public async Task<IActionResult> Get()
4947
{
5048
if (!await _permissionService.Authorize(PermissionSystemName.Maintenance)) return Forbid();

src/Modules/Grand.Module.Api/Controllers/CategoryController.cs

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,11 @@
99
using Microsoft.AspNetCore.Mvc;
1010
using Swashbuckle.AspNetCore.Annotations;
1111
using System.Net;
12-
using Grand.Module.Api.Constants;
1312
using Grand.Module.Api.Attributes;
13+
using Microsoft.AspNetCore.Http;
1414

1515
namespace Grand.Module.Api.Controllers;
1616

17-
[Route($"{Configurations.RestRoutePrefix}/Category")]
18-
[ApiExplorerSettings(IgnoreApi = false, GroupName = "v1")]
1917
public class CategoryController : BaseApiController
2018
{
2119
private readonly IMediator _mediator;
@@ -32,7 +30,7 @@ public CategoryController(
3230
[SwaggerOperation("Get entity from Category by key", OperationId = "GetCategoryById")]
3331
[HttpGet("{key}")]
3432
[ProducesResponseType((int)HttpStatusCode.Forbidden)]
35-
[ProducesResponseType((int)HttpStatusCode.OK)]
33+
[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(CategoryDto))]
3634
[ProducesResponseType((int)HttpStatusCode.NotFound)]
3735
public async Task<IActionResult> Get([FromRoute] string key)
3836
{
@@ -48,7 +46,7 @@ public async Task<IActionResult> Get([FromRoute] string key)
4846
[HttpGet]
4947
[EnableQuery]
5048
[ProducesResponseType((int)HttpStatusCode.Forbidden)]
51-
[ProducesResponseType((int)HttpStatusCode.OK)]
49+
[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(IEnumerable<CategoryDto>))]
5250
public async Task<IActionResult> Get()
5351
{
5452
if (!await _permissionService.Authorize(PermissionSystemName.Categories)) return Forbid();
@@ -59,7 +57,7 @@ public async Task<IActionResult> Get()
5957
[SwaggerOperation("Add new entity to Category", OperationId = "InsertCategory")]
6058
[HttpPost]
6159
[ProducesResponseType((int)HttpStatusCode.Forbidden)]
62-
[ProducesResponseType((int)HttpStatusCode.OK)]
60+
[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(CategoryDto))]
6361
[ProducesResponseType((int)HttpStatusCode.BadRequest)]
6462
public async Task<IActionResult> Post([FromBody] CategoryDto model)
6563
{
@@ -70,16 +68,16 @@ public async Task<IActionResult> Post([FromBody] CategoryDto model)
7068
}
7169

7270
[SwaggerOperation("Update entity in Category", OperationId = "UpdateCategory")]
73-
[HttpPut]
71+
[HttpPut("{key}")]
7472
[ProducesResponseType((int)HttpStatusCode.Forbidden)]
75-
[ProducesResponseType((int)HttpStatusCode.OK)]
73+
[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(CategoryDto))]
7674
[ProducesResponseType((int)HttpStatusCode.BadRequest)]
7775
[ProducesResponseType((int)HttpStatusCode.NotFound)]
78-
public async Task<IActionResult> Put([FromBody] CategoryDto model)
76+
public async Task<IActionResult> Put([FromRoute] string key, [FromBody] CategoryDto model)
7977
{
8078
if (!await _permissionService.Authorize(PermissionSystemName.Categories)) return Forbid();
8179

82-
var category = await _mediator.Send(new GetGenericQuery<CategoryDto, Category>(model.Id));
80+
var category = await _mediator.Send(new GetGenericQuery<CategoryDto, Category>(key));
8381
if (!category.Any()) return NotFound();
8482

8583
model = await _mediator.Send(new UpdateCategoryCommand { Model = model });
@@ -109,11 +107,11 @@ public async Task<IActionResult> Patch([FromRoute] string key, [FromBody] JsonPa
109107
}
110108

111109
[SwaggerOperation("Delete entity from Category", OperationId = "DeleteCategory")]
112-
[HttpDelete]
110+
[HttpDelete("{key}")]
113111
[ProducesResponseType((int)HttpStatusCode.Forbidden)]
114112
[ProducesResponseType((int)HttpStatusCode.OK)]
115113
[ProducesResponseType((int)HttpStatusCode.NotFound)]
116-
public async Task<IActionResult> Delete(string key)
114+
public async Task<IActionResult> Delete([FromRoute] string key)
117115
{
118116
if (!await _permissionService.Authorize(PermissionSystemName.Categories)) return Forbid();
119117

src/Modules/Grand.Module.Api/Controllers/CategoryLayoutController.cs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,11 @@
77
using Microsoft.AspNetCore.Mvc;
88
using Swashbuckle.AspNetCore.Annotations;
99
using System.Net;
10-
using Grand.Module.Api.Constants;
1110
using Grand.Module.Api.Attributes;
11+
using Microsoft.AspNetCore.Http;
1212

1313
namespace Grand.Module.Api.Controllers;
1414

15-
[Route($"{Configurations.RestRoutePrefix}/CategoryLayout")]
16-
[ApiExplorerSettings(IgnoreApi = false, GroupName = "v1")]
1715
public class CategoryLayoutController : BaseApiController
1816
{
1917
private readonly IMediator _mediator;
@@ -30,7 +28,7 @@ public CategoryLayoutController(
3028
[SwaggerOperation("Get entity from CategoryLayout by key", OperationId = "GetCategoryLayoutById")]
3129
[HttpGet("{key}")]
3230
[ProducesResponseType((int)HttpStatusCode.Forbidden)]
33-
[ProducesResponseType((int)HttpStatusCode.OK)]
31+
[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(LayoutDto))]
3432
[ProducesResponseType((int)HttpStatusCode.NotFound)]
3533
public async Task<IActionResult> Get([FromRoute] string key)
3634
{
@@ -46,7 +44,7 @@ public async Task<IActionResult> Get([FromRoute] string key)
4644
[HttpGet]
4745
[EnableQuery]
4846
[ProducesResponseType((int)HttpStatusCode.Forbidden)]
49-
[ProducesResponseType((int)HttpStatusCode.OK)]
47+
[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(IEnumerable<LayoutDto>))]
5048
public async Task<IActionResult> Get()
5149
{
5250
if (!await _permissionService.Authorize(PermissionSystemName.Maintenance)) return Forbid();

src/Modules/Grand.Module.Api/Controllers/CollectionController.cs

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
using Grand.Domain.Catalog;
33
using Grand.Domain.Permissions;
44
using Grand.Module.Api.Commands.Models.Catalog;
5-
using Grand.Module.Api.Constants;
65
using Grand.Module.Api.DTOs.Catalog;
76
using Grand.Module.Api.Attributes;
87
using Grand.Module.Api.Queries.Models.Common;
@@ -11,11 +10,10 @@
1110
using Microsoft.AspNetCore.Mvc;
1211
using Swashbuckle.AspNetCore.Annotations;
1312
using System.Net;
13+
using Microsoft.AspNetCore.Http;
1414

1515
namespace Grand.Module.Api.Controllers;
1616

17-
[Route($"{Configurations.RestRoutePrefix}/Collection")]
18-
[ApiExplorerSettings(IgnoreApi = false, GroupName = "v1")]
1917
public class CollectionController : BaseApiController
2018
{
2119
private readonly IMediator _mediator;
@@ -30,7 +28,7 @@ public CollectionController(IMediator mediator, IPermissionService permissionSer
3028
[SwaggerOperation("Get entity from Collection by key", OperationId = "GetCollectionById")]
3129
[HttpGet("{key}")]
3230
[ProducesResponseType((int)HttpStatusCode.Forbidden)]
33-
[ProducesResponseType((int)HttpStatusCode.OK)]
31+
[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(CollectionDto))]
3432
[ProducesResponseType((int)HttpStatusCode.NotFound)]
3533
public async Task<IActionResult> Get([FromRoute] string key)
3634
{
@@ -46,7 +44,7 @@ public async Task<IActionResult> Get([FromRoute] string key)
4644
[HttpGet]
4745
[EnableQuery]
4846
[ProducesResponseType((int)HttpStatusCode.Forbidden)]
49-
[ProducesResponseType((int)HttpStatusCode.OK)]
47+
[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(IEnumerable<CollectionDto>))]
5048
public async Task<IActionResult> Get()
5149
{
5250
if (!await _permissionService.Authorize(PermissionSystemName.Collections)) return Forbid();
@@ -57,7 +55,7 @@ public async Task<IActionResult> Get()
5755
[SwaggerOperation("Add new entity to Collection", OperationId = "InsertCollection")]
5856
[HttpPost]
5957
[ProducesResponseType((int)HttpStatusCode.Forbidden)]
60-
[ProducesResponseType((int)HttpStatusCode.OK)]
58+
[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(CollectionDto))]
6159
[ProducesResponseType((int)HttpStatusCode.BadRequest)]
6260
public async Task<IActionResult> Post([FromBody] CollectionDto model)
6361
{
@@ -68,16 +66,16 @@ public async Task<IActionResult> Post([FromBody] CollectionDto model)
6866
}
6967

7068
[SwaggerOperation("Update entity in Collection", OperationId = "UpdateCollection")]
71-
[HttpPut]
69+
[HttpPut("{key}")]
7270
[ProducesResponseType((int)HttpStatusCode.Forbidden)]
73-
[ProducesResponseType((int)HttpStatusCode.OK)]
71+
[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(CollectionDto))]
7472
[ProducesResponseType((int)HttpStatusCode.BadRequest)]
7573
[ProducesResponseType((int)HttpStatusCode.NotFound)]
76-
public async Task<IActionResult> Put([FromBody] CollectionDto model)
74+
public async Task<IActionResult> Put([FromRoute] string key, [FromBody] CollectionDto model)
7775
{
7876
if (!await _permissionService.Authorize(PermissionSystemName.Collections)) return Forbid();
7977

80-
var collection = await _mediator.Send(new GetGenericQuery<CollectionDto, Collection>(model.Id));
78+
var collection = await _mediator.Send(new GetGenericQuery<CollectionDto, Collection>(key));
8179
if (!collection.Any()) return NotFound();
8280

8381
model = await _mediator.Send(new UpdateCollectionCommand { Model = model });
@@ -107,11 +105,11 @@ public async Task<IActionResult> Patch([FromRoute] string key, [FromBody] JsonPa
107105
}
108106

109107
[SwaggerOperation("Delete entity in Collection", OperationId = "DeleteCollection")]
110-
[HttpDelete]
108+
[HttpDelete("{key}")]
111109
[ProducesResponseType((int)HttpStatusCode.Forbidden)]
112110
[ProducesResponseType((int)HttpStatusCode.OK)]
113111
[ProducesResponseType((int)HttpStatusCode.NotFound)]
114-
public async Task<IActionResult> Delete(string key)
112+
public async Task<IActionResult> Delete([FromRoute] string key)
115113
{
116114
if (!await _permissionService.Authorize(PermissionSystemName.Collections)) return Forbid();
117115

src/Modules/Grand.Module.Api/Controllers/CollectionLayoutController.cs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,11 @@
77
using Microsoft.AspNetCore.Mvc;
88
using Swashbuckle.AspNetCore.Annotations;
99
using System.Net;
10-
using Grand.Module.Api.Constants;
1110
using Grand.Module.Api.Attributes;
11+
using Microsoft.AspNetCore.Http;
1212

1313
namespace Grand.Module.Api.Controllers;
1414

15-
[Route($"{Configurations.RestRoutePrefix}/CollectionLayout")]
16-
[ApiExplorerSettings(IgnoreApi = false, GroupName = "v1")]
1715
public class CollectionLayoutController : BaseApiController
1816
{
1917
private readonly IMediator _mediator;
@@ -28,7 +26,7 @@ public CollectionLayoutController(IMediator mediator, IPermissionService permiss
2826
[SwaggerOperation("Get entity from CollectionLayout by key", OperationId = "GetCollectionLayoutById")]
2927
[HttpGet("{key}")]
3028
[ProducesResponseType((int)HttpStatusCode.Forbidden)]
31-
[ProducesResponseType((int)HttpStatusCode.OK)]
29+
[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(LayoutDto))]
3230
[ProducesResponseType((int)HttpStatusCode.NotFound)]
3331
public async Task<IActionResult> Get([FromRoute] string key)
3432
{
@@ -44,7 +42,7 @@ public async Task<IActionResult> Get([FromRoute] string key)
4442
[HttpGet]
4543
[EnableQuery]
4644
[ProducesResponseType((int)HttpStatusCode.Forbidden)]
47-
[ProducesResponseType((int)HttpStatusCode.OK)]
45+
[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(IEnumerable<LayoutDto>))]
4846
public async Task<IActionResult> Get()
4947
{
5048
if (!await _permissionService.Authorize(PermissionSystemName.Maintenance)) return Forbid();

src/Modules/Grand.Module.Api/Controllers/CountryController.cs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,11 @@
77
using Microsoft.AspNetCore.Mvc;
88
using Swashbuckle.AspNetCore.Annotations;
99
using System.Net;
10-
using Grand.Module.Api.Constants;
1110
using Grand.Module.Api.Attributes;
11+
using Microsoft.AspNetCore.Http;
1212

1313
namespace Grand.Module.Api.Controllers;
1414

15-
[Route($"{Configurations.RestRoutePrefix}/Country")]
16-
[ApiExplorerSettings(IgnoreApi = false, GroupName = "v1")]
1715
public class CountryController : BaseApiController
1816
{
1917
private readonly IMediator _mediator;
@@ -28,7 +26,7 @@ public CountryController(IMediator mediator, IPermissionService permissionServic
2826
[SwaggerOperation("Get entity from Country by key", OperationId = "GetCountryById")]
2927
[HttpGet("{key}")]
3028
[ProducesResponseType((int)HttpStatusCode.Forbidden)]
31-
[ProducesResponseType((int)HttpStatusCode.OK)]
29+
[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(CountryDto))]
3230
[ProducesResponseType((int)HttpStatusCode.NotFound)]
3331
public async Task<IActionResult> Get([FromRoute] string key)
3432
{
@@ -45,7 +43,7 @@ public async Task<IActionResult> Get([FromRoute] string key)
4543
[HttpGet]
4644
[EnableQuery]
4745
[ProducesResponseType((int)HttpStatusCode.Forbidden)]
48-
[ProducesResponseType((int)HttpStatusCode.OK)]
46+
[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(IEnumerable<CountryDto>))]
4947
public async Task<IActionResult> Get()
5048
{
5149
if (!await _permissionService.Authorize(PermissionSystemName.Countries)) return Forbid();

0 commit comments

Comments
 (0)