Backend
The backend of openVALIDATION-IDE is a REST-API written in Java (version 8) with Spring Boot as the underlaying technology.
API-Documentation
You can find the official OpenAPI documentation through a Swagger-UI at http://openvalidation-ide.azurewebsites.net/swagger-ui.
Simplified data model
Ruleset
Field | Description |
| Unique identifier of a ruleset |
| Name of the ruleset, shown in UI |
| Description of the ruleset, shown in UI |
| Date of ruleset creation |
| Actually a user name as a string, in future this will be a entity |
| Date of last edit |
| Contains all rules of a ruleset |
Schema
Field | Description |
| Unique identifier of a schema |
Attribute
Field | Description |
| Unique identifier of an attribute |
| Name of the attribute, shown in UI |
| Type of attribute. Can be |
| Is a string with a sample value of the attribute (currently not in usage) |
| An attribute can have sub-attributes, if the |
Architecture & architectural decisions
The architecture of the openVALIDATION-IDE is divided through a Web-, Service- and Repository Layer. The basic idea behind this is that only contiguous layers communicate to each other. Furthermore, method calls always happen only from the upper to the lower layer.
The Web Layer only contains the controllers, whereas these controllers should be as "dumb" as possible. They should just forward the incoming API-calls to the services. Between the Web- and the Service Layer only Data Transfer Objects (DTO) are passed. Through the Service-Layer, entities and controllers are encapsulated. The services contain the business logic, what also ensures that the controllers remain clean. Also exception handling happens in the services. Between the Service- and the Repository Layer, only entities are passed. The Repository Layer only contains the repositories.
Package structure
The structure of packages is inspired by Domain-Driven-Design.
The package domain
holds all classes that are part of the domain. Inside of the domain
package, there is a sub-package for each aggregate. The packages for the aggregates, which are ruleset
and the schema
, contain all the classes which belong to this aggregate. We decided, that only entities will get an own package below the aggregate packages. All other classes remain on the root of the aggregate/entity package.
The infrastructure
package contains all classes for configuration of the infrastructure. In the package database are the classes for initializing and resetting the database. The package httpclient
contains a class CorsConfig
for configuring the CORS-Header.
Schema as an own aggregate
We decided to treat the schema as an own aggregate and independently of a ruleset, because it should be possible to share schemas between rulesets.
Currently, a new schema will be created by creating a ruleset. At the moment it is also not possible to manage schemas independent of a ruleset. There is an issue about that on GitHub, this is one of the next items on the agenda.
DTO's
One benefit of a DTO is, that we are free to decide for every special case, which information of our entities we want to reveal through our REST-API. Furthermore we have the freedom of changing our internal data model, without being forced to directly change our endpoints. We decided to implement DTO's inspired by CQRS-principles. We distinguish between three different kinds of DTO's:
DTO-Type | Usage |
General-DTO | DTO's which are given back to the user through the REST-API |
Create-DTO | DTO's which are received through the request body of a HTTP-POST |
Update-DTO | DTO's which are received through the request body of a HTTP-PUT |
The General-DTO gives us the opportunity, to only give that amount of information outwards, that we want to give to the consumer of our REST-API. Whereas the benefit of Create-and Update-DTO's are, to clearly specify which information we want to receive if an entity will be created or updated. This saves us a lot of validation work, because we always receive exactly the information we need in every case.
For mapping between DTO's and entities we use the external library MapStruct. Each entity has its own mapper.
Initialize and reset the database
DatabaseInitializer
The DatabaseIntializer
is responsible for initializing the database with some sample data. The initialization will be executed at the application startup. Initial data will only be created, if the database is empty. Also, there are some out commented rules in the DatabaseInitializer
. We have taken all sample rules from the official playground of openVALIDATION. Especially rules are commented out, where the syntax highlighting is not correctly shown in the openVALIDATION-IDE. The syntax highlighting is shown wrong, because currently (April 18, 2020) the language server does not provide finely granulated information on syntax highlighting, so that we could correctly syntax highlight these rules. Nevertheless, we have already prepared the rules so that they can easily be uncommented as soon as the language server provides the necessary information for syntax highlighting.
Reset-Endpoint
There is a API-endpoint /reset
for resetting the database to an initial state. This API-endpoint was implemented, because currently (July 11, 2020) the openVALIDATION-IDE does not provide a user management and everybody can play around with the rules at the official demo of openVALIDATION-IDE. This endpoint will be called once a day by a cron-job, so that the online-data is always clean. This endpoint can be obfuscated through an environment variable.
Unit- & Integration-Tests
The functionality of the backend can be tested by a set of Unit and integration tests.
Since the application logic is encapsulated in the services, these are validated as part of unit tests. The RulesetServiceTest
covers the logic behind the ruleset endpoint and thus focuses on the interaction with the Ruleset
entity. The SchemaServiceTest
includes the logic of the schema endpoint, which describes the interaction with the Schema
and Attribute
entity. In this case, the repository layer is mocked.
The integration tests include the interaction of the different application layers. The API endpoints, i.e. the controllers in the web layer, are used as the entry point. As a result, the HTTP status codes and content type generated by the endpoint are validated. The entire application process is carried out internally. The controllers in the web layer communicate with the internal services that execute the application logic using the specific DTOs. The services communicate with the repository layer. A temporary in-memory H2 database is used as part of the integration tests. The RulesetIntegrationTest
refers to the ruleset endpoint, while the SchemaIntegrationTest
covers the schema endpoint.
In both test types, the application behavior is tested on the one hand in the context of valid inquiries. However, the behavior of the application in the event of errors is also validated. These error cases are aimed at invalid arguments within the requests from outside that cannot be intercepted by a simple input validation or syntax check.
Environment variables
The table bellow shows the environment variables which can be configured.
Variable | Default Value | Description |
SPRING_PROFILES_ACTIVE | dev | Profile |
OPENVALIDATION_IDE_DB | postgres | Database technology |
OPENVALIDATION_IDE_DB_NAME | Database name | |
OPENVALIDATION_IDE_DB_USER | Database username | |
OPENVALIDATION_IDE_DB_PW | Database password | |
CORS_HEADERS | Allowed CORS Headers | |
RESET_SECRET | Secret for obfuscating |
SPRING_PROFILES_ACTIVE: There are two Spring Profiles to choose between: default
and dev
. The only difference between these profiles is the database technology. If the default
profile is activated, the data is stored in a h2 in-memory database, which in turn means that the data is only persistent until the application is stopped. With the dev
profile active, the data is persistent in a PostgreSQL database. Currently there is no profile for productional usage available, because the openVALIDATION-IDE is still work in progress.
Database configuration: The environment variables OPENVALIDATION_IDE_DB, OPENVALIDATION_IDE_DB_NAME, OPENVALIDATION_IDE_DB_USER and OPENVALIDATION_IDE_DB_PW are used to connect to a database.
CORS_HEADERS: In order to allow Cross-Origin Resource Sharing, this environment variable can be used to configure the allowed URLs. Multiple URLs are specified comma separated one after the other ( for example: https://sample-1.com,https://sample-2.com).
RESET_SECRET: This environment variable can be used to obfuscate the /reset
endpoint. For this purpose, any secret is assigned here, so that this endpoint can only be accessed by additionally specifying this secret in the URL: /reset/[secret]
. If this environment variable is not set, this endpoint can be reached without specifying a secret by using /reset
.
Last updated