Skip to content

Commit

Permalink
#19 set up NuGet for extension + new build yaml
Browse files Browse the repository at this point in the history
  • Loading branch information
Ian-Webster committed Dec 6, 2023
1 parent e4dabe5 commit 7f75221
Show file tree
Hide file tree
Showing 4 changed files with 158 additions and 110 deletions.
40 changes: 40 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
name: Build Action

on:
push:
paths:
- 'DataAccess/DataAccess.Repository/**'
- 'DataAccess/Extensions/DataAccess.Repository.HotChocolate/**'

jobs:

build:

runs-on: ubuntu-latest

strategy:
matrix:
project: ['DataAccess.Repository', 'DataAccess.Repository.HotChocolate']

steps:
- name: Checkout
uses: actions/checkout@v3

# Install the .NET Core workload
- name: Install .NET Core
uses: actions/setup-dotnet@v3
with:
dotnet-version: 8.0.x

# Set up local NuGet repo
- name: Setup GitHub NuGet
run: dotnet nuget add source --username USERNAME --password ${{ secrets.GITHUB_TOKEN }} --store-password-in-clear-text --name github "https://nuget.pkg.github.com/Ian-Webster/index.json"

# Resource NuGet dependencies
- name: Restore dependencies
run: dotnet restore 'DataAccess/${{ matrix.project }}'

# Build project
- name: Build
run: dotnet build --configuration Release 'DataAccess/${{ matrix.project }}'

2 changes: 1 addition & 1 deletion DataAccess.Repository/DataAccess.Repository.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
<Description>A simple base repository to be used in other projects requiring data access</Description>
<PackageProjectUrl>https://github.com/Ian-Webster/DataAccess</PackageProjectUrl>
<RepositoryUrl>https://github.com/Ian-Webster/DataAccess</RepositoryUrl>
<VersionPrefix>2.0.0-wip</VersionPrefix>
<VersionPrefix>2.0.1</VersionPrefix>
<VersionSuffix></VersionSuffix>
</PropertyGroup>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,13 @@
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
<Title>DataAccess.HotChocolate</Title>
<Description>Extension to the DataAccess package adding GraphQL functionality via the HotChocolate library</Description>
<PackageProjectUrl>https://github.com/Ian-Webster/DataAccess/Extensions/DataAccess.Repository.HotChocolate</PackageProjectUrl>
<RepositoryUrl>https://github.com/Ian-Webster/DataAccess</RepositoryUrl>
<VersionPrefix>0.1.0</VersionPrefix>
<VersionSuffix></VersionSuffix>
</PropertyGroup>

<ItemGroup>
Expand Down
219 changes: 110 additions & 109 deletions Extensions/DataAccess.Repository.HotChocolate/readme.md
Original file line number Diff line number Diff line change
@@ -1,116 +1,117 @@
# HotChocolate Extension
## Introduction
This extension provides GraphQL query functionality via the [HotChocolate Library](https://chillicream.com/docs/hotchocolate/v13)
# HotChocolate Extension
## Introduction
This extension provides GraphQL query functionality via the [HotChocolate Library](https://chillicream.com/docs/hotchocolate/v13)

## Installation
1. You'll need to install and set up the core data access NuGet package (see instructions [here](https://github.com/Ian-Webster/DataAccess#usage))
2. Add the following NuGet packages to your IoC project;
1. [HotChocolate](https://www.nuget.org/packages/HotChocolate/13.7.0?_src=template)
2. [HotChocolate.AspNetCore](https://www.nuget.org/packages/HotChocolate.AspNetCore/13.7.0?_src=template)
3. [HotChocolate.Data](https://www.nuget.org/packages/HotChocolate.Data/13.7.0?_src=template)
3. Add the following NuGet packages to your Repository project;
1. [HotChocolate](https://www.nuget.org/packages/HotChocolate/13.7.0?_src=template)
2. [HotChocolate.Data](https://www.nuget.org/packages/HotChocolate.Data/13.7.0?_src=template)
3. TBC- this extension
4. Modify your IoC services to add and configure HotChocolate;
```csharp
// set up HotChocolate
builder.Services.AddGraphQLServer()
.AddQueryType(q => q.Name("Query"))
.AddProjections()
.AddFiltering()
.AddSorting();
```
5.Modify your middleware configuration to include `app.MapGraphQL();`
6. We'll revisit your IoC configuration later to add queries.
## Installation
1. You'll need to install and set up the core data access NuGet package (see instructions [here](https://github.com/Ian-Webster/DataAccess#usage))
2. Add the following NuGet packages to your IoC project;
1. [HotChocolate](https://www.nuget.org/packages/HotChocolate/13.7.0?_src=template)
2. [HotChocolate.AspNetCore](https://www.nuget.org/packages/HotChocolate.AspNetCore/13.7.0?_src=template)
3. [HotChocolate.Data](https://www.nuget.org/packages/HotChocolate.Data/13.7.0?_src=template)
3. Add the following NuGet packages to your Repository project;
1. [HotChocolate](https://www.nuget.org/packages/HotChocolate/13.7.0?_src=template)
2. [HotChocolate.Data](https://www.nuget.org/packages/HotChocolate.Data/13.7.0?_src=template)
3. TBC- this extension
4. Modify your IoC services to add and configure HotChocolate;
```csharp
// set up HotChocolate
builder.Services.AddGraphQLServer()
.AddQueryType(q => q.Name("Query"))
.AddProjections()
.AddFiltering()
.AddSorting();
```
5.Modify your middleware configuration to include `app.MapGraphQL();`
6. We'll revisit your IoC configuration later to add queries.

## Building queries
Queries in GraphQL are like a stand-in for controller endpoints in REST, they provide a public API into your data, you can read more here https://chillicream.com/docs/hotchocolate/v13/defining-a-schema/queries
## Building queries
Queries in GraphQL are like a stand-in for controller endpoints in REST, they provide a public API into your data, you can read more here https://chillicream.com/docs/hotchocolate/v13/defining-a-schema/queries

HotChocolate can query your DBContext directly should you wish, however it does also provide a number of IQueryable extension methods and a query context class that allow you to use your own services and repository methods to perform the data operations.
HotChocolate can query your DBContext directly should you wish, however it does also provide a number of IQueryable extension methods and a query context class that allow you to use your own services and repository methods to perform the data operations.

The purpose of this extension library to obfuscate the complexities involved in modifying repository methods to support the HotChocolate extensions by providing a number of extension methods in the QueryExtensions;
* GetQueryItem - returns a single entity, supports filtering and projection
* GetQueryItems - returns a collection of entities, supports filtering, projection and sorting
* GetPagedQueryItems - returns a [Connection](https://chillicream.com/docs/hotchocolate/v13/fetching-data/pagination/#connections) object provided by the HotChocolate library, supports filtering, projection, sorting and pagination
The purpose of this extension library to obfuscate the complexities involved in modifying repository methods to support the HotChocolate extensions by providing a number of extension methods in the QueryExtensions;
* GetQueryItem - returns a single entity, supports filtering and projection
* GetQueryItems - returns a collection of entities, supports filtering, projection and sorting
* GetPagedQueryItems - returns a [Connection](https://chillicream.com/docs/hotchocolate/v13/fetching-data/pagination/#connections) object provided by the HotChocolate library, supports filtering, projection, sorting and pagination

Usage for this extension is as follows;
1. Modify your repository to accept IResolverContext and to call the extension, as an example this is how to get a single book entity for GraphQL;
```csharp
// interface
using HotChocolate.Resolvers; // namespace for IResolverContext
namespace DataAccess.Example.Data.Repositories;

public interface IBookRepository
{
Task<Book?> GetBookForGraphQuery(IResolverContext context, CancellationToken token);
}
Usage for this extension is as follows;
1. Modify your repository to accept IResolverContext and to call the extension, as an example this is how to get a single book entity for GraphQL;
```csharp
// interface
using HotChocolate.Resolvers; // namespace for IResolverContext
namespace DataAccess.Example.Data.Repositories;

public interface IBookRepository
{
Task<Book?> GetBookForGraphQuery(IResolverContext context, CancellationToken token);
}

// implementation
using DataAccess.Repository.HotChocolate; // namespace for this extension
using HotChocolate.Resolvers; // namespace for IResolverContext
namespace DataAccess.Example.Data.Repositories;

public class BookRepository: IBookRepository
{
private readonly IRepository<Book> _bookRepo;

public BookRepository(RepositoryFactory<LibraryDatabaseContext> repositoryFactory)
{
_bookRepo = repositoryFactory.GetRepositoryByType<Book>();
}

public async Task<Book?> GetBookForGraphQuery(IResolverContext context, CancellationToken token)
{
return await _bookRepo.GetQueryItem(context, token);
}
}
```
2. Create a query class here is the book query;
```csharp
using HotChocolate;
using HotChocolate.Types;
using HotChocolate.Resolvers;

namespace DataAccess.Example.Data.Queries;

[ExtendObjectType("Query")]
public class BookQuery
{
[UseProjection] // enable projecton for this query
[UseFiltering] // enable filtering for this query
// [Service] is an attribute hint provided by the HotChocolate library
// telling the code to use DI to retrieve the IBookRepository dependency
// IResolverContext and CancellationToken objects are provide as part of the
// GraphQL context
public async Task<Book?> GetBook([Service] IBookRepository repository, IResolverContext context, CancellationToken token)
{
return await repository.GetBookForGraphQuery(context, token);
}
}
```
3. Modify the HotChocolate IoC configuration you added earlier to include your query;
```csharp
// set up HotChocolate
builder.Services.AddGraphQLServer()
.AddQueryType(q => q.Name("Query"))
.AddTypeExtension<BookQuery>() // adding the book query type
.AddProjections()
.AddFiltering()
.AddSorting();
```
4. Run the API project as normal, you should be able to visit /graphql and see the [Banana Cake Pop](https://chillicream.com/products/bananacakepop/) UX
5. Run a query through the UX, as an example this will return the book "Fight Club" from the example project;
```json
{
book (where: {bookId: {eq: "2c4a20f5-3fc8-4694-9c03-cb444bf416dc"}})
{
bookId,
name
}
}
```
// implementation
using DataAccess.Repository.HotChocolate; // namespace for this extension
using HotChocolate.Resolvers; // namespace for IResolverContext
namespace DataAccess.Example.Data.Repositories;

public class BookRepository: IBookRepository
{
private readonly IRepository<Book> _bookRepo;

public BookRepository(RepositoryFactory<LibraryDatabaseContext> repositoryFactory)
{
_bookRepo = repositoryFactory.GetRepositoryByType<Book>();
}

public async Task<Book?> GetBookForGraphQuery(IResolverContext context, CancellationToken token)
{
return await _bookRepo.GetQueryItem(context, token);
}
}
```
2. Create a query class here is the book query;
```csharp
using HotChocolate;
using HotChocolate.Types;
using HotChocolate.Resolvers;

namespace DataAccess.Example.Data.Queries;

[ExtendObjectType("Query")]
public class BookQuery
{
[UseProjection] // enable projecton for this query
[UseFiltering] // enable filtering for this query
// [Service] is an attribute hint provided by the HotChocolate library
// telling the code to use DI to retrieve the IBookRepository dependency
// IResolverContext and CancellationToken objects are provide as part of the
// GraphQL context
public async Task<Book?> GetBook([Service] IBookRepository repository, IResolverContext context, CancellationToken token)
{
return await repository.GetBookForGraphQuery(context, token);
}
}
```
3. Modify the HotChocolate IoC configuration you added earlier to include your query;
```csharp
// set up HotChocolate
builder.Services.AddGraphQLServer()
.AddQueryType(q => q.Name("Query"))
.AddTypeExtension<BookQuery>() // adding the book query type
.AddProjections()
.AddFiltering()
.AddSorting();
```
4. Run the API project as normal, you should be able to visit /graphql and see the [Banana Cake Pop](https://chillicream.com/products/bananacakepop/) UX
5. Run a query through the UX, as an example this will return the book "Fight Club" from the example project;
```json
{
book (where: {bookId: {eq: "2c4a20f5-3fc8-4694-9c03-cb444bf416dc"}})
{
bookId,
name
}
}
```

## Version history
* 0.1.0 - Initial project creation, getting everything figured out and running locally
## Version history
* 1.0.0 - Initial release
* 0.1.0 - Initial project creation, getting everything figured out and running locally

0 comments on commit 7f75221

Please sign in to comment.