Skip to content

Commit

Permalink
Merge pull request #219 from MikeEdgar/216_path_template_param_patterns
Browse files Browse the repository at this point in the history
Apply path template pattern to associated parameter schema
  • Loading branch information
EricWittmann authored Nov 19, 2019
2 parents c4d6206 + bb7186a commit e101aa7
Show file tree
Hide file tree
Showing 3 changed files with 121 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@
import java.util.Set;
import java.util.TreeMap;
import java.util.function.Function;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import javax.ws.rs.core.MediaType;
Expand Down Expand Up @@ -92,6 +94,14 @@ public class ParameterProcessor {

private static final Logger LOG = Logger.getLogger(ParameterProcessor.class);

/**
* Pattern to describe a path template parameter with a regular expression pattern restriction.
*
* See JAX-RS {@link javax.ws.rs.Path Path} JavaDoc for explanation.
*/
static final Pattern TEMPLATE_PARAM_PATTERN = Pattern
.compile("\\{[ \\t]*(\\w[\\w\\.-]*)[ \\t]*:[ \\t]*((?:[^{}]|\\{[^{}]+\\})+)\\}");

private static Comparator<ParameterContextKey> parameterComparator = Comparator.comparing(ParameterContextKey::getLocation,
Comparator.nullsLast(Comparator.reverseOrder()))
.thenComparing(ParameterContextKey::getName,
Expand Down Expand Up @@ -420,7 +430,6 @@ private void reset() {
* @param parameters
* @return
*/
// TODO: Parse path segments to strip out variable names and patterns (apply patterns to path param schema)
String generatePath(AnnotationTarget target, List<Parameter> parameters) {
String path = pathOf(target);

Expand All @@ -443,9 +452,44 @@ String generatePath(AnnotationTarget target, List<Parameter> parameters) {
}
}

/*
* Search for path template variables where a regular expression
* is specified, extract the pattern and apply to the parameter's schema
* if no pattern is otherwise specified and the parameter is a string.
*/
Matcher templateMatcher = TEMPLATE_PARAM_PATTERN.matcher(path);

while (templateMatcher.find()) {
String variableName = templateMatcher.group(1).trim();
String variablePattern = templateMatcher.group(2).trim();

parameters.stream()
.filter(p -> variableName.equals(p.getName()))
.filter(ParameterProcessor::templateParameterPatternEligible)
.forEach(p -> p.getSchema().setPattern(variablePattern));

path = templateMatcher.replaceFirst('{' + variableName + '}');
templateMatcher = TEMPLATE_PARAM_PATTERN.matcher(path);
}

return path;
}

/**
* Determines if the parameter is eligible to have a pattern constraint
* applied to its schema.
*
* @param param the parameter
* @return true if the parameter may have the patter applied, otherwise false
*/
static boolean templateParameterPatternEligible(Parameter param) {
return Parameter.In.PATH.equals(param.getIn())
&& !Style.MATRIX.equals(param.getStyle())
&& param.getSchema() != null
&& SchemaType.STRING.equals(param.getSchema().getType())
&& param.getSchema().getPattern() == null;
}

/**
* Performs the final merging of JAX-RS parameters with MP-OAI parameters to produce the list
* of {@link Parameter}s found while scanning the current level (class or method).
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,12 @@ public void testOptionalParam() throws IOException, JSONException {
OptionalLong.class);
}

@Test
public void testPathParamTemplateRegex() throws IOException, JSONException {
test("params.path-param-templates.json",
PathParamTemplateRegexTestResource.class);
}

/***************** Test models and resources below. ***********************/

public static class Widget {
Expand Down Expand Up @@ -758,4 +764,15 @@ public String helloName9(@QueryParam("name9") @NotNull Optional<String> name) {
return "hello " + name.orElse("SmallRye!");
}
}

@Path("/template")
static class PathParamTemplateRegexTestResource {
@GET
@Path("{id:\\d+}/{name: [A-Z]+ }/{ nickname :[a-zA-Z]+}/{age: [0-9]{1,3}}")
@Produces(MediaType.TEXT_PLAIN)
public String echo(@PathParam("id") Integer id, @PathParam("name") String name, @PathParam("nickname") String nickname,
@PathParam("age") String age) {
return String.valueOf(id) + ' ' + name + ' ' + nickname + ' ' + age;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
{
"openapi": "3.0.1",
"paths": {
"/template/{id}/{name}/{nickname}/{age}": {
"get": {
"parameters": [
{
"name": "age",
"in": "path",
"required": true,
"schema": {
"pattern": "[0-9]{1,3}",
"type": "string"
}
},
{
"name": "id",
"in": "path",
"required": true,
"schema": {
"format": "int32",
"type": "integer"
}
},
{
"name": "name",
"in": "path",
"required": true,
"schema": {
"pattern": "[A-Z]+",
"type": "string"
}
},
{
"name": "nickname",
"in": "path",
"required": true,
"schema": {
"pattern": "[a-zA-Z]+",
"type": "string"
}
}
],
"responses": {
"200": {
"description": "OK",
"content": {
"text/plain": {
"schema": {
"type": "string"
}
}
}
}
}
}
}
}
}

0 comments on commit e101aa7

Please sign in to comment.