Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 23 additions & 22 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,28 +91,29 @@ Example using the default output path for the jar (replace `<version>` with the
#### Options File
The options file is described in json (example in `specs/options.json`), and has the following possible values:

|Option|Type|Possible Values|Default Value|Description|
|---|---|---|---|---|
|validateInfoLicense|boolean|`true`, `false`|`true`|Ensures that there is a license section in the info section|
|validateInfoDescription|boolean|`true`, `false`|`true`|Ensures that there is a description attribute in the info section|
|validateInfoContact|boolean|`true`, `false`|`true`|Ensures that there is a contact section in the info section|
|validateOperationOperationId|boolean|`true`, `false`|`true`|Ensures that there is an operation id for each operation|
|validateOperationDescription|boolean|`true`, `false`|`true`|Ensures that there is a description for each operation|
|validateOperationTag|boolean|`true`, `false`|`true`|Ensures that there is a tag for each operation|
|validateOperationSummary|boolean|`true`, `false`|`true`|Ensures that there is a summary for each operation|
|validateModelPropertiesExample|boolean|`true`, `false`|`true`|Ensures that the properties of the Schemas have an example value defined|
|validateModelPropertiesDescription|boolean|`true`, `false`|`true`|Ensures that the properties of the Schemas have a description value defined|
|validateModelRequiredProperties|boolean|`true`, `false`|`true`|Ensures that all required properties of the Schemas are listed among their properties|
|validateModelNoLocalDef|boolean|`true`, `false`|`true`|Not implemented yet|
|validateNaming|boolean|`true`, `false`|`true`|Ensures the names follow a given naming convention|
|ignoreHeaderXNaming|boolean|`true`, `false`|`true`|Exclude from validation header parameters starting with `x-`|
|pathNamingConvention|string|`CamelCase`, `PascalCase`, `HyphenUpperCase`, `HyphenCase`, `UnderscoreCase`, `UnderscoreUpperCase`, `AnyCase` |`HyphenCase`|Naming convention for paths|
|parameterNamingConvention|string|`CamelCase`, `PascalCase`, `HyphenUpperCase`, `HyphenCase`, `UnderscoreCase`, `UnderscoreUpperCase`, `AnyCase`|`CamelCase`|Global naming convention for all parameter types (path, query and cookie) [(note)](#parameter-naming-convention-hierarchy)|
|pathParamNamingConvention|string|`CamelCase`, `PascalCase`, `HyphenUpperCase`, `HyphenCase`, `UnderscoreCase`, `UnderscoreUpperCase`, `AnyCase`|(same as `parameterNamingConvention`)|Specific naming convention for path parameters [(note)](#parameter-naming-convention-hierarchy)|
|queryParamNamingConvention|string|`CamelCase`, `PascalCase`, `HyphenUpperCase`, `HyphenCase`, `UnderscoreCase`, `UnderscoreUpperCase`, `AnyCase`|(same as `parameterNamingConvention`)|Specific naming convention for query parameters [(note)](#parameter-naming-convention-hierarchy)|
|cookieParamNamingConvention|string|`CamelCase`, `PascalCase`, `HyphenUpperCase`, `HyphenCase`, `UnderscoreCase`, `UnderscoreUpperCase`, `AnyCase`|(same as `parameterNamingConvention`)|Specific naming convention for cookie parameters [(note)](#parameter-naming-convention-hierarchy)|
|headerNamingConvention|string|`CamelCase`, `PascalCase`, `HyphenUpperCase`, `HyphenCase`, `UnderscoreCase`, `UnderscoreUpperCase`, `AnyCase`|`UnderscoreUpperCase`|Naming convention for headers|
|propertyNamingConvention|string|`CamelCase`, `PascalCase`, `HyphenUpperCase`, `HyphenCase`, `UnderscoreCase`, `UnderscoreUpperCase`, `AnyCase`|`CamelCase`|Naming convention for properties|
|Option|Type| Possible Values |Default Value|Description|
|---|---|----------------------------------------------------------------------------------------------------------------|---|---|
|validateInfoLicense|boolean| `true`, `false` |`true`|Ensures that there is a license section in the info section|
|validateInfoDescription|boolean| `true`, `false` |`true`|Ensures that there is a description attribute in the info section|
|validateInfoContact|boolean| `true`, `false` |`true`|Ensures that there is a contact section in the info section|
|validateOperationOperationId|boolean| `true`, `false` |`true`|Ensures that there is an operation id for each operation|
|validateOperationDescription|boolean| `true`, `false` |`true`|Ensures that there is a description for each operation|
|validateOperationTag|boolean| `true`, `false` |`true`|Ensures that there is a tag for each operation|
|validateOperationSummary|boolean| `true`, `false` |`true`|Ensures that there is a summary for each operation|
|validateModelPropertiesExample|boolean| `true`, `false` |`true`|Ensures that the properties of the Schemas have an example value defined|
|validateModelPropertiesDescription|boolean| `true`, `false` |`true`|Ensures that the properties of the Schemas have a description value defined|
|validateModelRequiredProperties|boolean| `true`, `false` |`true`|Ensures that all required properties of the Schemas are listed among their properties|
|validateModelNoLocalDef|boolean| `true`, `false` |`true`|Not implemented yet|
|validateNaming|boolean| `true`, `false` |`true`|Ensures the names follow a given naming convention|
|ignoreHeaderXNaming|boolean| `true`, `false` |`true`|Exclude from validation header parameters starting with `x-`|
|pathNamingConvention|string| `CamelCase`, `PascalCase`, `HyphenUpperCase`, `HyphenCase`, `UnderscoreCase`, `UnderscoreUpperCase`, `AnyCase` |`HyphenCase`|Naming convention for paths|
|parameterNamingConvention|string| `CamelCase`, `PascalCase`, `HyphenUpperCase`, `HyphenCase`, `UnderscoreCase`, `UnderscoreUpperCase`, `AnyCase` |`CamelCase`|Global naming convention for all parameter types (path, query and cookie) [(note)](#parameter-naming-convention-hierarchy)|
|pathParamNamingConvention|string| `CamelCase`, `PascalCase`, `HyphenUpperCase`, `HyphenCase`, `UnderscoreCase`, `UnderscoreUpperCase`, `AnyCase` |(same as `parameterNamingConvention`)|Specific naming convention for path parameters [(note)](#parameter-naming-convention-hierarchy)|
|queryParamNamingConvention|string| `CamelCase`, `PascalCase`, `HyphenUpperCase`, `HyphenCase`, `UnderscoreCase`, `UnderscoreUpperCase`, `AnyCase` |(same as `parameterNamingConvention`)|Specific naming convention for query parameters [(note)](#parameter-naming-convention-hierarchy)|
|cookieParamNamingConvention|string| `CamelCase`, `PascalCase`, `HyphenUpperCase`, `HyphenCase`, `UnderscoreCase`, `UnderscoreUpperCase`, `AnyCase` |(same as `parameterNamingConvention`)|Specific naming convention for cookie parameters [(note)](#parameter-naming-convention-hierarchy)|
|headerNamingConvention|string| `CamelCase`, `PascalCase`, `HyphenUpperCase`, `HyphenCase`, `UnderscoreCase`, `UnderscoreUpperCase`, `AnyCase` |`UnderscoreUpperCase`|Naming convention for headers|
|propertyNamingConvention|string| `CamelCase`, `PascalCase`, `HyphenUpperCase`, `HyphenCase`, `UnderscoreCase`, `UnderscoreUpperCase`, `AnyCase` |`CamelCase`|Naming convention for properties|
|allowedModelProperties|array| `["_links", "_embedded"]`|`[]`|An array of property names that are authorised even if they do not match to the "propertyNamingConvention"|

#### Parameter Naming Convention hierarchy

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -193,8 +193,10 @@ private void validateNaming() {
if (model.getProperties() != null) {
for (Map.Entry<String, Schema> entry :
model.getProperties().entrySet()) {
String name = entry.getKey();
boolean isValid = namingValidator.isNamingValid(
entry.getKey(), parameters.getPropertyNamingConvention());
name, parameters.getPropertyNamingConvention())
|| parameters.getAllowedModelProperties().contains(name);
if (!isValid) {
errorAggregator.logModelBadNaming(
entry.getKey(),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
package org.openapitools.openapistylevalidator;

import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

public class ValidatorParameters {
public static final String VALIDATE_INFO_LICENSE = "validateInfoLicense";
public static final String VALIDATE_INFO_DESCRIPTION = "validateInfoDescription";
Expand Down Expand Up @@ -76,6 +81,8 @@ public String getDesignation() {
private boolean pathParamNamingConventionWasExplicitlySet = false;
private boolean cookieParamNamingConventionWasExplicitlySet = false;

private Set<String> allowedModelProperties = new HashSet<>();

public ValidatorParameters() {
// For Gson
}
Expand Down Expand Up @@ -277,6 +284,15 @@ public ValidatorParameters setIgnoreHeaderXNaming(boolean ignoreHeaderXNaming) {
return this;
}

public ValidatorParameters setAllowedModelProperties(List<String> allowedModelProperties) {
this.allowedModelProperties = new HashSet<>(allowedModelProperties);
return this;
}

public Set<String> getAllowedModelProperties() {
return Collections.unmodifiableSet(this.allowedModelProperties);
}

@Override
public String toString() {
return String.format(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,8 @@

import static org.junit.jupiter.api.Assertions.assertEquals;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.*;
import java.util.stream.Collectors;
import org.eclipse.microprofile.openapi.OASFactory;
import org.eclipse.microprofile.openapi.models.OpenAPI;
import org.eclipse.microprofile.openapi.models.media.Schema;
Expand Down Expand Up @@ -408,6 +406,40 @@ void shouldReportCookieParamNamingConventionError() {
}
/* end - tests for issue #367 */

// https://github.com/OpenAPITools/openapi-style-validator/issues/152
@Test
void shouldAcceptSpecificModelProperties() {
OpenAPI openAPI = createValidOpenAPI();
openAPI.components(openAPI.getComponents()
.addSchema(
"Items",
OASFactory.createSchema().type(SchemaType.OBJECT).properties(new HashMap<String, Schema>() {
{
put(
"_links",
OASFactory.createSchema()
// _links should be an object. However, this is enough
// to represent the case
.type(SchemaType.STRING));
}
})));

OpenApiSpecStyleValidator validator = new OpenApiSpecStyleValidator(openAPI);
ValidatorParameters parameters = new ValidatorParameters()
// Keep the details away
.setValidateModelPropertiesDescription(false)
.setValidateModelPropertiesExample(false)
// Reproduce the original error
.setPropertyNamingConvention(NamingConvention.CamelCase)
.setValidateNaming(true)
// Add the fix
.setAllowedModelProperties(Collections.singletonList("_links"));
List<StyleError> errors = validator.validate(parameters);
Assertions.assertTrue(
errors.isEmpty(),
() -> errors.stream().map(StyleError::toString).collect(Collectors.joining()));
}

private static OpenAPI createValidOpenAPI() {
return OASFactory.createOpenAPI()
.openapi("3.0.1")
Expand Down