{"id":24813662,"url":"https://github.com/rnelson/fetch-receipt_processor-dotnet","last_synced_at":"2025-03-25T18:23:24.164Z","repository":{"id":271917659,"uuid":"914921477","full_name":"rnelson/fetch-receipt_processor-dotnet","owner":"rnelson","description":"Fetch Receipt Processor","archived":false,"fork":false,"pushed_at":"2025-01-11T03:46:35.000Z","size":119,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-01-30T15:51:31.848Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/rnelson.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","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":"2025-01-10T15:28:44.000Z","updated_at":"2025-01-11T03:41:16.000Z","dependencies_parsed_at":null,"dependency_job_id":"df0cab31-7789-4ad8-8892-6e29bd33201f","html_url":"https://github.com/rnelson/fetch-receipt_processor-dotnet","commit_stats":null,"previous_names":["rnelson/fetch-receipt_processor-dotnet"],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rnelson%2Ffetch-receipt_processor-dotnet","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rnelson%2Ffetch-receipt_processor-dotnet/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rnelson%2Ffetch-receipt_processor-dotnet/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rnelson%2Ffetch-receipt_processor-dotnet/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/rnelson","download_url":"https://codeload.github.com/rnelson/fetch-receipt_processor-dotnet/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245517492,"owners_count":20628358,"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":[],"created_at":"2025-01-30T15:51:08.213Z","updated_at":"2025-03-25T18:23:24.113Z","avatar_url":"https://github.com/rnelson.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Fetch Receipt Processor (.NET)\n\n![Build status](https://github.com/rnelson/fetch-receipt_processor-dotnet/actions/workflows/dotnet.yml/badge.svg) ![License](https://img.shields.io/github/license/rnelson/fetch-receipt_processor-dotnet)\n\nA solution for Fetch's [Receipt Processor challenge][fetch-rpc].\n\n### About\n\nWhile Fetch's preferred language is Go, I am currently most comfortable in C#. As someone who has been \ndoing this for a while, I understand that any senior developer is often going to be able to read and  \nunderstand code even in a language they don't use, and doing this in the language I've most heavily \nused for the last 6 years gives the best representation of how I attack the problem and architect a \ncomplete project.\n\n#### Architecture\n\nOther than unit tests, the solution is split into the following projects:\n\n1. `Libexec.FetchReceiptProcessor`, the ASP.NET Core Web API project providing the API.\n2. `Libexec.FetchReceiptProcessor.Data`, a combination of shared models, abstractions, and my data access layer (DAL).\n3. `Libexec.FetchReceiptProcessor.Extensions`, a project for just [extension methods][dotnet-ext].\n\nThe Extensions project only has a single extension. I have been meaning to take all the random helper \nextension classes that I've written and shoving them into a single NuGet package for easier reuse, but \nsince I haven't gotten around to that yet the helper I wrote is in its own project.\n\nThere isn't a lot to say about the Data project. The one thing I feel I should point out is that I wrote \n`IDatabase` and `Database`, an interface and concrete class, to act as my in-memory database. In the startup \nfile ([Program.cs][program-cs]), I add a singleton mapping `IDatabase` to `Database` in ASP.NET Core's \ndependency injection framework. In a more realistic example, I would have an object that actually hits a \ndatabase through whatever means, and then be able to use that same DI container to mock a database for \nunit tests, so I'm not ruining real data or adding unnecessary stress to the DBMS.\n\nWith .NET 9, Microsoft released a new OpenAPI package. I've used Swashbuckle, a popular .NET Swagger package, \nfor years and took this as an opportunity to play with the new package. You can see the generated result by \nrequesting `/openapi/v1.json` from a running instance of the API.\n\nFor the person(s) reviewing this code, these are the important files:\n\n+ [src/Libexec.FetchReceiptProcessor/Program.cs](https://github.com/rnelson/fetch-receipt_processor-dotnet/blob/main/src/Libexec.FetchReceiptProcessor/Program.cs): startup code that configures the API and causes it to run\n+ [src/Libexec.FetchReceiptProcessor/Controllers/ReceiptsController.cs](https://github.com/rnelson/fetch-receipt_processor-dotnet/blob/main/src/Libexec.FetchReceiptProcessor/Controllers/ReceiptsController.cs): the controller handling the `/receipts` requests\n+ [src/Libexec.FetchReceiptProcessor.Data/Receipt.cs](https://github.com/rnelson/fetch-receipt_processor-dotnet/blob/main/src/Libexec.FetchReceiptProcessor.Data/Receipt.cs): model that contains the point calculation rules\n\n#### Tests\n\nSince I had no time constraint for this project, I chose to go beyond the 2-3 hour mark to set *everything* \nup the way that I would for a personal project. That includes doing sufficient testing of the application.\n\nFirst and foremost, there are three unit tests projects:\n\n![Unit test results](https://github.com/rnelson/fetch-receipt_processor-dotnet/blob/main/docs/unit_tests.png?raw=true)\n\nBetween these three projects, the solution has 100% code coverage:\n\n![Unit test code coverage](https://github.com/rnelson/fetch-receipt_processor-dotnet/blob/main/docs/code_coverage.png?raw=true)\n\nAdditionally, using [JetBrains' HTTP client][jb-http], I built simple integration tests that run all of the \nFetch-provided JSON through the live application:\n\n![HTTP test results](https://github.com/rnelson/fetch-receipt_processor-dotnet/blob/main/docs/http_tests.png?raw=true)\n\n(To run these, open the sln file in [Rider][rider], start the \"Libexec.FetchReceiptProcessor: http\" project, open \nthe Services explorer, and run the HTTP Requests.)\n\n## Requirements\n* .NET 9\n* ASP.NET Core\n* Docker (optional)\n\n## Container Usage\nThe container is [available on Docker Hub][hub-link] and can be run without having to build anything \nyourself: `docker run -d -p 12345:8080 rossnelson84/fetchreceiptprocessor:1.0.0`\n\nTo build the container from source, run `docker build -t fetchreceiptprocessor:1.0.0 .`\n\nYou can `docker run -d -p 12345:8080 fetchreceiptprocessor:1.0.0`, substituting your local port of choice \nfor `12345` (e.g., `-p 9090:8080` to run on port 9090 on the host).\n\n## License\nThis program is licensed under the [MIT license][license].\n\n[license]: https://rnelson.mit-license.org\n[fetch-rpc]: https://github.com/fetch-rewards/receipt-processor-challenge\n[hub-link]: https://hub.docker.com/repository/docker/rossnelson84/fetchreceiptprocessor/general\n[jb-http]: https://www.jetbrains.com/help/idea/http-client-in-product-code-editor.html\n[rider]: https://www.jetbrains.com/rider\n[dotnet-ext]: https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/extension-methods\n[program-cs]: https://github.com/rnelson/fetch-receipt_processor-dotnet/blob/main/src/Libexec.FetchReceiptProcessor/Program.cs","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frnelson%2Ffetch-receipt_processor-dotnet","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frnelson%2Ffetch-receipt_processor-dotnet","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frnelson%2Ffetch-receipt_processor-dotnet/lists"}