In this document (future) developers and contributors can find more information about the backend server repository of the MedTech Chain project.
Below is an index for the Java classes together with their purpose. All these classes can be found in src/main/java/nl/medtechchain/ directory.
- GatewayConfig.java : A configuration class for the Fabric Gateway. For testing, it has to be mocked (see variable
gateway.mockin application.properties) - JacksonConfig.java: A configuration class for ObjectMapper to specify custom JSON (de)serializers.
- PasswordConfig.java: A configuration class for the (BCrypt) PasswordEncoder.
- SecurityConfig.java: A configuration class for some of the Spring Security components (such as SecurityFilterChain, AuthenticationProvider, AuthenticationManager, CorsConfigurationSource). In this class, authorization requirements are defined for the endpoints (e.g. some endpoints are only accessible for admin, others for both admin and researcher).
- error
- ErrorResponse : A custom class for error responses.
- GlobalExceptionHandler: A class for global exception handling.
- ApiEndpoints: A class that contains all supported API endpoints, so that they can be accessed from all places (for easy reference and modification).
- UserController.java: A controller class that provides API endpoints for managing users and interacts with the AuthenticationService class. For the full API documentation, see docs/ directory. Possible operations are:
- POST
/api/users/login(accessible for all) - POST
/api/users/register(accessible only for admin) - GET
/api/users/researchers(accessible only for admin) - PUT
/api/users/update(accessible only for admin) - DELETE
/api/users/delete(accessible only for admin) - PUT
/api/users/change_password(accessible for all)
- POST
- QueryController.java: A controller class that gets queries from researchers, sends them to the blockchain and returns the result. For the full API documentation, see docs/ directory. Possible operations are:
- POST
/api/queries(accessible only for researchers)
- POST
- JwtAuthenticationFilter.java: A class that represents a custom authentication filter based on JWT.
- JwtProvider.java: A class that manages JWTs, i.e. generation, parsing and validation etc.
- JwtSecretKey.java: A configuration class for creating the JWT key.
- email
- EmailData: An abstract class that stores the basic email data (recipient, subject and template) and is used to store the data common for all email types (i.e. child classes).
- CredentialsEmail: A class that stores the data necessary to send an email with the credentials when registering a new user.
- Researcher.java: A DTO class for a researcher that will be sent when researchers have been requested.
- UserData.java: A class that is used to store the user data (userID, username, password, email, first name, last name, affiliation etc.).
- UserRole.java: An enum class used to represent different user roles (currently "admin" and "researcher"), used for authorization checks when accessing endpoints. A new user is registered as researcher and this role cannot be changed. There is only one admin.
- JsonToProtobufDeserializer: A custom deserializer for the Query (protobuf) object, which is used when receiving a query request with JSON body which has to be forwarded to the blockchain.
- UserDataRepository.java: A class for the database that stores the user data (see UserData.java class).
- AuthenticationService.java: A service class that communicates with the database with the user data (see UserDataRepository.java and UserData.java classes).
- EmailService.java: A service class used to send emails (when registering a new user, the generated credentials are sent to the new user by email).
Application.java: The main class for the backend server.
For production/development configurations, see application.properties file. Postgres database is used. The database is initialised with the SQL script. In order to run the database, you have to run the build command in the README.md with deps option.
For testing configurations, see application-test.properties file. H2 database is used. The database is initialised with the SQL script.
In order to run the Fabric Gateway, you need to have chaincode and tools repositories cloned in the parent directory of this repository (i.e. you will have chaincode, tools and backend in one directory). To run the infrastructure, run ./infra-start.sh and then ./cc-deploy.sh (also see README.md).
Tests can be found in src/test/java/nl/medtechchain/ directory. TestConfig class configures some mocks used for testing. The actual tests can be found in controllers, models and services packages (directories). For controller tests, MockMvc is used.
When writing tests, please try to write meaningful assertions and make sure that the tests pass before you push.
The workflow file is structured as follows:
- Set up Java (version 21) and Gradle
- Run the build
- Run Checkstyle
- Run tests
- Run JaCoCo coverage
- Create the coverage summary (shown on the workflow page in GitHub)
Create a Pull Request from your branch into main and make sure that the pipeline (i.e. GitHub Actions) passes. After that, wait for approval from the project maintainers. Your time and efforts are highly appreciated! ❤️
Debugging the application (especially the one using Spring Security) might be very hard and intimidating. While we cannot give you a full guide on debugging, we can share a couple of tips, which might help you in locating the errors.
We have disabled the CSRF protection which Spring Security uses by default, which, however, also leads to not very informative 403 errors for many other exceptions. In our case, we are using JWT tokens in the Authorization header, so CSRF tokens are not per se needed.
Furthermore, we allow thrown exceptions to actually reach the destinations with their status codes instead of constant 403 by adding the line .dispatcherTypeMatchers(DispatcherType.ERROR).permitAll() to the SecurityConfig.java.
Nonetheless, if you still happen to get weird (403) exceptions, we can recommend some possible actions:
- Check whether you are requesting the correct endpoint and the correct method (e.g. you might have forgotten to update your HTTP request to use POST and you are still trying to access GET).
- To debug the Authorization errors, set a breakpoint to JwtAuthenticationFilter.java. This is the first filter that you can interact with. From there, you can step into the
doFiltermethod of thefilterChainin order to get to theFilterChainProxyand iterate over the filters. This might be quite painful... - Authentication errors (related to username-password authentications) can be debugged in the
DaoAuthenticationProviderclass. - You can always try disabling some configurations in the SecurityConfig.java to see if requests without authentication/authorization are successful.
If you are also running frontend and think that you are facing some CORS issues, you can change the configuration in application.properties file or in SecurityConfig.java to make the policy extremely mild. If the request succeeds, then this is indeed a CORS issue. Otherwise, there is some other problem...
This can be for multiple reasons. In case the issue is in the JSON to Protobuf deserialization, the first place where you can set a breakpoint would be JsonToProtobufDeserializer.java. There you can see whether the JSON in the request body has been deserialized successfully. If the deserialization has been successful, then most likely the issue is in the chaincode...
As a general tip, it is always nice to see what exactly does an API except. E.g. in the SecurityConfig.java you can see an overview of the endpoints and the permissions they require. Example requests can also be found in the docs folder, e.g. in the Markdown API documentation.
Furthermore, (JavaDoc) comments might provide some help regarding the expectations of the methods. We have tried documenting subtle details as comments in the methods or in the JavaDoc, so you can try also reading those.