Request Parameters validations in vertx 4.0.3 - vert.x

I was using vertx-Web-api-contracts in vertx 3.0 to validate my query parameters and form parameters using
HTTPRequestValidationHandler and ParameterTypeValidator
code sample :
private final ParameterTypeValidator fileIdValueValidator = new IdTypeValidator().create();
private final ParameterTypeValidator tokenTypeValidator = new TokenTypeValidator().create();
private HTTPRequestValidationHandler getDeleteRequestValidations() {
final HTTPRequestValidationHandler validator = HTTPRequestValidationHandler.create()
.addQueryParamWithCustomTypeValidator(PARAM__ID, IdValueValidator, true, false)
.addHeaderParamWithCustomTypeValidator(HEADER_TOKEN, tokenTypeValidator, true, false);
return validator;
}
Here I am using ParameterTypeValidator to provide custom logic to validate my parameters value. I am using customTypeValidator, because I need custom value validation for parameter value
for ex. I need to validate my ID Parameter should contain four parts separated by _ ( part1_part2_part3_part4 )
Now while I am trying to migrate to vertx 4.0 and vertx-Web-api-contracts is deprecated, I am forced to use vertx-web-validation, but web-validation lacks custompropertyvalidation like api-contract-validations.
How I am trying to do,
private ValidationHandler getDeleteRequestValidations(final SchemaParser parser) {
ValidationHandler validationHandler=ValidationHandler.builder(parser)
.queryParameter(Parameters.param(PARAM__ID, stringSchema()))
.headerParameter(Parameters.param(HEADER_TOKEN,stringSchema()))
.build();
return validationHandler;
}
But I want to know how to pass/build a custom schema instead of stringSchema() or intSchema() to validate with custom logic. Earlier I was creating Custom classes and implements ParameterTypeValidator to provide custom validation logic(like IdTypeValidator()).
Is there any way to achieve same with web-validation.

Not really familiar with the new validation mechanism, but will try to help you using some facts.
The new validation uses Json Schema, so you should first go for understanding that one: https://vertx.io/docs/vertx-json-schema/java/
Then, examining the Parameters.param() signature, the second parameter is just an instance of the io.vertx.json.schema.common.dsl.SchemaBuilder which is then described how to be built in this part of the docs:
https://vertx.io/docs/vertx-json-schema/java/#_building_your_schemas_from_code
I hope this will give you a direction on how to solve your problem.

Related

Spring #QuerydslPredicate and QuerydslBinderCustomizer: is it possible to infuse default criteria into predicate generated from request params?

I am using Spring Data JPA and QueryDsl (v.4.2.2), Java 8. I can explicitly construct search predicates and pass them to the repository methods. However, I like the idea of using the #QuerydslPredicate annotation on a web/REST controller's method argument when the queried entities have more than a few properties, and I want the flexibility of filtering the search by any of them. So, something like this, generally, works very well:
#GetMapping("/accounts/summaries")
public PageDto<AccountSummaryDto> getAccountSummaries(#QuerydslPredicate(root = AccountSummary.class) Predicate accountSearchPredicate,
#RequestParam(name = "pageIndex", defaultValue = "0") int pageIndex,
#RequestParam(name = "pageSize", defaultValue = "25") int pageSize,
#RequestParam(name = "sortBy", defaultValue = "id") String sortBy,
#RequestParam(name = "sortOrder", defaultValue = "desc") String sortOrder) {
// delegating to web-agnostic service that:
// - creates Pageable pageRequest,
// - calls accountSummaryRepository.findAll(predicate, pageRequest),
// - constructs custom PageDto wrapper, etc.
return accountService.retrieveAccountSummaries(accountSearchPredicate, pageIndex, pageSize, sortBy, sortOrder);
}
My Spring Data JPA repository interface looks similar to this:
public interface AccountSummarySearchRepository
extends JpaRepository<AccountSummary, Integer>, QuerydslPredicateExecutor<AccountSummary>, QuerydslBinderCustomizer<QAccountSummary > {
#Override
default void customize(QuerydslBindings bindings, QAccountSummary acctSummary) {
bindings.bind(acctSummary.customer.firstName).first((path, value) -> path.isNull().or(path.startsWithIgnoreCase(value))) ;
bindings.bind(acctSummary.customer.lastName).first((path, value) -> path.isNull().or(path.startsWithIgnoreCase(value))) ;
// etc.
// default binding for String properties to be case insensitive "contains" match
bindings.bind(String.class).first(
(StringPath path, String value) -> path.isNull().or(path.containsIgnoreCase(value)));
}
My question:
The bindings in the customize method are set using the entity field
paths and the values of the request parameters that match those
paths. If the parameter is not specified, is there a way to bind the
path to some constant value or a value obtained dynamically?
For example, I want to always ONLY retrieve the entities where property deleted is set to false - without forcing the client to pass that as a query parameter? Similarly, I may want to set other default lookup values dynamically for each query. For example, I may want to "retrieve only those accounts where assignedTo == [current user ID available on a ThreadLocal]...
The following will not work
bindings.bind(acctSummary.deleted).first((path, value) -> path.eq(false));
because it, obviously, expects the first occurrence of the path/value pair for deleted=... in the Predicate (mapped from the incoming request params via the #QuerydslPredicate annotation. I don't want to pass that as a parameter because the requester does not even need to know about the existence of such field.
Is there a simple way to infuse the Predicate instance that is auto-populated via the #QuerydslPredicate annotation with any additional implicit/default criteria that are not explicitly passed in the web request? Could this be done in the customize method? I suppose, one (very ugly) way would be to intercept the HTTP request in a filter - before it is processed by the Spring-QueryDsl framework - and replace it with a new request with added parameters? That would be a horrible solution, and I feel there has to be a better way to do it via some hook/capability provided by the framework itself.
Unfortunately, there seem to be no comprehensive documentation for Spring QueryDsl support - other than some very simplistic examples.
Thanks for your help!
Answering my own question... I was hoping to find a hook in the framework where I could add the code to enhance the auto-generated predicate with criteria common for all my queries - before it arrives in the controller method, but wasn’t able to figure that out. Overriding QuerydslPredicateArgumentResolver doesn't seem a good or necessary option. And, quite frankly, I've come to the conclusion that this wasn't such a great idea to begin with. It seems that any modifications to the search criteria should be done in a more obvious way - in the business tier. So I decided to simply update the predicate in the service method:
public PageDto<AccountSummaryDto> retrieveByPredicate(Predicate predicate, int pageIndex, int pageSize, String sortBy, String sortOrder) {
Pageable pageRequest = PageRequest.of(pageIndex, pageSize, Sort.Direction.fromString(sortOrder), sortBy);
QAccountSummary accountSummary = QAccountSummary.accountSummary; //QueryDsl auto-generated query type for AccountSummary (path root)
// construct new enhanced search predicate w/added criteria common for all queries
// using original predicate generated by framework from request params as base
BooleanBuilder updatedPredicate = new BooleanBuilder(predicate)
.and(accountSummary.somethingNested.id.eq(SomeThreadContext.getSomethingId()))
.and(accountSummary.deleted.eq(false))
.and(accountSummary.someProperty.eq("xyz"));
Page<accountSummary> page = summarySearchRepository.findAll(updatedPredicate, pageRequest);
return toAccountSummaryPageDto(page); // custom method that converts results to page DTO w/entity dots and page stats
}
The construction of the updated predicate may be extracted into a separate private method on the service should it be desirable to use it in multiple search methods and/or if more logic is required to dynamically generate additional search criteria.

Is it possible for a restful webservice to have a parameter in the url?

I was instructed to create webservices ( with Spring-Boot ). My colleague gave me the url of the webservice and it looks like this : http://172.20.40.4:8080/Oxalys_WS/stock/ITM=1559
In general we create a RestController with the url :
#RestController
#RequestMapping("stock")
public class StockController {
#Autowired
private StockService stockService;
#GetMapping(value = "/{code}", produces = "application/json")
public JsonModel getByCode(#PathVariable String code) {
JsonModel jsonModel = new JsonModel();
final Map<String, Object> data = new HashMap<>();
List<Stock> stock = stockService.getByCode(code);
data.put("stock", stock);
data.put("stockTotal", stockService.getTotal(code));
jsonModel.setDatas(data);
return jsonModel;
}
}
So is it normal to create a Restful Spring-Boot webservice with a parameter in the url ?
Spring provides parameter in two standard way.
Query Param : http://172.20.40.4:8080/Oxalys_WS/stock?ITM=1559
Path Variable : http://172.20.40.4:8080/Oxalys_WS/stock/1559
Query Param :- It is a typical old way to pass some value as QueryParam with using of some variable starts with ?(Question Mark) and value is assigned using =(equals).
PathVariable :- this is a newer pattern introduce for REST-api Services. URL must be structured such in a way that this should not look too messy if multiple parameters need to pass within a URL.
For more info Navigate this link
Yes, you can have the one in your URL
When you are required to have the path variable, you can give in the Request URL

Parse HL7 v2.3 REF message with local customizations in HAPI

I am trying parse a HL7 REF I12 message with local customization(NZ).
When I tried using the GenericParser, I keep getting Validation exceptions.
For example for the segment below, I keep get the output
ca.uhn.hl7v2.validation.ValidationException: Validation failed:
Primitive value '(08)569-7555' requires to be empty or a US phone
number
PRD|PP|See T Tan^""^""^^""|""^^^^""^New Zealand||(08)569-7555||14134^NZMC
My question is:
Is there a way to avoid the validation by using the conformance class
generator
Is it possible to create own validation classes using
CustomModelClasses?
In either case, is there any example code for that or tutorial example documentation?
If disabling validation altogether is an option for your application, then you can set the validation context to use NoValidation.
See this thread in the hapi developers mailing list: http://sourceforge.net/p/hl7api/mailman/message/31244500/
Here is an example of how to disable validation:
HapiContext context = new DefaultHapiContext();
context.setValidationContext(new NoValidation());
GenericParser parser = context.getGenericParser();
String message = ...
try {
parser.parse(message);
} catch (Exception e) {
e.printStackTrace();
}
If you still require validation, but just want to change the validator for specific rules, then you'll have to create your own implementation of ValidationContext. This would be done by sub classing ca.uhn.hl7v2.validation.builder.support.NoValidationBuilder and overriding the configure method and use this to instantiate an instance of ValidationContextImpl.
For an example of how to implement the configure method in your subclass of NoValidationBuilder, see the source code for ca.uhn.hl7v2.validation.builder.support.DefaultValidationBuilder. This is the default validation context that is generating the error message you're seeing. To make it easier for you, I'm including the class listing here:
public class DefaultValidationBuilder extends DefaultValidationWithoutTNBuilder {
#Override
protected void configure() {
super.configure();
forAllVersions()
.primitive("TN")
.refersToSection("Version 2.4 Section 2.9.45")
.is(emptyOr(usPhoneNumber()));
}
}
Notice this is the implementation of the usPhoneNumber method defined in BuilderSupport:
public Predicate usPhoneNumber() {
return matches("(\\d{1,2} )?(\\(\\d{3}\\))?\\d{3}-\\d{4}(X\\d{1,5})?(B\\d{1,5})?(C.*)?",
"a US phone number");
}

Use GuidRepresentation.Standard with MongoDB

I am implementing a custom IBsonSerializer with the official MongoDB driver (C#). I am in the situation where I must serialize and deserialize a Guid.
If I implement the Serialize method as follow, it works:
public void Serialize(BsonWriter bsonWriter, Type nominalType, object value, IBsonSerializationOptions options)
{
BsonBinaryData data = new BsonBinaryData(value, GuidRepresentation.CSharpLegacy);
bsonWriter.WriteBinaryData(data);
}
However I don't want the Guid representation to be CSharpLegacy, I want to use the standard representation. But if I change the Guid representation in that code, I get the following error:
MongoDB.Bson.BsonSerializationException: The GuidRepresentation for the writer is CSharpLegacy, which requires the subType argument to be UuidLegacy, not UuidStandard.
How do I serialize a Guid value using the standard representation?
Old question but in case someone finds it on google like I did...
Do this once:
BsonDefaults.GuidRepresentation = GuidRepresentation.Standard;
For example, in a Web Application/Web API, your Global.asax.cs file is best place to add it once
public class WebApiApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
BsonDefaults.GuidRepresentation = GuidRepresentation.Standard;
//Other code...below
}
}
If you don't want to modify the global setting BsonDefaults.GuidRepresentation (and you shouldn't, because modifying globals is a bad pattern), you can specify the setting when you create your collection:
IMongoDatabase db = ???;
string collectionName = ???;
var collectionSettings = new MongoCollectionSettings {
GuidRepresentation = GuidRepresentation.Standard
};
var collection = db.GetCollection<BsonDocument>(collectionName, collectionSettings);
Then any GUIDs written to the collection will be in the standard format.
Note that when you read records from the database, you will get a System.FormatException if the GUID format in the database is different from the format in your collection settings.
It looks like what's happening is when you are not explicitly passing the GuidRepresentation to BsonBinaryData constructor, it defaults to passing GuidRepresentation.Unspecified and that ultimately maps to GuidRepresentation.Legacy (see this line in the source)
So you need to explicitly pass the guidRepresentation as a third argument to BsonBinaryData set to GuidRepresentation.Standard.
edit: As was later pointed out, you can set BsonDefaults.GuidRepresentation = GuidRepresentation.Standard if that's what you always want to use.

Eclipselink JPA MappingSelectionCriteria customization

According to EclipseLink/Examples/JPA/MappingSelectionCriteria I can make some filtering on OneToOne or OneToMany relationships. To do that I have to implement DescriptorCustomizer.
My question is: Can I do some conditional filtering with this technique and how? I mean, in the example of mentioned link we can write something like this
public class ConfigureBsFilter implements DescriptorCustomizer {
public void customize(ClassDescriptor descriptor) throws Exception {
OneToManyMapping mapping = (OneToManyMapping) descriptor
.getMappingForAttributeName("bs");
ExpressionBuilder eb = new ExpressionBuilder(mapping
.getReferenceClass());
Expression fkExp = eb.getField("A_ID").equal(eb.getParameter("A_ID"));
Expression activeExp = eb.get("active").equal(true);
mapping.setSelectionCriteria(fkExp.and(activeExp));
}
}
But what if in the expression
Expression activeExp = eb.get("active").equal(true);
the "active" is not always true but have to be set at runtime by some parameter. Can I do that and how?
Looking at wiki.eclipse.org/Using_Advanced_Query_API_(ELUG) you could use a query redirector on the ForeignReferenceMapping#getSelectionQuery() so that your query redirector can dynamically clone the query and add filters as required. Passing parameters to the redirector will need to be creative though, such as storing them on the thread context or in the session's properties map.