Skip to content

Commit 989b862

Browse files
authoredFeb 25, 2017
Merge pull request #38 from Research-Institute/meta-objects
Meta objects
2 parents 605e039 + 456d65c commit 989b862

File tree

15 files changed

+247
-22
lines changed

15 files changed

+247
-22
lines changed
 

‎README.md

+32
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ JsonApiDotnetCore provides a framework for building [json:api](http://jsonapi.or
2424
- [Pagination](#pagination)
2525
- [Filtering](#filtering)
2626
- [Sorting](#sorting)
27+
- [Meta](#meta)
2728
- [Tests](#tests)
2829

2930
## Installation
@@ -240,6 +241,18 @@ when setting up the services:
240241
opt => opt.DefaultPageSize = 10);
241242
```
242243

244+
**Total Record Count**
245+
246+
The total number of records can be added to the document meta by setting it in the options:
247+
248+
```
249+
services.AddJsonApi<AppDbContext>(opt =>
250+
{
251+
opt.DefaultPageSize = 5;
252+
opt.IncludeTotalRecordCount = true;
253+
});
254+
```
255+
243256
### Filtering
244257

245258
You can filter resources by attributes using the `filter` query parameter.
@@ -270,6 +283,25 @@ Resources can be sorted by an attribute:
270283
?sort=-attribute // descending
271284
```
272285

286+
### Meta
287+
288+
Resource meta can be defined by implementing `IHasMeta` on the model class:
289+
290+
```
291+
public class Person : Identifiable<int>, IHasMeta
292+
{
293+
// ...
294+
295+
public Dictionary<string, object> GetMeta(IJsonApiContext context)
296+
{
297+
return new Dictionary<string, object> {
298+
{ "copyright", "Copyright 2015 Example Corp." },
299+
{ "authors", new string[] { "Jared Nance" } }
300+
};
301+
}
302+
}
303+
```
304+
273305
## Tests
274306

275307
I am using DotNetCoreDocs to generate sample requests and documentation.

‎src/JsonApiDotNetCore/Builders/DocumentBuilder.cs

+22-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System.Collections;
22
using System.Collections.Generic;
3+
using System.Linq;
34
using JsonApiDotNetCore.Extensions;
45
using JsonApiDotNetCore.Internal;
56
using JsonApiDotNetCore.Models;
@@ -24,7 +25,8 @@ public Document Build(IIdentifiable entity)
2425

2526
var document = new Document
2627
{
27-
Data = _getData(contextEntity, entity)
28+
Data = _getData(contextEntity, entity),
29+
Meta = _getMeta(entity)
2830
};
2931

3032
document.Included = _appendIncludedObject(document.Included, contextEntity, entity);
@@ -42,7 +44,8 @@ public Documents Build(IEnumerable<IIdentifiable> entities)
4244

4345
var documents = new Documents
4446
{
45-
Data = new List<DocumentData>()
47+
Data = new List<DocumentData>(),
48+
Meta = _getMeta(entities.FirstOrDefault())
4649
};
4750

4851
foreach (var entity in entities)
@@ -54,6 +57,23 @@ public Documents Build(IEnumerable<IIdentifiable> entities)
5457
return documents;
5558
}
5659

60+
private Dictionary<string, object> _getMeta(IIdentifiable entity)
61+
{
62+
if (entity == null) return null;
63+
64+
var meta = new Dictionary<string, object>();
65+
var metaEntity = entity as IHasMeta;
66+
67+
if(metaEntity != null)
68+
meta = metaEntity.GetMeta(_jsonApiContext);
69+
70+
if(_jsonApiContext.Options.IncludeTotalRecordCount)
71+
meta["total-records"] = _jsonApiContext.TotalRecords;
72+
73+
if(meta.Count > 0) return meta;
74+
return null;
75+
}
76+
5777
private List<DocumentData> _appendIncludedObject(List<DocumentData> includedObject, ContextEntity contextEntity, IIdentifiable entity)
5878
{
5979
var includedEntities = _getIncludedEntities(contextEntity, entity);

‎src/JsonApiDotNetCore/Configuration/JsonApiOptions.cs

+1
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,6 @@ public class JsonApiOptions
44
{
55
public string Namespace { get; set; }
66
public int DefaultPageSize { get; set; }
7+
public bool IncludeTotalRecordCount { get; set; }
78
}
89
}

‎src/JsonApiDotNetCore/Controllers/JsonApiController.cs

+3
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,9 @@ public virtual async Task<IActionResult> GetAsync()
6464
if (_jsonApiContext.QuerySet != null && _jsonApiContext.QuerySet.IncludedRelationships != null && _jsonApiContext.QuerySet.IncludedRelationships.Count > 0)
6565
entities = IncludeRelationships(entities, _jsonApiContext.QuerySet.IncludedRelationships);
6666

67+
if (_jsonApiContext.Options.IncludeTotalRecordCount)
68+
_jsonApiContext.TotalRecords = await entities.CountAsync();
69+
6770
// pagination should be done last since it will execute the query
6871
var pagedEntities = await ApplyPageQueryAsync(entities);
6972

+1-5
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,10 @@
1-
using System.Collections.Generic;
21
using Newtonsoft.Json;
32

43
namespace JsonApiDotNetCore.Models
54
{
6-
public class Document
5+
public class Document : DocumentBase
76
{
87
[JsonProperty("data")]
98
public DocumentData Data { get; set; }
10-
11-
[JsonProperty("included")]
12-
public List<DocumentData> Included { get; set; }
139
}
1410
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
using System.Collections.Generic;
2+
using Newtonsoft.Json;
3+
4+
namespace JsonApiDotNetCore.Models
5+
{
6+
public class DocumentBase
7+
{
8+
[JsonProperty("included")]
9+
public List<DocumentData> Included { get; set; }
10+
public Dictionary<string, object> Meta { get; set; }
11+
}
12+
}

‎src/JsonApiDotNetCore/Models/Documents.cs

+1-4
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,9 @@
33

44
namespace JsonApiDotNetCore.Models
55
{
6-
public class Documents
6+
public class Documents : DocumentBase
77
{
88
[JsonProperty("data")]
99
public List<DocumentData> Data { get; set; }
10-
11-
[JsonProperty("included")]
12-
public List<DocumentData> Included { get; set; }
1310
}
1411
}
+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
using System.Collections.Generic;
2+
using JsonApiDotNetCore.Services;
3+
4+
namespace JsonApiDotNetCore.Models
5+
{
6+
public interface IHasMeta
7+
{
8+
Dictionary<string, object> GetMeta(IJsonApiContext context);
9+
}
10+
}

‎src/JsonApiDotNetCore/Services/IJsonApiContext.cs

+1
Original file line numberDiff line numberDiff line change
@@ -15,5 +15,6 @@ public interface IJsonApiContext
1515
QuerySet QuerySet { get; set; }
1616
bool IsRelationshipData { get; set; }
1717
List<string> IncludedRelationships { get; set; }
18+
int TotalRecords { get; set; }
1819
}
1920
}

‎src/JsonApiDotNetCore/Services/JsonApiContext.cs

+2
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,15 @@ public JsonApiContext(
2020
_httpContextAccessor = httpContextAccessor;
2121
Options = options;
2222
}
23+
2324
public JsonApiOptions Options { get; set; }
2425
public IContextGraph ContextGraph { get; set; }
2526
public ContextEntity RequestEntity { get; set; }
2627
public string BasePath { get; set; }
2728
public QuerySet QuerySet { get; set; }
2829
public bool IsRelationshipData { get; set; }
2930
public List<string> IncludedRelationships { get; set; }
31+
public int TotalRecords { get; set; }
3032

3133
public IJsonApiContext ApplyContext<T>()
3234
{

‎src/JsonApiDotNetCore/project.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"version": "0.2.11",
2+
"version": "0.2.12",
33

44
"dependencies": {
55
"Microsoft.NETCore.App": {

‎src/JsonApiDotNetCoreExample/Models/Person.cs

+10-1
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
using System.Collections.Generic;
22
using JsonApiDotNetCore.Internal;
33
using JsonApiDotNetCore.Models;
4+
using JsonApiDotNetCore.Services;
45

56
namespace JsonApiDotNetCoreExample.Models
67
{
7-
public class Person : Identifiable<int>
8+
public class Person : Identifiable<int>, IHasMeta
89
{
910
public override int Id { get; set; }
1011

@@ -15,5 +16,13 @@ public class Person : Identifiable<int>
1516
public string LastName { get; set; }
1617

1718
public virtual List<TodoItem> TodoItems { get; set; }
19+
20+
public Dictionary<string, object> GetMeta(IJsonApiContext context)
21+
{
22+
return new Dictionary<string, object> {
23+
{ "copyright", "Copyright 2015 Example Corp." },
24+
{ "authors", new string[] { "Jared Nance" } }
25+
};
26+
}
1827
}
1928
}

‎src/JsonApiDotNetCoreExample/Startup.cs

+9-9
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ namespace JsonApiDotNetCoreExample
1515
{
1616
public class Startup
1717
{
18-
private readonly IConfiguration _config;
18+
public readonly IConfiguration Config;
1919

2020
public Startup(IHostingEnvironment env)
2121
{
@@ -25,10 +25,10 @@ public Startup(IHostingEnvironment env)
2525
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
2626
.AddEnvironmentVariables();
2727

28-
_config = builder.Build();
28+
Config = builder.Build();
2929
}
3030

31-
public IServiceProvider ConfigureServices(IServiceCollection services)
31+
public virtual IServiceProvider ConfigureServices(IServiceCollection services)
3232
{
3333
var loggerFactory = new LoggerFactory();
3434
loggerFactory
@@ -37,7 +37,7 @@ public IServiceProvider ConfigureServices(IServiceCollection services)
3737

3838
services.AddDbContext<AppDbContext>(options =>
3939
{
40-
options.UseNpgsql(_getDbConnectionString());
40+
options.UseNpgsql(GetDbConnectionString());
4141
}, ServiceLifetime.Transient);
4242

4343
services.AddJsonApi<AppDbContext>(opt =>
@@ -46,7 +46,7 @@ public IServiceProvider ConfigureServices(IServiceCollection services)
4646
opt.DefaultPageSize = 5;
4747
});
4848

49-
services.AddDocumentationConfiguration(_config);
49+
services.AddDocumentationConfiguration(Config);
5050

5151
var provider = services.BuildServiceProvider();
5252
var appContext = provider.GetRequiredService<AppDbContext>();
@@ -55,25 +55,25 @@ public IServiceProvider ConfigureServices(IServiceCollection services)
5555
return provider;
5656
}
5757

58-
public void Configure(
58+
public virtual void Configure(
5959
IApplicationBuilder app,
6060
IHostingEnvironment env,
6161
ILoggerFactory loggerFactory,
6262
AppDbContext context)
6363
{
6464
context.Database.Migrate();
6565

66-
loggerFactory.AddConsole(_config.GetSection("Logging"));
66+
loggerFactory.AddConsole(Config.GetSection("Logging"));
6767
loggerFactory.AddDebug();
6868

6969
app.UseDocs();
7070

7171
app.UseJsonApi();
7272
}
7373

74-
private string _getDbConnectionString()
74+
public string GetDbConnectionString()
7575
{
76-
return _config["Data:DefaultConnection"];
76+
return Config["Data:DefaultConnection"];
7777
}
7878
}
7979
}

0 commit comments

Comments
 (0)