Skip to content

Meta objects #38

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 11 commits into from
Feb 25, 2017
32 changes: 32 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ JsonApiDotnetCore provides a framework for building [json:api](http://jsonapi.or
- [Pagination](#pagination)
- [Filtering](#filtering)
- [Sorting](#sorting)
- [Meta](#meta)
- [Tests](#tests)

## Installation
Expand Down Expand Up @@ -240,6 +241,18 @@ when setting up the services:
opt => opt.DefaultPageSize = 10);
```

**Total Record Count**

The total number of records can be added to the document meta by setting it in the options:

```
services.AddJsonApi<AppDbContext>(opt =>
{
opt.DefaultPageSize = 5;
opt.IncludeTotalRecordCount = true;
});
```

### Filtering

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

### Meta

Resource meta can be defined by implementing `IHasMeta` on the model class:

```
public class Person : Identifiable<int>, IHasMeta
{
// ...

public Dictionary<string, object> GetMeta(IJsonApiContext context)
{
return new Dictionary<string, object> {
{ "copyright", "Copyright 2015 Example Corp." },
{ "authors", new string[] { "Jared Nance" } }
};
}
}
```

## Tests

I am using DotNetCoreDocs to generate sample requests and documentation.
Expand Down
24 changes: 22 additions & 2 deletions src/JsonApiDotNetCore/Builders/DocumentBuilder.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using JsonApiDotNetCore.Extensions;
using JsonApiDotNetCore.Internal;
using JsonApiDotNetCore.Models;
Expand All @@ -24,7 +25,8 @@ public Document Build(IIdentifiable entity)

var document = new Document
{
Data = _getData(contextEntity, entity)
Data = _getData(contextEntity, entity),
Meta = _getMeta(entity)
};

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

var documents = new Documents
{
Data = new List<DocumentData>()
Data = new List<DocumentData>(),
Meta = _getMeta(entities.FirstOrDefault())
};

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

private Dictionary<string, object> _getMeta(IIdentifiable entity)
{
if (entity == null) return null;

var meta = new Dictionary<string, object>();
var metaEntity = entity as IHasMeta;

if(metaEntity != null)
meta = metaEntity.GetMeta(_jsonApiContext);

if(_jsonApiContext.Options.IncludeTotalRecordCount)
meta["total-records"] = _jsonApiContext.TotalRecords;

if(meta.Count > 0) return meta;
return null;
}

private List<DocumentData> _appendIncludedObject(List<DocumentData> includedObject, ContextEntity contextEntity, IIdentifiable entity)
{
var includedEntities = _getIncludedEntities(contextEntity, entity);
Expand Down
1 change: 1 addition & 0 deletions src/JsonApiDotNetCore/Configuration/JsonApiOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@ public class JsonApiOptions
{
public string Namespace { get; set; }
public int DefaultPageSize { get; set; }
public bool IncludeTotalRecordCount { get; set; }
}
}
3 changes: 3 additions & 0 deletions src/JsonApiDotNetCore/Controllers/JsonApiController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,9 @@ public virtual async Task<IActionResult> GetAsync()
if (_jsonApiContext.QuerySet != null && _jsonApiContext.QuerySet.IncludedRelationships != null && _jsonApiContext.QuerySet.IncludedRelationships.Count > 0)
entities = IncludeRelationships(entities, _jsonApiContext.QuerySet.IncludedRelationships);

if (_jsonApiContext.Options.IncludeTotalRecordCount)
_jsonApiContext.TotalRecords = await entities.CountAsync();

// pagination should be done last since it will execute the query
var pagedEntities = await ApplyPageQueryAsync(entities);

Expand Down
6 changes: 1 addition & 5 deletions src/JsonApiDotNetCore/Models/Document.cs
Original file line number Diff line number Diff line change
@@ -1,14 +1,10 @@
using System.Collections.Generic;
using Newtonsoft.Json;

namespace JsonApiDotNetCore.Models
{
public class Document
public class Document : DocumentBase
{
[JsonProperty("data")]
public DocumentData Data { get; set; }

[JsonProperty("included")]
public List<DocumentData> Included { get; set; }
}
}
12 changes: 12 additions & 0 deletions src/JsonApiDotNetCore/Models/DocumentBase.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using System.Collections.Generic;
using Newtonsoft.Json;

namespace JsonApiDotNetCore.Models
{
public class DocumentBase
{
[JsonProperty("included")]
public List<DocumentData> Included { get; set; }
public Dictionary<string, object> Meta { get; set; }
}
}
5 changes: 1 addition & 4 deletions src/JsonApiDotNetCore/Models/Documents.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,9 @@

namespace JsonApiDotNetCore.Models
{
public class Documents
public class Documents : DocumentBase
{
[JsonProperty("data")]
public List<DocumentData> Data { get; set; }

[JsonProperty("included")]
public List<DocumentData> Included { get; set; }
}
}
10 changes: 10 additions & 0 deletions src/JsonApiDotNetCore/Models/IHasMeta.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
using System.Collections.Generic;
using JsonApiDotNetCore.Services;

namespace JsonApiDotNetCore.Models
{
public interface IHasMeta
{
Dictionary<string, object> GetMeta(IJsonApiContext context);
}
}
1 change: 1 addition & 0 deletions src/JsonApiDotNetCore/Services/IJsonApiContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,6 @@ public interface IJsonApiContext
QuerySet QuerySet { get; set; }
bool IsRelationshipData { get; set; }
List<string> IncludedRelationships { get; set; }
int TotalRecords { get; set; }
}
}
2 changes: 2 additions & 0 deletions src/JsonApiDotNetCore/Services/JsonApiContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,15 @@ public JsonApiContext(
_httpContextAccessor = httpContextAccessor;
Options = options;
}

public JsonApiOptions Options { get; set; }
public IContextGraph ContextGraph { get; set; }
public ContextEntity RequestEntity { get; set; }
public string BasePath { get; set; }
public QuerySet QuerySet { get; set; }
public bool IsRelationshipData { get; set; }
public List<string> IncludedRelationships { get; set; }
public int TotalRecords { get; set; }

public IJsonApiContext ApplyContext<T>()
{
Expand Down
2 changes: 1 addition & 1 deletion src/JsonApiDotNetCore/project.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"version": "0.2.11",
"version": "0.2.12",

"dependencies": {
"Microsoft.NETCore.App": {
Expand Down
11 changes: 10 additions & 1 deletion src/JsonApiDotNetCoreExample/Models/Person.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
using System.Collections.Generic;
using JsonApiDotNetCore.Internal;
using JsonApiDotNetCore.Models;
using JsonApiDotNetCore.Services;

namespace JsonApiDotNetCoreExample.Models
{
public class Person : Identifiable<int>
public class Person : Identifiable<int>, IHasMeta
{
public override int Id { get; set; }

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

public virtual List<TodoItem> TodoItems { get; set; }

public Dictionary<string, object> GetMeta(IJsonApiContext context)
{
return new Dictionary<string, object> {
{ "copyright", "Copyright 2015 Example Corp." },
{ "authors", new string[] { "Jared Nance" } }
};
}
}
}
18 changes: 9 additions & 9 deletions src/JsonApiDotNetCoreExample/Startup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ namespace JsonApiDotNetCoreExample
{
public class Startup
{
private readonly IConfiguration _config;
public readonly IConfiguration Config;

public Startup(IHostingEnvironment env)
{
Expand All @@ -25,10 +25,10 @@ public Startup(IHostingEnvironment env)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
.AddEnvironmentVariables();

_config = builder.Build();
Config = builder.Build();
}

public IServiceProvider ConfigureServices(IServiceCollection services)
public virtual IServiceProvider ConfigureServices(IServiceCollection services)
{
var loggerFactory = new LoggerFactory();
loggerFactory
Expand All @@ -37,7 +37,7 @@ public IServiceProvider ConfigureServices(IServiceCollection services)

services.AddDbContext<AppDbContext>(options =>
{
options.UseNpgsql(_getDbConnectionString());
options.UseNpgsql(GetDbConnectionString());
}, ServiceLifetime.Transient);

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

services.AddDocumentationConfiguration(_config);
services.AddDocumentationConfiguration(Config);

var provider = services.BuildServiceProvider();
var appContext = provider.GetRequiredService<AppDbContext>();
Expand All @@ -55,25 +55,25 @@ public IServiceProvider ConfigureServices(IServiceCollection services)
return provider;
}

public void Configure(
public virtual void Configure(
IApplicationBuilder app,
IHostingEnvironment env,
ILoggerFactory loggerFactory,
AppDbContext context)
{
context.Database.Migrate();

loggerFactory.AddConsole(_config.GetSection("Logging"));
loggerFactory.AddConsole(Config.GetSection("Logging"));
loggerFactory.AddDebug();

app.UseDocs();

app.UseJsonApi();
}

private string _getDbConnectionString()
public string GetDbConnectionString()
{
return _config["Data:DefaultConnection"];
return Config["Data:DefaultConnection"];
}
}
}
Loading