Add validation options to RepositoryValidingInterceptor (#2294)

* Add repository validating interceptor outcome to response

* Add a doc

* Add a test and some docs

* Rework validation
This commit is contained in:
James Agnew 2021-01-17 16:40:32 -05:00 committed by GitHub
parent 391a6d1a3f
commit 66e1a51e01
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 130 additions and 3 deletions

View File

@ -28,6 +28,7 @@ import ca.uhn.fhir.jpa.interceptor.validation.RepositoryValidatingRuleBuilder;
import ca.uhn.fhir.validation.ResultSeverityEnum;
import org.springframework.context.ApplicationContext;
import javax.annotation.Nonnull;
import java.util.List;
@SuppressWarnings("unused")
@ -107,11 +108,44 @@ public class RepositoryValidatingInterceptorExamples {
ruleBuilder
.forResourcesOfType("Patient")
.requireValidationToDeclaredProfiles()
.dontReject()
.neverReject()
.tagOnSeverity(ResultSeverityEnum.ERROR, "http://example.com", "validation-failure");
//END SNIPPET: requireValidationToDeclaredProfilesTagOnFailure
}
public void requireValidationToDeclaredProfilesAdditionalOptions() {
RepositoryValidatingRuleBuilder ruleBuilder = myAppCtx.getBean(RepositoryValidatingRuleBuilder.class);
//START SNIPPET: requireValidationToDeclaredProfilesAdditionalOptions
ruleBuilder
.forResourcesOfType("Patient")
.requireValidationToDeclaredProfiles()
// Configure the validator to never reject extensions
.allowAnyExtensions()
// Configure the validator to not perform terminology validation
.disableTerminologyChecks()
// Configure the validator to raise an error if a resource being
// validated declares a profile, and the StructureDefinition for
// this profile can not be found.
.errorOnUnknownProfiles()
// Configure the validator to suppress the information-level
// message that is added to the validation result if a profile
// StructureDefinition does not declare a binding for a coded
// field.
.suppressNoBindingMessage()
// Configure the validator to suppress the warning-level message
// that is added when validating a code that can't be found in a
// ValueSet that has an extensible binding.
.suppressWarningForExtensibleValueSetValidation();
//END SNIPPET: requireValidationToDeclaredProfilesAdditionalOptions
}
public void disallowProfiles() {
RepositoryValidatingRuleBuilder ruleBuilder = myAppCtx.getBean(RepositoryValidatingRuleBuilder.class);

View File

@ -95,6 +95,13 @@ By default, resource updates/changes resulting in failing validation will cause
{{snippet:classpath:/ca/uhn/hapi/fhir/docs/RepositoryValidatingInterceptorExamples.java|requireValidationToDeclaredProfilesTagOnFailure}}
```
## Configuring the Validator
The following snippet shows a number of additional optional settings that can be chained onto the validation rule.
```java
{{snippet:classpath:/ca/uhn/hapi/fhir/docs/RepositoryValidatingInterceptorExamples.java|requireValidationToDeclaredProfilesAdditionalOptions}}
```
# Rules: Disallow Specific Profiles

View File

@ -226,7 +226,7 @@ public final class RepositoryValidatingRuleBuilder implements IRuleRoot {
* Specifies that the resource should not be rejected from storage even if it does not pass validation.
*/
@Nonnull
public FinalizedRequireValidationRule dontReject() {
public FinalizedRequireValidationRule neverReject() {
myRule.dontReject();
return this;
}
@ -292,6 +292,57 @@ public final class RepositoryValidatingRuleBuilder implements IRuleRoot {
return this;
}
/**
* Configure the validator to never reject extensions
*/
@Nonnull
public FinalizedRequireValidationRule allowAnyExtensions() {
myRule.getValidator().setAnyExtensionsAllowed(true);
return this;
}
/**
* Configure the validator to not perform terminology validation
*/
@Nonnull
public FinalizedRequireValidationRule disableTerminologyChecks() {
myRule.getValidator().setNoTerminologyChecks(true);
return this;
}
/**
* Configure the validator to raise an error if a resource being validated
* declares a profile, and the StructureDefinition for this profile
* can not be found.
*/
@Nonnull
public FinalizedRequireValidationRule errorOnUnknownProfiles() {
myRule.getValidator().setErrorForUnknownProfiles(true);
return this;
}
/**
* Configure the validator to suppress the information-level message that
* is added to the validation result if a profile StructureDefinition does
* not declare a binding for a coded field.
*/
@Nonnull
public FinalizedRequireValidationRule suppressNoBindingMessage() {
myRule.getValidator().setNoBindingMsgSuppressed(true);
return this;
}
/**
* Configure the validator to suppress the warning-level message that
* is added when validating a code that can't be found in an ValueSet that
* has an extensible binding.
*/
@Nonnull
public FinalizedRequireValidationRule suppressWarningForExtensibleValueSetValidation() {
myRule.getValidator().setNoExtensibleWarnings(true);
return this;
}
}
}

View File

@ -117,6 +117,14 @@ class RequireValidationRule extends BaseTypedRule {
.toString();
}
public FhirInstanceValidator getValidator() {
return myValidator;
}
public void setAllowAnyExtensions() {
myValidator.setAnyExtensionsAllowed(true);
}
private static class TagOnSeverity {
private final int mySeverity;
private final String myTagSystem;

View File

@ -264,13 +264,40 @@ public class RepositoryValidatingInterceptorR4Test extends BaseJpaR4Test {
}
}
@Test
public void testRequireValidation_AdditionalOptions() {
List<IRepositoryValidatingRule> rules = newRuleBuilder()
.forResourcesOfType("Observation")
.requireValidationToDeclaredProfiles()
.withBestPracticeWarningLevel("IGNORE")
.allowAnyExtensions()
.disableTerminologyChecks()
.errorOnUnknownProfiles()
.suppressNoBindingMessage()
.suppressWarningForExtensibleValueSetValidation()
.build();
myValInterceptor.setRules(rules);
Observation obs = new Observation();
obs.getCode().addCoding().setSystem("http://foo").setCode("123").setDisplay("help im a bug");
obs.setStatus(Observation.ObservationStatus.AMENDED);
try {
IIdType id = myObservationDao.create(obs).getId();
assertEquals("1", id.getVersionIdPart());
} catch (PreconditionFailedException e) {
// should not happen
fail(myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(e.getOperationOutcome()));
}
}
@Test
public void testRequireValidation_FailNoRejectAndTag() {
List<IRepositoryValidatingRule> rules = newRuleBuilder()
.forResourcesOfType("Observation")
.requireValidationToDeclaredProfiles()
.withBestPracticeWarningLevel("IGNORE")
.dontReject()
.neverReject()
.tagOnSeverity(ResultSeverityEnum.ERROR, "http://foo", "validation-error")
.build();
myValInterceptor.setRules(rules);