{"id":24666218,"url":"https://github.com/oznakdn/graphql-learning","last_synced_at":"2026-05-08T13:14:13.024Z","repository":{"id":222795487,"uuid":"758391829","full_name":"oznakdn/GraphQL-Learning","owner":"oznakdn","description":null,"archived":false,"fork":false,"pushed_at":"2024-03-07T13:54:25.000Z","size":24,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-01-26T07:41:27.581Z","etag":null,"topics":["bogus","efcore","grapql","grapql-server","hot-chocolate","jwt-authentication","jwt-authorization"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/oznakdn.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-02-16T08:12:14.000Z","updated_at":"2024-11-28T08:07:21.000Z","dependencies_parsed_at":"2024-03-07T14:58:12.290Z","dependency_job_id":"40719b1c-34e2-4ecf-8f5d-a63b84e1dce2","html_url":"https://github.com/oznakdn/GraphQL-Learning","commit_stats":null,"previous_names":["oznakdn/practical-graphql","oznakdn/graphql-learning"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/oznakdn%2FGraphQL-Learning","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/oznakdn%2FGraphQL-Learning/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/oznakdn%2FGraphQL-Learning/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/oznakdn%2FGraphQL-Learning/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/oznakdn","download_url":"https://codeload.github.com/oznakdn/GraphQL-Learning/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244787229,"owners_count":20510093,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["bogus","efcore","grapql","grapql-server","hot-chocolate","jwt-authentication","jwt-authorization"],"created_at":"2025-01-26T07:41:30.518Z","updated_at":"2026-05-08T13:14:12.982Z","avatar_url":"https://github.com/oznakdn.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"\n\u003cimg src=\"https://api.nuget.org/v3-flatcontainer/hotchocolate/13.8.1/icon\" height=200 width=200\u003e\n\u003ca href=\"https://chillicream.com/docs/hotchocolate/v13\"\u003eHot Chocolate documentation\u003c/a\u003e \u003c/br\u003e\n\u003ca href=\"https://github.com/ChilliCream/hotchocolate-examples/tree/master/misc\"\u003eExamples documentation\u003c/a\u003e\u003c/br\u003e\n\u003ca href=\"https://github.com/ChilliCream/hotchocolate-examples/tree/master/misc%2FCodeFirst\"\u003eExample documentation\u003c/a\u003e\n\n\n# Nuget Package\n\n```csharp\nHotChocolate.AspNetCore\nHotChocolate.AspNetCore.Authorization\nMicrosoft.AspNetCore.Authentication.JwtBearer\nHotChocolate.Data.EntityFramework\nMicrosoft.EntityFrameworkCore.InMemory\n```\n\n# Program.cs\n\n```csharp\n\nbuilder.Services.AddScoped\u003cTokenHelper\u003e();\n\nbuilder.Services.AddDbContext\u003cAppDbContext\u003e(opt =\u003e opt.UseInMemoryDatabase(\"ApiDb\"));\n\n\nbuilder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)\n                .AddJwtBearer(options =\u003e\n                {\n                    options.TokenValidationParameters = new TokenValidationParameters\n                    {\n                        ValidIssuer = \"http://localhost:5054\",\n                        ValidAudience = \"http://localhost:5054\",\n                        ValidateIssuerSigningKey = true,\n                        IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(\"c082a53a-938b-4504-8cff-def4667e8854\"))\n                    };\n                });\n\nbuilder.Services.AddAuthorization(options =\u003e\n{\n    options.AddPolicy(\"HasRole\", policy =\u003e\n    policy.RequireAssertion(context =\u003e\n        context.User.HasClaim(c =\u003e c.Type == ClaimTypes.Role)));\n});\n\nbuilder.Services.AddGraphQLServer()\n                .AddAuthorization()\n                .AddProjections()\n                .AddFiltering()\n                .AddSorting()\n                .AddQueryType\u003cQuery\u003e()\n                .AddMutationType\u003cMutation\u003e()\n                .AddSubscriptionType\u003cSubscription\u003e();\n\n\nvar app = builder.Build();\n\napp.SeedData();\n\napp.UseAuthentication();\n\napp.UseAuthorization();\n\napp.UseWebSockets();\n\napp.MapGraphQL();\n\napp.Run();\n```\n\n# Models\n```csharp\npublic class Project\n{\n    public string Id { get; set; }\n    public string Name { get; set; }\n\n    public ICollection\u003cMember\u003e Members { get; set; } = new HashSet\u003cMember\u003e();\n}\n```\n\n```csharp\npublic class Member\n{\n    \n    public string Id { get; set; }\n    public string Name { get; set; }\n    public string LastName { get; set; }\n    public string Title { get; set; }\n\n    public string ProjectId { get; set; }\n    public Project? Project { get; set; }\n}\n```\n\n```csharp\npublic class User\n{\n    public string Id { get; set; }\n    public string Email { get; set; }\n    public string Password { get; set; }\n    public string Username { get; set; }   \n\n    public string? RoleId { get; set; }\n    public Role? Role { get; set; }\n\n}\n```\n\n```csharp\npublic class Role\n{\n    public string Id { get; set; }\n    public string Name { get; set; }\n\n    public ICollection\u003cUser\u003e Users { get; set; }  = new HashSet\u003cUser\u003e();\n}\n```\n\n# Context\n\n```csharp\npublic class AppDbContext : DbContext\n{\n    public AppDbContext(DbContextOptions\u003cAppDbContext\u003eoptions) : base(options)\n    {\n        \n    }\n\n    public DbSet\u003cProject\u003eProjects { get; set; }\n    public DbSet\u003cMember\u003e Members { get; set; }\n    public DbSet\u003cUser\u003e Users { get; set; }\n    public DbSet\u003cRole\u003eRoles { get; set; }\n\n}\n```\n\n# Seeding Data by Bogus\n\n```csharp\npublic static class DataSeeding\n{\n    public static void SeedData(this WebApplication app)\n    {\n        var scope = app.Services.CreateScope();\n        var db = scope.ServiceProvider.GetRequiredService\u003cAppDbContext\u003e();\n\n\n        // Seeding project\n        string projectId = Guid.NewGuid().ToString();\n        var fakerProject = new Faker\u003cProject\u003e()\n        .RuleFor(x =\u003e x.Name, f =\u003e f.Company.Bs())\n        .RuleFor(x =\u003e x.Id, f =\u003e projectId);\n\n        Project project = fakerProject.Generate();\n        db.Projects.Add(project);\n\n\n        // Seeding member\n        var fakerMember = new Faker\u003cMember\u003e()\n            .RuleFor(x =\u003e x.ProjectId, f =\u003e projectId)\n            .RuleFor(x =\u003e x.Name, f =\u003e f.Name.FirstName())\n            .RuleFor(x =\u003e x.LastName, f =\u003e f.Name.LastName())\n            .RuleFor(x =\u003e x.Title, f =\u003e f.Name.JobTitle())\n            .RuleFor(x =\u003e x.Id, f =\u003e Guid.NewGuid().ToString());\n\n\n        List\u003cMember\u003e members = fakerMember.Generate(20);\n        db.Members.AddRange(members);\n\n\n        // Seeding role\n        string adminId = Guid.NewGuid().ToString();\n        var fakeRoleAdmin = new Faker\u003cRole\u003e()\n            .RuleFor(x =\u003e x.Name, f =\u003e \"ADMIN\")\n            .RuleFor(x =\u003e x.Id, f =\u003e adminId);\n\n        string managerId = Guid.NewGuid().ToString();\n        var fakeRoleManager = new Faker\u003cRole\u003e()\n            .RuleFor(x =\u003e x.Name, f =\u003e \"MANAGER\")\n            .RuleFor(x =\u003e x.Id, f =\u003e managerId);\n\n\n        var admin = fakeRoleAdmin.Generate();\n        var manager = fakeRoleManager.Generate();\n        db.Roles.AddRange(admin, manager);\n\n        // Seeding User\n        var fakeManager = new Faker\u003cUser\u003e()\n         .RuleFor(x =\u003e x.Id, f =\u003e Guid.NewGuid().ToString())\n          .RuleFor(x =\u003e x.Email, f =\u003e f.Person.Email)\n          .RuleFor(x =\u003e x.Password, f =\u003e \"123456\")\n          .RuleFor(x =\u003e x.Username, f =\u003e f.Person.UserName)\n          .RuleFor(x =\u003e x.RoleId, f =\u003e managerId);\n\n        var user = fakeManager.Generate(1);\n        db.Users.AddRange(user);\n\n        var fakeUser = new Faker\u003cUser\u003e()\n            .RuleFor(x =\u003e x.Id, f =\u003e Guid.NewGuid().ToString())\n            .RuleFor(x =\u003e x.Email, f =\u003e f.Person.Email)\n            .RuleFor(x =\u003e x.Password, f =\u003e \"123456\")\n            .RuleFor(x =\u003e x.Username, f =\u003e f.Person.UserName)\n            .RuleFor(x =\u003e x.RoleId, f =\u003e adminId);\n\n        List\u003cUser\u003e users = fakeUser.Generate(5);\n\n        db.Users.AddRange(users);\n\n        db.SaveChanges();\n    }\n```\n\n# Schemas\n\n## Query.cs\n\n```csharp\npublic class Query\n{\n\n    [UseProjection]\n    [UseFiltering]\n    [UseSorting]\n    public async Task\u003cIQueryable\u003cProject\u003e\u003e GetProjectAsync([Service] AppDbContext context)\n    {\n        return await Task.FromResult(context.Projects);\n    }\n\n    [UseProjection]\n    [UseFiltering]\n    [UseSorting]\n    public async Task\u003cIQueryable\u003cMember\u003e\u003e GetMemberAsync([Service] AppDbContext context)\n    {\n        return await Task.FromResult(context.Members);\n    }\n\n    [UseProjection]\n    [UseFiltering]\n    [UseSorting]\n    public async Task\u003cIQueryable\u003cUser\u003e\u003e GetUserAsync([Service] AppDbContext context)\n    {\n        return await Task.FromResult(context.Users);\n    }\n\n\n    [UseProjection]\n    [UseFiltering]\n    [UseSorting]\n    [Authorize(\"HasRole\", Roles = [\"MANAGER\"])]\n    public async Task\u003cIQueryable\u003cRole\u003e\u003e GetRoleAsync([Service] AppDbContext context)\n    {\n        return await Task.FromResult(context.Roles);\n    }\n\n\n    public async Task\u003cLoginResponse\u003e LoginAsync(LoginInput input, [Service] AppDbContext context, [Service] TokenHelper tokenHelper)\n    {\n        var user = await context.Users.Include(x=\u003ex.Role).SingleOrDefaultAsync(x =\u003e x.Username == input.Username \u0026\u0026 x.Password == input.Password);\n\n        if (user is null)\n        {\n            throw new GraphQLException(\"Username or password is wrong!\");\n        }\n\n        var token = tokenHelper.GenerateToken(user);\n\n        return new LoginResponse(token.Token, token.TokenExpire, user);\n    }\n}\n\n```\n## Mutation.cs\n```csharp\npublic class Mutation\n{\n    public async Task\u003cCreateProjectOutput\u003e CreateProjectAsync(CreateProjectInput input, CancellationToken cancellationToken, [Service] AppDbContext context)\n    {\n        var project = new Project\n        {\n            Id = Guid.NewGuid().ToString(),\n            Name = input.Name\n        };\n\n        context.Add(project);\n        await context.SaveChangesAsync(cancellationToken);\n        return new CreateProjectOutput(project);\n    }\n\n    public async Task\u003cbool\u003e UpdateProjectAsync(UpdateProjectInput input, CancellationToken cancellationToken, [Service] AppDbContext context)\n    {\n        var project = await context.Projects.SingleOrDefaultAsync(p =\u003e p.Id == input.Id);\n\n        if (project is null)\n            throw new GraphQLException(\"Project not found!\");\n\n        project.Name = input.Name ?? default!;\n\n        context.Update(project);\n        return await context.SaveChangesAsync(cancellationToken) \u003e 0;\n    }\n\n    public async Task\u003cbool\u003e RemoveProjectAsync(string id, CancellationToken cancellationToken, [Service] AppDbContext context)\n    {\n        var project = await context.Projects.SingleOrDefaultAsync(p =\u003e p.Id == id);\n\n        if (project is null)\n            throw new GraphQLException(\"Project not found!\");\n\n        context.Remove(project);\n        return await context.SaveChangesAsync(cancellationToken) \u003e 0;\n    }\n\n    // This method is for the Subscription's OnProjectCreated event\n    public async Task\u003cCreateProjectOutput\u003e AddProjectWithEventAsync(CreateProjectInput input, [Service] AppDbContext context, [Service] ITopicEventSender eventSender, CancellationToken cancellationToken)\n    {\n        var project = new Project\n        {\n            Id = Guid.NewGuid().ToString(),\n            Name = input.Name\n        };\n\n        context.Add(project);\n        await context.SaveChangesAsync(cancellationToken);\n\n        await eventSender.SendAsync(nameof(Subscription.OnProjectCreated), project, cancellationToken);\n\n        return new CreateProjectOutput(project);\n    }\n}\n```\n\n## Subscription.cs\n\n```csharp\npublic class Subscription\n{\n    [Subscribe]\n    [Topic]\n    public Project OnProjectCreated([EventMessage] Project project)\n    {\n        return project;\n    }\n}\n```\n\n# Requests and responses\nAttention! All the requests must to call by the Http POST method for usage the GraphQL\n\n## User-Role requests and responses\n![Screenshot_1](https://github.com/oznakdn/Practical-GraphQL/assets/79724084/ea15623a-e034-4b45-af6e-1865f61be24f)\n![Screenshot_2](https://github.com/oznakdn/Practical-GraphQL/assets/79724084/9c83f8b5-9f05-4db3-96d0-224522471474)\n\n\n## Project requests and responses\n![Screenshot_1](https://github.com/oznakdn/Practical-GraphQL/assets/79724084/704f5b33-22f1-4515-bf6e-1f5e5bca2328)\n![Screenshot_2](https://github.com/oznakdn/Practical-GraphQL/assets/79724084/e4c611d2-8be4-4d02-a77f-49445e124f67)\n![Screenshot_3](https://github.com/oznakdn/Practical-GraphQL/assets/79724084/c3fc26bc-ff52-4138-9d86-f0fbecc2ce0c)\n![Screenshot_4](https://github.com/oznakdn/Practical-GraphQL/assets/79724084/499cf1de-b83e-4fa0-ad5a-80083985bc16)\n![Screenshot_5](https://github.com/oznakdn/Practical-GraphQL/assets/79724084/187cf396-2908-4218-82e4-8c525ba945a4)\n![Screenshot_6](https://github.com/oznakdn/Practical-GraphQL/assets/79724084/614c2be2-e68c-4ce2-b701-f5e3443b3d01)\n\n## Member requests and responses\n![Screenshot_7](https://github.com/oznakdn/Practical-GraphQL/assets/79724084/efd17bab-f3bb-4946-ae1d-c872d8c7272c)\n![Screenshot_8](https://github.com/oznakdn/Practical-GraphQL/assets/79724084/d06300d0-7ac7-4fe4-a207-ddf3e7ea4f72)\n![Screenshot_9](https://github.com/oznakdn/Practical-GraphQL/assets/79724084/b85f5db6-3f9e-4391-94c4-5abc61f28edd)\n![Screenshot_10](https://github.com/oznakdn/Practical-GraphQL/assets/79724084/d3525a31-456a-48e2-8e04-41499f74e232)\n\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Foznakdn%2Fgraphql-learning","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Foznakdn%2Fgraphql-learning","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Foznakdn%2Fgraphql-learning/lists"}