{"id":25658416,"url":"https://github.com/those-otter-programs/spring_boot_3_restfull_api","last_synced_at":"2026-05-14T01:33:14.246Z","repository":{"id":277557234,"uuid":"932300801","full_name":"Those-Otter-Programs/spring_boot_3_restfull_api","owner":"Those-Otter-Programs","description":"A Spring Boot 3 RESTfull API sample ","archived":false,"fork":false,"pushed_at":"2025-02-22T22:19:45.000Z","size":193,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"dev","last_synced_at":"2025-02-22T22:19:58.573Z","etag":null,"topics":["assertj","bddmockito","content-negotiation","cors","flyway","h2-database","hamcrest","hateoas","java17","jpa-hibernate","jwt-authentication","lombok","mapstruct","mockito","openapi","rest-assured","restfull-api","spring-boot-3","swagger-ui","testcontainers"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Those-Otter-Programs.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-02-13T17:35:03.000Z","updated_at":"2025-02-22T22:19:48.000Z","dependencies_parsed_at":"2025-02-14T15:43:32.947Z","dependency_job_id":"25eea4a9-2dda-421b-99b3-7e49120ca631","html_url":"https://github.com/Those-Otter-Programs/spring_boot_3_restfull_api","commit_stats":null,"previous_names":["those-otter-programs/spring_boot_3_restfull_api"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Those-Otter-Programs%2Fspring_boot_3_restfull_api","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Those-Otter-Programs%2Fspring_boot_3_restfull_api/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Those-Otter-Programs%2Fspring_boot_3_restfull_api/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Those-Otter-Programs%2Fspring_boot_3_restfull_api/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Those-Otter-Programs","download_url":"https://codeload.github.com/Those-Otter-Programs/spring_boot_3_restfull_api/tar.gz/refs/heads/dev","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":240396784,"owners_count":19794729,"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":["assertj","bddmockito","content-negotiation","cors","flyway","h2-database","hamcrest","hateoas","java17","jpa-hibernate","jwt-authentication","lombok","mapstruct","mockito","openapi","rest-assured","restfull-api","spring-boot-3","swagger-ui","testcontainers"],"created_at":"2025-02-24T00:20:59.250Z","updated_at":"2025-11-17T01:01:31.493Z","avatar_url":"https://github.com/Those-Otter-Programs.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Spring Boot 3 RESTful API\n## A Spring Boot 3 RESTfull API sample\n \n[![Buid Status](https://travis-ci.org/joemccann/dillinger.svg?branch=master)](https://travis-ci.org/joemccann/dillinger)\n\n[Project repository](https://github.com/Those-Otter-Programs/spring_boot_3_restfull_api)\n\n## Description:\nProject exemplifies the use of the following resources: \n\n    - It was used SOLID, DRY, KISS, FIRST and other useful principles.\n    - Design Patterns when reasonable to do so.\n    - Different environment profiles with different sets of configurations for\n      the Spring Security, Authenticated routes and databases.\n    - Custom database table to store and manage the system's users, which I \n      called Members in the system.\n    - HATEOAS\n    - Content Negotiation (JSON, XML and YML)\n    - CORS for origin filtering.\n    - Automatic Code Coverage generation (maven-surefire-plugin and JaCoCo).\n    - Spring Boot Security 6.4\n    - Authentication based on JWT tokens\n    - JWT tokens generation and validation through filters.\n    - Authentication events capture.\n    - Authentication/Authorization filters.\n    - Lombok\n    - Mapstruct\n    - OpenAPI\n    - H2 database in \"file-mode\", having the generated persistence \n      files store on the 'data' folder at the root of the project.\n    - Flyway to apply migrations to H2\n    - Using yaml files for the application properties.\n    - Tests and mocks:\n            Junit, Assertj, Rest Assured, Mockito, BDDMockito, Hamcrest...\n\n## Features:\n\n- The project evolved from a basic and simplistic implementation to a more complex yet minimalistic monolithic implementation, utilizing the latest versions of common Java resources and dependencies.\n- The objective was to test the new versions of the dependencies mentioned earlier by applying them to a micro-monolithic application. This test did not take into account concurrent or parallel access to the application's resources, particularly the database.\n- The decision to use the H2 database was based on its practicality. H2 is a relatively simple database, primarily used for testing. However, for a micro application like this, it allows us to complete tasks without the need to configure or run additional services or containers. It is portable and easy to manage.\n- The system creates database structures for different profiles (test, dev, prod) using Flyway migrations and an H2 (file-mode) database.\n- In the pom.xml file, the maven-surefire-plugin has been configured to work in conjunction with JaCoCo, generating automatic reports whenever 'mvn test' is executed.\n- MapStruct and Lombok working together, with the integration of Lombok’s MapStruct binding features.\n\n---\n\n## Controllers\n\n- [InfoController](#infocontroller)\n- [MemberController](#membercontroller)\n- [AuthenticationFailureLogController](#authenticationfailurelogcontroller)\n\n---\n\n## OpenAPI:\n```bash\nhttp://localhost:8080/swagger-ui/index.html\nhttp://localhost:8080/v3/api-docs\n```\n\n---\n\n## H2:\n\n```bash\nhttp://localhost:8080/h2\n```\n\n**H2 persistence base on environment profiles:**\n\n\n- **DEV** : jdbc:h2:file:./data/test_dev_db\n- **TEST** : jdbc:h2:file:./data/testdb\n- **PROD** : jdbc:h2:file:./data/test_prod_db\n\n---\n\n## JWT Token generation and use:\n\n```bash\n [GET] /api/member/v1/token\n```\n\n- This route requires basic authentication, and the accepted media type response \n  can be JSON (default), XML or YAML.\n- The response carries the JWT token on its header, in the 'Authorization' attribute, and\n  also in the body, through the property (or tag) 'token'.\n\n### To get the JWT token from the response body:\n\n```bash\n# ------------- JSON --------------\ncurl -s -u 'ayrton.senna@bravo.com:ayrton_pass' \\\n    -L -X GET 'http://localhost:8080/api/member/v1/token' | jq\n\n# Base64 encoded credentials:\ncurl -s -u 'YXlydG9uLnNlbm5hQGJyYXZvLmNvbTpheXJ0b25fcGFzcw=='\n    -L -X GET 'http://localhost:8080/api/member/v1/token' | jq\n\n# ------------- XML --------------\ncurl -s -u 'ayrton.senna@bravo.com:ayrton_pass' -H 'Accept: application/xml' \\\n    -L -X GET 'http://localhost:8080/api/member/v1/token' | xmllint --format -\n\n# ------------- YAML --------------\ncurl -s -u 'ayrton.senna@bravo.com:ayrton_pass' -H 'Accept: application/x-yaml' \\\n    -L -X GET 'http://localhost:8080/api/member/v1/token' | yq\n\n# ------------- CORS --------------\ncurl -s -u 'ayrton.senna@bravo.com:ayrton_pass' -H 'Origin: http://localhost:3000' \\\n    -L -X GET 'http://localhost:8080/api/member/v1/token' | yq\n```\n\n-- JSON response --\n\n```bash\n{\n    \"token\": [your-jwt-token]\n}\n```\n\n### To get the JWT token from the response headers:\n\n```bash\ncurl -s -I -u 'ayrton.senna@bravo.com:ayrton_pass' -L -X GET 'http://localhost:8080/api/member/v1/token'\n\n```\n\n-- response --\n\n```bash\nHTTP/1.1 200 \nAuthorization: [your-jwt-toke] \nSet-Cookie: JSESSIONID=598F62A04F9B40A6D85ECCF8F853F024; Path=/; HttpOnly\nVary: Origin\nVary: Access-Control-Request-Method\nVary: Access-Control-Request-Headers\nX-Content-Type-Options: nosniff\nX-XSS-Protection: 0\nCache-Control: no-cache, no-store, max-age=0, must-revalidate\nPragma: no-cache\nExpires: 0\nContent-Type: application/json\nTransfer-Encoding: chunked\nDate: Sun, 23 Feb 2025 15:43:44 GMT\n```\n\n### To get the JWT token from the response body and use it in other authenticated routes: \n\n```bash\n# BASH:\n\n# get the JWT token and stores it in a bash variable:\nmyJWTToken=`curl -s -u 'ayrton.senna@bravo.com:ayrton_pass' \\\n    -L -X GET 'http://localhost:8080/api/member/v1/token' | jq -r '.token'`\n        \n# run cURL using the variable as the authorization token:\ncurl -s -H \"Authorization: $myJWTToken\" \\\n    -L -X GET 'http://localhost:8080/api/member/v1/member-details/ayrton.senna@bravo.com' | jq\n```\n\n---\n\n## InfoController\n\nThis controller implements 3 actions:\n\n```bash\n [GET] /api/corporation/v1             - unautenticated route\n [GET] /api/corporation/v1/info        - unautenticated route\n [GET] /api/corporation/v1/info-corp   - authenticated route\n```\n    \n- This controller implements 3 routes.\n- Only Web layer tests.\n- **HATEOAS** - regardless of the selected Response data format, Responses \n  include HATEOAS links to make it a RESTful API.\n- **Content Negotiation** allow for Responses and Requests in JSON, XML and YML \n  data formats (**JSON by default**).\n\n\n***ROUTES:***\n\n**/api/corporation/v1**\n\n```bash\n# JSON response:\ncurl -s -L -X GET 'http://localhost:8080/api/corporation/v1' | jq\n\n# XML response:\ncurl -s -H 'Accept: application/xml' \\\n    -L -X GET 'http://localhost:8080/api/corporation/v1' | xmllint --format -\n\n# YAML response:\ncurl -s -H 'Accept: application/x-yaml' \\\n    -L -X GET 'http://localhost:8080/api/corporation/v1' | yq\n```\n\n**/api/corporation/v1/info**\n\n```bash\n# JSON response:\ncurl -s -L -X GET 'http://localhost:8080/api/corporation/v1/info' | jq\n\n# XML response:\ncurl -s -H 'Accept: application/xml' \\\n    -L -X GET 'http://localhost:8080/api/corporation/v1/info' | xmllint --format -\n\n# YAML response:\ncurl -s -H 'Accept: application/x-yaml' \\\n    -L -X GET 'http://localhost:8080/api/corporation/v1/info' | yq\n```\n\n**/api/corporation/v1/info-corp**\n\n```bash\n# BASH:\n\n# get the JWT token and stores it in a bash variable:\nmyJWTToken=`curl -s -u 'ayrton.senna@bravo.com:ayrton_pass' \\\n    -L -X GET 'http://localhost:8080/api/member/v1/token' | jq -r '.token'`\n\n# run cURL using the variable as the authorization token:\n\n# ------------- JSON --------------\ncurl -s -H \"Authorization: $myJWTToken\" \\\n    -L -X GET 'http://localhost:8080/api/corporation/v1/info-corp' | jq\n\n# ------------- XML ---------------\ncurl -s -H \"Authorization: $myJWTToken\" -H 'Accept: application/xml' \\\n    -L -X GET 'http://localhost:8080/api/corporation/v1/info-corp' | xmllint --format -\n\n# ------------- YAML --------------\ncurl -s -H \"Authorization: $myJWTToken\" -H 'Accept: application/x-yaml' \\\n    -L -X GET 'http://localhost:8080/api/corporation/v1/info-corp' | yq\n\n# ------------- CORS --------------\ncurl -s -H \"Authorization: $myJWTToken\" -H 'Accept: application/json' -H 'Origin: http://localhost:3000' \\\n    -L -X GET 'http://localhost:8080/api/corporation/v1/info-corp' | jq\n```\n\n---\n\n## MemberController\n\nThis controller implements routes to manage Members (Users), and also the action to generate the JWT tokens:\n\n- **HATEOAS** - regardless of the selected Response data format, Responses \n  include 'links' to make it a RESTful API.\n\n- **Content Negotiation** allow for Responses and Requests in JSON, XML and YML \n  data formats (**JSON by default**).\n\n- **Pagination** - paginated list of members on /api/member/v1/list, with page number, size (quantity), and sorting direction \n\n```\n   [GET] /api/member/v1/token\n  [POST] /api/member/v1/member-create\n   [GET] /api/member/v1/list \n   [GET] /api/member/v1/member-full-details/{username} \n   [GET] /api/member/v1/member-details/{username} \n   [GET] /api/member/v1/me \n   [PUT] /api/member/v1/member-update \n [PATCH] /api/member/v1/member-password\n [PATCH] /api/member/v1/manage-member-password\n [PATCH] /api/member/v1/member-disable/{id}\n [PATCH] /api/member/v1/member-enable/{id}\n [PATCH] /api/member/v1/member-lock/{id}\n [PATCH] /api/member/v1/member-unlock/{id}\n```\n\n### REQUESTS /api/member/v1/member-create:\n##### Requesting the JWT token and saving it into a bash variable:\n\n```bash\n\n# Requesting the JWT token and storing it in a bash variable\nmyJWTToken=`curl -s -u 'ayrton.senna@bravo.com:ayrton_pass' \\\n    -L -X GET 'http://localhost:8080/api/member/v1/token' | jq -r '.token'`\n\n```\n\n##### REQUEST ---\u003e sending JSON data:\n\n```bash \n# JSON request and response:\ncurl -s -H \"Authorization: $myJWTToken\" -H 'Content-Type: application/json' \\\n    -L -X POST 'http://localhost:8080/api/member/v1/member-create' \\\n    -d '{\n            \"memberName\":\"Rubens Barrichello\", \n            \"memberEmail\":\"rubens.barrichello@bravo.com\",\n            \"memberMobileNumber\":\"(11) 98765-4321\", \n            \"memberPassword\": \"barrichello_pass\",\n            \"memberAuthorities\": [\n                \"ROLE_ADMIN\"\n            ]\n        }' | jq\n```\n\n##### REQUEST ---\u003e sending XML data:\n\n```bash \n# XML request and response:\ncurl -s -H \"Authorization: $myJWTToken\" -H 'Accept: application/xml' -H 'Content-Type: application/xml' \\\n    -L -X POST 'http://localhost:8080/api/member/v1/member-create' \\\n    -d '\u003cMemberCreateRequest\u003e\n            \u003cmemberName\u003eEmerson Fittipaldi\u003c/memberName\u003e\n            \u003cmemberEmail\u003eemerson.fittipaldi@bravo.com\u003c/memberEmail\u003e\n            \u003cmemberMobileNumber\u003e(11) 98765-4321\u003c/memberMobileNumber\u003e\n            \u003cmemberPassword\u003efittipaldi_pass\u003c/memberPassword\u003e\n            \u003cmemberAuthorities\u003e\n                \u003cmemberAuthorities\u003eROLE_ADMIN\u003c/memberAuthorities\u003e\n            \u003c/memberAuthorities\u003e\n        \u003c/MemberCreateRequest\u003e' | xmllint --format -\n```\n\n##### REQUEST ---\u003e sending YAML data:\n\n```bash\n# YAML request and response:\ncurl -s -H \"Authorization: $myJWTToken\" -H 'Accept: application/x-yaml' -H 'Content-Type: application/x-yaml' \\\n    -L -X POST 'http://localhost:8080/api/member/v1/member-create' \\\n    -d '---\n        memberName: \"Nelson Piquet\"\n        memberEmail: \"nelson.piquet@bravo.com\"\n        memberMobileNumber: \"(11) 98765-4321\"\n        memberPassword: \"piquet_pass\"\n        memberAuthorities:\n            - \"ROLE_ADMIN\"' | yq\n```\n\n##### REQUEST ---\u003e with CORS origin filtering:\n```bash\n# CORS - origin filter and JSON request / response\ncurl -s -H \"Authorization: $myJWTToken\" -H 'Origin: http://localhost:3000' \\\n    -H 'Content-Type: application/json' \\\n    -L -X POST 'http://localhost:8080/api/member/v1/member-create' \\\n    -d '{\n            \"memberName\":\"Felipe Massa\", \n            \"memberEmail\":\"felipe.massa@bravo.com\",\n            \"memberMobileNumber\":\"(11) 98765-4321\", \n            \"memberPassword\": \"massa_pass\",\n            \"memberAuthorities\": [\n                \"ROLE_ADMIN\"\n            ]\n        }' | jq\n```\n\n### REQUESTS /api/member/v1/list:\n\nPaginated params for this request:\n\n- **page**: *(default: 0)* the page number to be shown (determined by the quantity of members in the database divided by the value of the '**size**' param, which is explained bellow)\n- **size**: *(default: 8)* the quantity of members to be showed per page\n- **sortDir**: *(default: asc)* the sorting direction, if asc or desc.\n- **sortBy**: *(default: memberEmail)* the data wich the sorting must be based (memberEmail, memberId, and so on..)\n\n##### OBSERVATIONS:\n\n**sortDir:** \nIt selects 'asc' (ascending) sort direction, in case an invalid sorting direction is received.\n\n**sortBy:** \nIt throws a custom exception (InvalidSortByException) in case the value is not a member data, which would make it an unsortable data.\n\n\n```bash\n\n# Requesting the JWT token and storing it in a bash variable\nmyJWTToken=`curl -s -u 'ayrton.senna@bravo.com:ayrton_pass' \\\n    -L -X GET 'http://localhost:8080/api/member/v1/token' | jq -r '.token'`\n\n# run cURL using the variable as the authorization token:\n\n# ------------- JSON - PAGINATED --------------\ncurl -s -H \"Authorization: $myJWTToken\" \n    -L -X GET 'http://localhost:8080/api/member/v1/list?page=0\u0026size=8\u0026sortDir=desc\u0026sortBy=memberId' | jq\n\ncurl -s -H \"Authorization: $myJWTToken\" \n    -L -X GET 'http://localhost:8080/api/member/v1/list?page=0\u0026size=8\u0026sortDir=desc' | jq\n\ncurl -s -H \"Authorization: $myJWTToken\" \n    -L -X GET 'http://localhost:8080/api/member/v1/list?page=0\u0026size=8' | jq\n\ncurl -s -H \"Authorization: $myJWTToken\" \n    -L -X GET 'http://localhost:8080/api/member/v1/list?page=0' | jq\n\ncurl -s -H \"Authorization: $myJWTToken\" \n-L -X GET 'http://localhost:8080/api/member/v1/list' | jq\n\n# -------------- XML - PAGINATED --------------\ncurl -s -H \"Authorization: $myJWTToken\" -H 'Accept: application/xml' \\\n    -L -X GET 'http://localhost:8080/api/member/v1/list?page=0\u0026size=8\u0026sortDir=desc\u0026sortBy=memberId' | xmllint --format -\n\n# ------------- YAML - PAGINATED --------------\ncurl -s -H \"Authorization: $myJWTToken\" -H 'Accept: application/x-yaml' \\\n    -L -X GET 'http://localhost:8080/api/member/v1/list?page=0\u0026size=8\u0026sortDir=desc\u0026sortBy=memberId' | yq\n\n# ------------- CORS - PAGINATED --------------\ncurl -s -H \"Authorization: $myJWTToken\" -H 'Origin: http://localhost:3000' \\\n    -L -X GET 'http://localhost:8080/api/member/v1/list?page=0\u0026size=8\u0026sortDir=desc\u0026sortBy=memberId' | jq\n\n```\n\n### REQUESTS /api/member/v1/member-full-details/{username} \n\n\n```bash\n# Requesting the JWT token and storing it in a bash variable\nmyJWTToken=`curl -s -u 'ayrton.senna@bravo.com:ayrton_pass' \\\n    -L -X GET 'http://localhost:8080/api/member/v1/token' | jq -r '.token'`\n\n# run cURL using the variable as the authorization token:\n\n# ------------- JSON --------------\ncurl -s -H \"Authorization: $myJWTToken\" \\\n    -L -X GET 'http://localhost:8080/api/member/v1/member-full-details/ayrton.senna@bravo.com' | jq\n\n# ------------- XML --------------\ncurl -s -H \"Authorization: $myJWTToken\" -H 'Accept: application/xml' \\\n    -L -X GET 'http://localhost:8080/api/member/v1/member-full-details/ayrton.senna@bravo.com' \\\n    | xmllint --format -\n\n# ------------- YAML --------------\ncurl -s -H \"Authorization: $myJWTToken\" -H 'Accept: application/x-yaml' \\\n    -L -X GET 'http://localhost:8080/api/member/v1/member-full-details/ayrton.senna@bravo.com' | yq\n\n# ------------- CORS --------------\ncurl -s -H \"Authorization: $myJWTToken\" -H 'Origin: http://localhost:3000' \\\n    -L -X GET 'http://localhost:8080/api/member/v1/member-full-details/ayrton.senna@bravo.com' | jq\n```\n\n### REQUESTS /api/member/v1/member-details/{username} \n\n\n```bash\n# Requesting the JWT token and storing it in a bash variable\nmyJWTToken=`curl -s -u 'ayrton.senna@bravo.com:ayrton_pass' \\\n    -L -X GET 'http://localhost:8080/api/member/v1/token' | jq -r '.token'`\n\n# run cURL using the variable as the authorization token:\n\n# ------------- JSON --------------\ncurl -s -H \"Authorization: $myJWTToken\" \\\n    -L -X GET 'http://localhost:8080/api/member/v1/member-details/ayrton.senna@bravo.com' | jq\n\n# ------------- XML --------------\ncurl -s -H \"Authorization: $myJWTToken\" -H 'Accept: application/xml' \\\n    -L -X GET 'http://localhost:8080/api/member/v1/member-details/ayrton.senna@bravo.com' \\\n    | xmllint --format -\n\n# ------------- YAML --------------\ncurl -s -H \"Authorization: $myJWTToken\" -H 'Accept: application/x-yaml' \\\n    -L -X GET 'http://localhost:8080/api/member/v1/member-details/ayrton.senna@bravo.com' | yq\n\n# ------------- CORS --------------\ncurl -s -H \"Authorization: $myJWTToken\" -H 'Origin: http://localhost:3000' \\\n    -L -X GET 'http://localhost:8080/api/member/v1/member-details/ayrton.senna@bravo.com' | jq\n```\n\n### REQUESTS /api/member/v1/me \n\n```bash\n# Requesting the JWT token and storing it in a bash variable\nmyJWTToken=`curl -s -u 'ayrton.senna@bravo.com:ayrton_pass' \\\n    -L -X GET 'http://localhost:8080/api/member/v1/token' | jq -r '.token'`\n\n# run cURL using the variable as the authorization token:\n\n# ------------- JSON --------------\ncurl -s -H \"Authorization: $myJWTToken\" \\\n    -L -X GET 'http://localhost:8080/api/member/v1/me' | jq\n\n# ------------- XML --------------\ncurl -s -H \"Authorization: $myJWTToken\" -H 'Accept: application/xml' \\\n    -L -X GET 'http://localhost:8080/api/member/v1/me' | xmllint --format -\n\n# ------------- YAML --------------\ncurl -s -H \"Authorization: $myJWTToken\" -H 'Accept: application/x-yaml' \\\n    -L -X GET 'http://localhost:8080/api/member/v1/me' | yq\n\n# ------------- CORS --------------\ncurl -s -H \"Authorization: $myJWTToken\" -H 'Origin: http://localhost:3000' \\\n    -L -X GET 'http://localhost:8080/api/member/v1/me' | jq\n```\n\n### REQUESTS /api/member/v1/member-update \n\n##### Requesting the JWT token and saving it into a bash variable:\n\n```bash\n# Requesting the JWT token and storing it in a bash variable\nmyJWTToken=`curl -s -u 'ayrton.senna@bravo.com:ayrton_pass' \\\n    -L -X GET 'http://localhost:8080/api/member/v1/token' | jq -r '.token'`\n```\n\n##### REQUEST ---\u003e sending JSON data:\n\n```bash \n# ------------- JSON (request and response) --------------\ncurl -s -H \"Authorization: $myJWTToken\" -H 'Content-Type: application/json' \\\n    -L -X PUT 'http://localhost:8080/api/member/v1/member-update' \\\n    -d '{\n            \"membrerId\": 51,\n            \"memberName\":\"Rubens Barrichello\", \n            \"memberEmail\":\"rubens.barrichello@bravo.com\",\n            \"memberMobileNumber\":\"(11) 98765-4321\", \n            \"memberPassword\": \"barrichello_pass\",\n            \"memberAuthorities\": [\n                \"ROLE_ADMIN\"\n            ]\n        }' | jq\n```\n\n##### REQUEST ---\u003e sending XML data:\n```bash\n# -------------- XML (request and response) --------------\ncurl -s -H \"Authorization: $myJWTToken\" -H 'Accept: application/xml' \\\n    -H 'Content-Type: application/xml' \\\n    -L -X PUT 'http://localhost:8080/api/member/v1/member-update' \\\n    -d '\u003cMemberCreateRequest\u003e\n            \u003cmemberId\u003e52\u003c/memberId\u003e\n            \u003cmemberName\u003eEmerson Fittipaldi\u003c/memberName\u003e\n            \u003cmemberEmail\u003eemerson.fittipaldi@bravo.com\u003c/memberEmail\u003e\n            \u003cmemberMobileNumber\u003e(11) 98765-4321\u003c/memberMobileNumber\u003e\n            \u003cmemberPassword\u003efittipaldi_pass\u003c/memberPassword\u003e\n            \u003cmemberAuthorities\u003e\n                \u003cmemberAuthorities\u003eROLE_ADMIN\u003c/memberAuthorities\u003e\n            \u003c/memberAuthorities\u003e\n        \u003c/MemberCreateRequest\u003e' | xmllint --format - \n```\n\n##### REQUEST ---\u003e sending YAML data:\n```bash\n# ------------- YAML (request and response) --------------\ncurl -s -H \"Authorization: $myJWTToken\" -H 'Accept: application/x-yaml' \\\n    -H 'Content-Type: application/x-yaml' \\\n    -L -X PUT 'http://localhost:8080/api/member/v1/member-update' \\\n    -d '---\n        memberId: 53\n        memberName: \"Nelson Piquet\"\n        memberEmail: \"nelson.piquet@bravo.com\"\n        memberMobileNumber: \"(11) 98765-4321\"\n        memberPassword: \"piquet_pass\"\n        memberAuthorities:\n            - \"ROLE_ADMIN\"' | yq\n```\n\n##### REQUEST ---\u003e with CORS origin filtering:\n```bash\n# ------------- CORS - origin filter and JSON request / response -------------\ncurl -s -H \"Authorization: $myJWTToken\" -H 'Origin: http://localhost:3000' \\\n    -H 'Content-Type: application/json' \\\n    -L -X PUT 'http://localhost:8080/api/member/v1/member-update' \\\n    -d '{\n            \"memberId\": 54,\n            \"memberName\":\"Felipe Massa\", \n            \"memberEmail\":\"felipe.massa@bravo.com\",\n            \"memberMobileNumber\":\"(11) 98765-4321\", \n            \"memberPassword\": \"massa_pass\",\n            \"memberAuthorities\": [\n                \"ROLE_ADMIN\"\n            ]\n        }' | jq\n```\n\n### REQUESTS /api/member/v1/member-password\n\n##### Requesting the JWT token and saving it into a bash variable:\n\n```bash\n# Requesting the JWT token and storing it in a bash variable\nmyJWTToken=`curl -s -u 'ayrton.senna@bravo.com:ayrton_pass' \\\n    -L -X GET 'http://localhost:8080/api/member/v1/token' | jq -r '.token'`\n```\n\n##### REQUEST ---\u003e [PATCH] Requesting JSON data:\n\n```bash\ncurl -s -H \"Authorization: $myJWTToken\" \\\n    -L -X PATCH 'http://localhost:8080/api/member/v1/member-password' \\\n    -d '{\"newPassword\": \"mynewpassword\"}' | jq\n```\n\n##### REQUEST ---\u003e [PATCH] Requesting XML data:\n\n```bash\ncurl -s -H \"Authorization: $myJWTToken\" -H 'Accept: application/xml' -H 'Content-Type: application/xml' \\\n    -L -X PATCH 'http://localhost:8080/api/member/v1/member-password' \\\n    -d '\u003cMemberUpdatePasswordRequest\u003e\n       \t    \u003cnewPassword\u003emynewpassword\u003c/newPassword\u003e\n       \t\u003c/MemberUpdatePasswordRequest\u003e' | xmllint --format -\n```\n\n##### REQUEST ---\u003e [PATCH] Requesting YAMLL data:\n\n```bash\ncurl -s -H \"Authorization: $myJWTToken\" -H 'Accept: application/x-yaml' -H 'Content-Type: application/x-yaml' \\\n    -L -X PATCH 'http://localhost:8080/api/member/v1/member-password' \\\n    -d '--- newPassword: \"mynewpassword\"' | yq\n```\n\n##### REQUEST ---\u003e [PATCH] Requesting JSON data with CORS origin filtering:\n\n```bash\ncurl -s -H \"Authorization: $myJWTToken\" -H 'Origin: http://localhost:3000' \\\n    -L -X PATCH 'http://localhost:8080/api/member/v1/member-password' \\\n    -d '{\"newPassword\": \"mynewpassword\"}' | jq\n```\n\n### REQUESTS /api/member/v1/manage-member-password\n\n##### Requesting the JWT token and saving it into a bash variable:\n\n```bash\n# Requesting the JWT token and storing it in a bash variable\nmyJWTToken=`curl -s -u 'ayrton.senna@bravo.com:ayrton_pass' \\\n    -L -X GET 'http://localhost:8080/api/member/v1/token' | jq -r '.token'`\n```\n\n##### REQUEST ---\u003e [PATCH] Sending and requesting JSON data:\n\n```bash \ncurl -s -H \"Authorization: $myJWTToken\" \\\n    -L -X PATCH 'http://localhost:8080/api/member/v1/manage-member-password' \\\n    -d '{\"memberUsername\": \"mfredson2@amazon.com\", \"memberPassword\": \"newpassword\"}' | jq\n\n```\n\n##### REQUEST ---\u003e [PATCH] Sending JSON data and requesting XML data:\n\n```bash \ncurl -s -H \"Authorization: $myJWTToken\" -H 'Accept: application/xml' \\\n    -H 'Content-Type: application/xml' \\\n    -L -X PATCH 'http://localhost:8080/api/member/v1/manage-member-password' \\\n    -d '\u003cMemberManagePasswordRequest\u003e\n       \t\t\u003cmemberUsername\u003emfredson2@amazon.com\u003c/memberUsername\u003e\n       \t\t\u003cmemberPassword\u003enewpassword\u003c/memberPassword\u003e\n       \t\u003c/MemberManagePasswordRequest\u003e' | xmllint --format -\n```\n       \n##### REQUEST ---\u003e [PATCH] Sending JSON data and requesting YAML data:\n\n```bash \ncurl -s -H \"Authorization: $myJWTToken\" -H 'Accept: application/x-yaml' \\\n    -H 'Content-Type: application/x-yaml' \\\n    -L -X PATCH 'http://localhost:8080/api/member/v1/manage-member-password' \\\n    -d '---\n        memberUsername: \"Nelson Piquet\"\n        memberPassword: \"newpassword\"' | yq\n```\n       \n##### REQUEST ---\u003e [PATCH] Sending and requesting JSON data with CORS origin filtering:\n\n```bash \ncurl -s -H \"Authorization: $myJWTToken\" -H 'Origin: http://localhost:3000' \\\n    -L -X GET 'http://localhost:8080/api/member/v1/manage-member-password' \\\n    -d '{\"memberUsername\": \"mfredson2@amazon.com\", \"memberPassword\": \"newpassword\"}' \\\n    | jq\n```\n\n### REQUESTS /api/member/v1/member-disable/{id}\n\n```bash\n# Requesting the JWT token and storing it in a bash variable\nmyJWTToken=`curl -s -u 'ayrton.senna@bravo.com:ayrton_pass' \\\n    -L -X GET 'http://localhost:8080/api/member/v1/token' | jq -r '.token'`\n\n# run cURL using the variable as the authorization token:\n\n# ------------- JSON --------------\ncurl -s -H \"Authorization: $myJWTToken\" \\\n    -L -X PATCH 'http://localhost:8080/api/member/v1/member-disable/3' | jq\n\n# ------------- XML --------------\ncurl -s -H \"Authorization: $myJWTToken\" -H 'Accept: application/xml' \\\n    -L -X PATCH 'http://localhost:8080/api/member/v1/member-disable/3' | xmllint --format -\n\n# ------------- YAML --------------\ncurl -s -H \"Authorization: $myJWTToken\" -H 'Accept: application/x-yaml' \\\n    -L -X PATCH 'http://localhost:8080/api/member/v1/member-disable/3' | yq\n\n# ------------- CORS --------------\ncurl -s -H \"Authorization: $myJWTToken\" -H 'Origin: http://localhost:3000' \\\n    -L -X PATCH 'http://localhost:8080/api/member/v1/member-disable/3' | jq\n```\n\n### REQUESTS /api/member/v1/member-enable/{id}\n\n```bash\n# Requesting the JWT token and storing it in a bash variable\nmyJWTToken=`curl -s -u 'ayrton.senna@bravo.com:ayrton_pass' \\\n    -L -X GET 'http://localhost:8080/api/member/v1/token' | jq -r '.token'`\n\n# ------------- JSON --------------\ncurl -s -H \"Authorization: $myJWTToken\" \\\n    -L -X PATCH 'http://localhost:8080/api/member/v1/member-enable/3' | jq\n\n# -------------- XML --------------\ncurl -s -H \"Authorization: $myJWTToken\" -H 'Accept: application/xml' \\\n    -L -X PATCH 'http://localhost:8080/api/member/v1/member-enable/3' | xmllint --format -\n\n# ------------- YAML --------------\ncurl -s -H \"Authorization: $myJWTToken\" -H 'Accept: application/x-yaml' \\\n    -L -X PATCH 'http://localhost:8080/api/member/v1/member-enable/3' | yq\n\n# ------------- CORS --------------\ncurl -s -H \"Authorization: $myJWTToken\" -H 'Origin: http://localhost:3000' \\\n    -L -X PATCH 'http://localhost:8080/api/member/v1/member-enable/3' | jq\n```\n\n### REQUESTS /api/member/v1/member-lock/{id}\n\n```bash\n# Requesting the JWT token and storing it in a bash variable\nmyJWTToken=`curl -s -u 'ayrton.senna@bravo.com:ayrton_pass' \\\n    -L -X GET 'http://localhost:8080/api/member/v1/token' | jq -r '.token'`\n\n# ------------- JSON --------------\ncurl -s -H \"Authorization: $myJWTToken\" \\\n    -L -X PATCH 'http://localhost:8080/api/member/v1/member-lock/3' | jq\n\n# -------------- XML --------------\ncurl -s -H \"Authorization: $myJWTToken\" -H 'Accept: application/xml' \\\n    -L -X PATCH 'http://localhost:8080/api/member/v1/member-lock/3' | xmllint --format -\n\n# ------------- YAML --------------\ncurl -s -H \"Authorization: $myJWTToken\" -H 'Accept: application/x-yaml' \\\n    -L -X PATCH 'http://localhost:8080/api/member/v1/member-lock/3' | yq\n\n# ------------- CORS --------------\ncurl -s -H \"Authorization: $myJWTToken\" \\\n    -H 'Origin: http://localhost:3000' \\\n    -L -X PATCH 'http://localhost:8080/api/member/v1/member-lock/3' | jq\n```\n\n### REQUESTS /api/member/v1/member-unlock/{id}\n\n```bash\n# Requesting the JWT token and storing it in a bash variable\nmyJWTToken=`curl -s -u 'ayrton.senna@bravo.com:ayrton_pass' \\\n    -L -X GET 'http://localhost:8080/api/member/v1/token' | jq -r '.token'`\n\n# ------------- JSON --------------\ncurl -s -H \"Authorization: $myJWTToken\" \\\n    -L -X PATCH 'http://localhost:8080/api/member/v1/member-unlock/3' | jq\n\n# -------------- XML --------------\ncurl -s -H \"Authorization: $myJWTToken\" -H 'Accept: application/xml' \\\n    -L -X PATCH 'http://localhost:8080/api/member/v1/member-unlock/3' | xmllint --format -\n\n# ------------- YAML --------------\ncurl -s -H \"Authorization: $myJWTToken\" -H 'Accept: application/x-yaml' \\\n    -L -X PATCH 'http://localhost:8080/api/member/v1/member-unlock/3' | yq\n\n# ------------- CORS --------------\ncurl -s -H \"Authorization: $myJWTToken\" \\\n    -H 'Origin: http://localhost:3000' \\\n    -L -X PATCH 'http://localhost:8080/api/member/v1/member-unlock/3' | jq\n```\n\n## AuthenticationFailureLogController\n\nThis controller implements routes to manage Members (Users), and also the action to generate the JWT tokens:\n\n- **HATEOAS** - regardless of the selected Response data format, Responses \n  include 'links' to make it a RESTful API.\n\n- **Content Negotiation** allow for Responses and Requests in JSON, XML and YML \n  data formats (**JSON by default**).\n\n- **Pagination** - paginated list of members on /api/authentication-failure/v1/member/{username}, with page number, size (quantity), and sorting direction \n\n```\n   [GET] /api/authentication-failure/v1/member/{username}\n   [GET] /api/authentication-failure/v1/log/{id} \n```\n\n### REQUESTS /api/authentication-failure/v1/member/{username}:\n\nPaginated params for this request:\n\n- **page**: *(default: 0)* the page number to be shown (determined by the quantity of a member's logs in the database divided by the value of the '**size**' param, which is explained bellow)\n- **size**: *(default: 8)* the quantity of a member's authentication failure logs to be showed per page\n- **sortDir**: *(default: asc)* the sorting direction, if asc or desc.\n- **sortBy**: *(default: memberEmail)* the data wich the sorting must be based (memberEmail, memberId, and so on..)\n\n##### OBSERVATIONS:\n\n**sortDir:** \nIt selects 'asc' (ascending) sort direction, in case an invalid sorting direction is received.\n\n**sortBy:** \nIt throws a custom exception (InvalidSortByException) in case the value is not a member's log data, which would make it an unsortable data.\n\n\n```bash\n\n# Requesting the JWT token and storing it in a bash variable\nmyJWTToken=`curl -s -u 'ayrton.senna@bravo.com:ayrton_pass' \\\n    -L -X GET 'http://localhost:8080/api/member/v1/token' | jq -r '.token'`\n\n# run cURL using the variable as the authorization token:\n\n# ------------- JSON - PAGINATED --------------\ncurl -s -H \"Authorization: $myJWTToken\" \\\n    -L -X GET 'http://localhost:8080/api/authentication-failure/v1/member/ayrton.senna@bravo.com?page=0\u0026size=8\u0026sortDir=desc\u0026sortBy=logAuthTime' | jq\n    \ncurl -s -H \"Authorization: $myJWTToken\" \\\n    -L -X GET 'http://localhost:8080/api/authentication-failure/v1/member/ayrton.senna@bravo.com?page=0\u0026size=8\u0026sortDir=desc' | jq\n\ncurl -s -H \"Authorization: $myJWTToken\" \\\n    -L -X GET 'http://localhost:8080/api/authentication-failure/v1/member/ayrton.senna@bravo.com?page=0\u0026size=8' | jq\n    \ncurl -s -H \"Authorization: $myJWTToken\" \\\n    -L -X GET 'http://localhost:8080/api/authentication-failure/v1/member/ayrton.senna@bravo.com?page=0' | jq\n    \ncurl -s -H \"Authorization: $myJWTToken\" \\\n    -L -X GET 'http://localhost:8080/api/authentication-failure/v1/member/ayrton.senna@bravo.com' | jq\n\n# -------------- XML - PAGINATED --------------\ncurl -s -H \"Authorization: $myJWTToken\" -H 'Accept: application/xml' \\\n    -L -X GET 'http://localhost:8080/api/authentication-failure/v1/member/ayrton.senna@bravo.com?page=0\u0026size=8\u0026sortDir=desc\u0026sortBy=logAuthTime' \\\n    | xmllint --format -\n\n# ------------- YAML - PAGINATED --------------\ncurl -s -H \"Authorization: $myJWTToken\" -H 'Accept: application/x-yaml' \\\n    -L -X GET 'http://localhost:8080/api/authentication-failure/v1/member/ayrton.senna@bravo.com?page=0\u0026size=8\u0026sortDir=desc\u0026sortBy=logAuthTime' \\\n    | yq\n\n# ------------- CORS - PAGINATED --------------\ncurl -s -H \"Authorization: $myJWTToken\" -H 'Origin: http://localhost:3000' \\\n    -L -X GET 'http://localhost:8080/api/authentication-failure/v1/member/ayrton.senna@bravo.com?page=0\u0026size=8\u0026sortDir=desc\u0026sortBy=logAuthTime' \\\n    | jq\n\n```\n\n### REQUESTS /api/authentication-failure/v1/log/{id}\n\n```bash\n# Requesting the JWT token and storing it in a bash variable\nmyJWTToken=`curl -s -u 'ayrton.senna@bravo.com:ayrton_pass' \\\n    -L -X GET 'http://localhost:8080/api/member/v1/token' | jq -r '.token'`\n\n# run cURL using the variable as the authorization token:\n\n# ------------- JSON --------------\ncurl -s -H \"Authorization: $myJWTToken\" \\\n    -L -X GET 'http://localhost:8080/api/authentication-failure/v1/log/1' | jq\n\n# -------------- XML --------------\ncurl -s -H \"Authorization: $myJWTToken\" -H 'Accept: application/xml' \\\n    -L -X GET 'http://localhost:8080/api/authentication-failure/v1/log/1' | xmllint --format -\n\n# ------------- YAML --------------\ncurl -s -H \"Authorization: $myJWTToken\" -H 'Accept: application/x-yaml' \\\n    -L -X GET 'http://localhost:8080/api/authentication-failure/v1/log/1' | yq\n\n# ------------- CORS --------------\ncurl -s -H \"Authorization: $myJWTToken\" -H 'Origin: http://localhost:3000' \\\n    -L -X GET 'http://localhost:8080/api/authentication-failure/v1/log/1' | jq\n```\n\n---\n\n## TO BE CONTINUED...\n---\n\n## Author: James Mallon\n- [github](https://github.com/jamesmallon)\n- [linkedin](https://www.linkedin.com/in/roccojamesmallon/)\n\n## License\n[Apache 2.0](LICENSE)\n\n---\n### Have a drink...\n\n![Have a good one](src/main/resources/imgs/cool_otter.jpg)\n\n---\n\u003e If you want to be a lion, you must train with lions.\n\u003e -- Carlos Gracie, Sr","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fthose-otter-programs%2Fspring_boot_3_restfull_api","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fthose-otter-programs%2Fspring_boot_3_restfull_api","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fthose-otter-programs%2Fspring_boot_3_restfull_api/lists"}