{"id":20482191,"url":"https://github.com/rajagopal28/transaction-manager","last_synced_at":"2025-09-01T00:43:32.613Z","repository":{"id":52655255,"uuid":"193069942","full_name":"rajagopal28/transaction-manager","owner":"rajagopal28","description":"A Small, light-weight Rest API based Java application without any framework, which does not require any server or container runtime.","archived":false,"fork":false,"pushed_at":"2023-05-23T20:11:41.000Z","size":1264,"stargazers_count":1,"open_issues_count":2,"forks_count":1,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-06-25T23:36:06.510Z","etag":null,"topics":["embedded-server","integration-testing","java","javax-persistence","jax-rs","jpa","lighweight","mockito","powermockito","rest-api","rest-assured","sqlite3","tdd"],"latest_commit_sha":null,"homepage":"","language":"Java","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/rajagopal28.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":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-06-21T09:25:14.000Z","updated_at":"2022-10-10T10:16:58.000Z","dependencies_parsed_at":"2024-11-15T16:22:05.290Z","dependency_job_id":null,"html_url":"https://github.com/rajagopal28/transaction-manager","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/rajagopal28/transaction-manager","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rajagopal28%2Ftransaction-manager","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rajagopal28%2Ftransaction-manager/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rajagopal28%2Ftransaction-manager/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rajagopal28%2Ftransaction-manager/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/rajagopal28","download_url":"https://codeload.github.com/rajagopal28/transaction-manager/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rajagopal28%2Ftransaction-manager/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":267773392,"owners_count":24142103,"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","status":"online","status_checked_at":"2025-07-29T02:00:12.549Z","response_time":2574,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":["embedded-server","integration-testing","java","javax-persistence","jax-rs","jpa","lighweight","mockito","powermockito","rest-api","rest-assured","sqlite3","tdd"],"created_at":"2024-11-15T16:11:57.571Z","updated_at":"2025-07-29T22:42:34.708Z","avatar_url":"https://github.com/rajagopal28.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# transaction-manager\n\n* [Context](#context)\n* [Objectives](#objectives)\n* [Approach](#the-approach)\n* [Schema](#schema)\n* [API System](#api-system-flow)\n* [API Flows](#api-flows)\n* [TDD-Red-\u003eGreen-\u003eRefactor cycle](#tdd---red-\u003egreen-\u003erefactor-cycle)\n    * [Test Coverages](#unit-test-and-integration-test-coverage)\n* [Setup](#setup-and-launch)\n* [Libraries Used](#libraries-used)\n* [Challenges](#challenges)\n* [References](#references)\n\n## Context\nA Small, light-weight Rest API based Java application without any framework, which does not require any server.\n\n## Objectives\nFollowing are the primary objectives this project is based on\n1. The REST API should be built on an embedded server which means there should be no server or container that helps these API end points run at a particular application endpoint\n2. TDD should be enforced at every stage of the implementation\n3. The Application implementation should be simple and scalable as if it has real time traffic with multiple users accessing the system simultaneously\n4. The Application is meant to be Light weight hence Heavy frameworks such as Spring could not considered while implementing\n5. Application could only rely on in memory datastores\n\n## The Approach\nBased on the aforementioned objectives the system that is being built has been built based on the following approach:\n- Using Jersey-Server library to create a JAX-RS reliant REST API server which can run as a self contained, embedded server that can be started and stopped from a simple Java application.\n- Using Mockito and PowerMocktio frameworks the entire implementation is developed following the TDD strategy where fail tests -\u003e refactor -\u003e pass tests cycle was strictly carried on.\n- JAX-RS application are simple, fast, reliable at the same time scaled based on the underlying data access implementations\n- SQLite datastore is used to store the data without involving any sever runtime or containers to actively engage with data connections.\n- Hibernate-JPA library is used to leverage the advantages javax.persistence library which helps in efficient, simple and scaled database access approaches.\n\n\n## Schema\n![Schema Diagram](transaction-manager-schema.png)\n\n## API System flow\n![Flow Diagram](api-system-flow.png)\n\n\n## API Flows\n### Endpoint info\n| Endpoint\\HTTP METHOD | POST            | GET       |\n| ----------- | --------------- | --------- |\n| CRUD OP                               | CREATE                                | READ                                                              | \n| /users                                | Create new User                       | List existing users                                               |\n| /users/1                              | --                                    | Show Existing user                                                |\n| /users/1/accounts                     | Create an account for user1           | List All Accounts of user 1                                       |\n| /users/1/accounts/1                   | --                                    | Show Existing User's Chosen Account                               |\n| /users/1/accounts/1/transactions      | Post a transaction to the given account - payload varies           | Show Selected Account transactions   |\n| /users/1/accounts/1/transactions/1    | --                                    | Show Chosen Transaction detail                                    |\n\n### Response Status Codes\nFollowing are the response status codes that are sent as part of the system\n* 200 - OK\n* 304 - Not Modified\n* 400 - Bad Request\n* 404 - Not Found\n* 500 - Internal Server Error\n\n| Endpoint | Applicable status codes| \n| ----------- | --------------- |\n| /users                                | 200, 304, 500           |\n| /users/1                              | 200, 404                |\n| /users/1/accounts                     | 200, 400, 500           |\n| /users/1/accounts/1                   | 200, 400, 404           |\n| /users/1/accounts/1/transactions      | 200, 400, 404, 500      |\n| /users/1/accounts/1/transactions/1    | 200, 304, 400, 404, 500,|\n\n### Endpoint details\n#### /users\nGET:\n```bash\ncurl http://localhost:8080/users\n```\n``\nHTTP STATUS: 200\n``\n```javascript\n[\n    {\n        \"city\": \"Pasedena\",\n        \"dob\": \"11/03/1980\",\n        \"email\": \"lenny@caltech.com\",\n        \"firstName\": \"Leonard\",\n        \"gender\": \"male\",\n        \"id\": 1,\n        \"lastName\": \"Hofstader\",\n        \"phoneNumber\": \"+811297983423\"\n    },\n    {\n        \"city\": \"Pasedena\",\n        \"dob\": \"12/12/1983\",\n        \"email\": \"penny@cheesecakefactory.com\",\n        \"firstName\": \"Penny\",\n        \"gender\": \"female\",\n        \"id\": 2,\n        \"lastName\": \"Barrington\",\n        \"phoneNumber\": \"+8242312213123\"\n    }\n]\n```\nPOST:\n```bash\ncurl -d '{\"city\": \"Pasedena\",\"dob\": \"11/03/1980\",\"email\": \"lenny@caltech.com\",\"firstName\": \"Leonard\",\"gender\": \"male\",\"lastName\": \"Hofstader\",\"phoneNumber\": \"+811297983423\"}' -H \"Content-Type: application/json\" -X POST http://localhost:8080/users/\n```\n``\nHTTP STATUS: 201\n``\n```javascript\n{\n    \"city\": \"Pasedena\",\n    \"dob\": \"11/03/1980\",\n    \"email\": \"lenny@caltech.com\",\n    \"firstName\": \"Leonard\",\n    \"gender\": \"male\",\n    \"id\": 1,\n    \"lastName\": \"Hofstader\",\n    \"phoneNumber\": \"+811297983423\"\n}\n```\n\n*Possible error messages:*\n* Record Creation Failed!\n* Required Field(s) are Invalid! Field(s) : \u003clist-of-fields\u003e\n* Unable to Find Record with given data!\n* Internal Server Error! Please check Logs!\n\n\n#### /users/{user-id}\nGET:\n```bash\ncurl http://localhost:8080/users/1\n```\n``\nHTTP STATUS: 200\n``\n```javascript\n{\n    \"city\": \"Pasedena\",\n    \"dob\": \"11/03/1980\",\n    \"email\": \"lenny@caltech.com\",\n    \"firstName\": \"Leonard\",\n    \"gender\": \"male\",\n    \"id\": 1,\n    \"lastName\": \"Hofstader\",\n    \"phoneNumber\": \"+811297983423\"\n}\n```\n\n#### /users/{user-id}/accounts\nGET:\n```bash\ncurl http://localhost:8080/users/1/accounts\n```\n``\nHTTP STATUS: 200\n``\n```javascript\n[\n    {\n        \"accountNumber\": \"2321342SFDS12\",\n        \"accountType\": \"SAVINGS\",\n        \"balance\": 123.456,\n        \"currency\": \"USD\",\n        \"id\": 1,\n        \"timeCreated\": 1561723026458,\n        \"user\": {\n            \"city\": \"Pasedena\",\n            \"dob\": \"12/12/2019\",\n            \"email\": \"lenny@caltech.com\",\n            \"firstName\": \"Leonard\",\n            \"gender\": \"male\",\n            \"id\": 1,\n            \"lastName\": \"Hofstader\",\n            \"phoneNumber\": \"+811297983423\"\n        }\n    }\n]\n```\nPOST:\n```bash\ncurl -d '{\"accountNumber\" : \"2321342SFDS12\",\"accountType\" : \"SAVINGS\",\"currency\" : \"USD\",\"balance\" : 123.456}' -H \"Content-Type: application/json\" -X POST http://localhost:8080/users/1/accounts\n```\n``\nHTTP STATUS: 201\n``\n```javascript\n{\n    \"accountNumber\": \"2321342SFDS12\",\n    \"accountType\": \"SAVINGS\",\n    \"balance\": 123.456,\n    \"currency\": \"USD\",\n    \"id\": 1,\n    \"timeCreated\": 1561723026458,\n    \"user\": {\n        \"city\": null,\n        \"dob\": null,\n        \"email\": null,\n        \"firstName\": null,\n        \"gender\": null,\n        \"id\": 1,\n        \"lastName\": null,\n        \"phoneNumber\": null\n    }\n}\n```\n\n*Possible error messages:*\n* Record Creation Failed!\n* Required Field(s) are Invalid! Field(s) : \u003clist-of-fields\u003e\n* Unable to Find Record with given data!\n* Internal Server Error! Please check Logs!\n\n#### /users/{user-id}/accounts/{account-id}\nGET:\n```bash\ncurl http://localhost:8080/users/1/accounts/1\n```\n``\nHTTP STATUS: 200\n``\n```javascript\n{\n    \"accountNumber\": \"2321342SFDS12\",\n    \"accountType\": \"SAVINGS\",\n    \"balance\": 123.456,\n    \"currency\": \"USD\",\n    \"id\": 1,\n    \"timeCreated\": 1561723026458,\n    \"user\": {\n        \"city\": \"Pasedena\",\n        \"dob\": \"12/12/2019\",\n        \"email\": \"lenny@caltech.com\",\n        \"firstName\": \"Leonard\",\n        \"gender\": \"male\",\n        \"id\": 1,\n        \"lastName\": \"Hofstader\",\n        \"phoneNumber\": \"+811297983423\"\n    }\n}\n```\n\n#### /users/{user-id}/accounts/{account-id}/transactions\n\nGET:\n```bash\ncurl http://localhost:8080/users/1/accounts\n```\n``\nHTTP STATUS: 200\n``\n```javascript\n{\n    \"message\": \"Record Creation Failed!\"\n}\n```\nPOST (DEPOSIT):\n```bash\ncurl -d '{\"transactionType\" : \"CHEQUE_DEPOSIT\",\"amount\" : 100.00,\"currency\" : \"USD\"}' -H \"Content-Type: application/json\" -X POST http://localhost:8080/users/1/accounts/1\n```\n``\nHTTP STATUS: 304\n``\n```javascript\n{\n    \"amount\": 100,\n    \"currency\": \"USD\",\n    \"fromAccount\": null,\n    \"id\": 1,\n    \"timeCreated\": 0,\n    \"toAccount\": {\n        \"accountNumber\": \"2321342SFDS12\",\n        \"accountType\": \"SAVINGS\",\n        \"balance\": 223.45600000000002,\n        \"currency\": \"USD\",\n        \"id\": 1,\n        \"timeCreated\": 1561723026458,\n        \"user\": {\n            \"city\": \"Pasedena\",\n            \"dob\": \"12/12/2019\",\n            \"email\": \"lenny@caltech.com\",\n            \"firstName\": \"Leonard\",\n            \"gender\": \"male\",\n            \"id\": 1,\n            \"lastName\": \"Hofstader\",\n            \"phoneNumber\": \"+811297983423\"\n        }\n    },\n    \"transactionType\": \"CHEQUE_DEPOSIT\"\n}\n```\n\nPOST (TRANSFER):\n```bash\ncurl -d '{\"transactionType\" : \"TRANSFFER\", \"fromAccountId\" : 2,\"amount\" : 10.00,\"currency\" : \"USD\"}' -H \"Content-Type: application/json\" -X POST http://localhost:8080/users/1/accounts/1\n```\n``\nHTTP STATUS: 304\n``\n```javascript\n{\n    \"amount\": 100,\n    \"currency\": \"USD\",\n    \"fromAccount\": {\n        \"accountNumber\": \"1211342SFDS12\",\n        \"accountType\": \"SAVINGS\",\n        \"balance\": 23.456000000000003,\n        \"currency\": \"USD\",\n        \"id\": 2,\n        \"timeCreated\": 1561731946466,\n        \"user\": {\n            \"city\": \"Pasedena\",\n            \"dob\": \"12/12/2019\",\n            \"email\": \"penny@caltech.com\",\n            \"firstName\": \"Penny\",\n            \"gender\": \"female\",\n            \"id\": 2,\n            \"lastName\": \"Hofstader\",\n            \"phoneNumber\": \"+811297983423\"\n        }\n    },\n    \"id\": 1,\n    \"timeCreated\": 1561732053415,\n    \"toAccount\": {\n        \"accountNumber\": \"1211342SFDS12\",\n        \"accountType\": \"SAVINGS\",\n        \"balance\": 223.45600000000002,\n        \"currency\": \"USD\",\n        \"id\": 1,\n        \"timeCreated\": 1561731933733,\n        \"user\": {\n            \"city\": \"Pasedena\",\n            \"dob\": \"12/12/2019\",\n            \"email\": \"lenny@caltech.com\",\n            \"firstName\": \"Leonard\",\n            \"gender\": \"male\",\n            \"id\": 1,\n            \"lastName\": \"Hofstader\",\n            \"phoneNumber\": \"+811297983423\"\n        }\n    },\n    \"transactionType\": \"TRANSFER\"\n}\n```\n\n\n*Possible transaction types:*\n- TRANSFER\n- CHEQUE_DEPOSIT\n- CASH_DEPOSIT\n\n*Possible error messages:*\n* Record Creation Failed!\n* Unable to process transaction! Currency Conversion Not enabled\n* Unable to process transaction! Insufficient Balance in you Account!!\n* Required Field(s) are Invalid! Field(s) : \u003clist-of-fields\u003e\n* Unable to Find Record with given data!\n* Cannot transfer within the Same Account!\n* Internal Server Error! Please check Logs!\n\n\n#### /users/{user-id}/accounts/{account-id}/transactions/{transaction-id}\n\nGET:\n```bash\ncurl http://localhost:8080/users/1/accounts/1/transactions/1\n```\n``\nHTTP STATUS: 200\n``\n```javascript\n{\n    \"amount\": 100,\n    \"currency\": \"USD\",\n    \"fromAccount\": null,\n    \"id\": 1,\n    \"timeCreated\": 0,\n    \"toAccount\": {\n        \"accountNumber\": \"2321342SFDS12\",\n        \"accountType\": \"SAVINGS\",\n        \"balance\": 223.45600000000002,\n        \"currency\": \"USD\",\n        \"id\": 1,\n        \"timeCreated\": 1561723026458,\n        \"user\": {\n            \"city\": \"Pasedena\",\n            \"dob\": \"12/12/2019\",\n            \"email\": \"lenny@caltech.com\",\n            \"firstName\": \"Leonard\",\n            \"gender\": \"male\",\n            \"id\": 1,\n            \"lastName\": \"Hofstader\",\n            \"phoneNumber\": \"+811297983423\"\n        }\n    },\n    \"transactionType\": \"CHEQUE_DEPOSIT\"\n}\n```\n\n\n### Error handling\nAll the internal errors including runtime errors are handled at controller and sent as a valid response to user following is an example\n```bash\ncurl -d '{\"accountNumber\" : \"2321342SFDS12\",\"accountType\" : \"SAVINGS\",\"currency\" : \"USD\",\"balance\" : 123.456}' -H \"Content-Type: application/json\" -X POST http://localhost:8080/users/1/accounts\n```\n``\nHTTP STATUS: 304\n``\n```javascript\n{\n    \"message\": \"Record Creation Failed!\"\n}\n```\n\n\n## TDD - Red-\u003eGreen-\u003eRefactor cycle\n![TDD Diagram](red-green-refactor.png)\n\n### Unit test and Integration test coverage\n![Test Coverage](unit-tests-and-integration-tests.png)\n\n## Setup and launch\n\n### installing the packages\nWith Tests: \n```bash\n$ mvn clean install -U\n```\n\n### running tests\nUnit tests: \n```bash\n$ mvn  test\n```\nIntegration tests: \n```bash\n$ mvn integration-test\n```\n\n### running server\n```bash\n$ java  com.revolut.assesment.project.server.EmbeddedJettyServer\n ```\n\n## Libraries Used\nFollowing are the Libraries that are used as part of source and test cycles\n![Dependency Diagram](dependency-libraries.png)\n\n\u003e         Developed in Jetbrain's IntelliJ IDE\n\n## Challenges\n- Had a lot of challenges in setting up environment first with maven as there was a certificate issue that was messing with my maven commands due to network provider issues\n- Had difficulty in choosing the embedded server library as the prime objective was to keep the application light weight\n- Initially started with H2 in-memory DB and found out the hard way that it cannot be alive without a server/container or a EJB environment like JBoss.\n- Faced quite a lot of difficulties when trying to adapt the JAX-RS framework over the jetty-server library provided by sun.net and not the glassfish one.\n- Chose SQLite as it was serving the purpose and lightweight but I had to write a lot of boilerplate code initially as I was not able to find any ORM support like JPA adapting to JAX-RS and embedded server format.\n- But after spending a lot of time researching I have found a way to make JPA from hibernate support SQLite which let me throw away all my code involving explicit connection handling.\n- Had issues trying to setup integration tests, tried glassfish-jersey-client and faced a lot of dependency mismatch issues but finally found the restassured.io that helped me adapt to the sun.net jersey-client library.\n\n\n## References\n- Jersey-Server based Embedded Server supporting JAX-RS: https://dzone.com/articles/lightweight-embedded-java-rest-server-without-a-fr\n- Enabling CORS for the Above embedded server approach: https://crunchify.com/what-is-cross-origin-resource-sharing-cors-how-to-add-it-to-your-java-jersey-web-server/\n- https://dzone.com/articles/how-i-test-my-java-classes-for-thread-safety\n- JAXRS-H2: https://github.com/dprasanthv/JAX-RS-JPA-Hibernate-H2-In-Memory-Database\n- JPA-SQlite: https://github.com/juniorware/sqlite-jpa/\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frajagopal28%2Ftransaction-manager","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frajagopal28%2Ftransaction-manager","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frajagopal28%2Ftransaction-manager/lists"}