Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[REST API] Replaced the old "/test" rest api endpoint with a "dryRun" query param #4722

Merged
merged 1 commit into from
May 31, 2024
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
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@
@ApplicationScoped
@Interceptors({ResponseErrorLivenessCheck.class, ResponseTimeoutReadinessCheck.class})
@Logged
public class GroupsResourceImpl extends AbstractResourceImpl implements GroupsResource {

Check warning on line 121 in app/src/main/java/io/apicurio/registry/rest/v3/GroupsResourceImpl.java

View workflow job for this annotation

GitHub Actions / Qodana Community for JVM

Overly complex class

Overly complex class `GroupsResourceImpl` (cyclomatic complexity = 121)

Check warning on line 121 in app/src/main/java/io/apicurio/registry/rest/v3/GroupsResourceImpl.java

View workflow job for this annotation

GitHub Actions / Qodana Community for JVM

Class with too many methods

`GroupsResourceImpl` has too many methods (method count = 52)

private static final String EMPTY_CONTENT_ERROR_MESSAGE = "Empty content is not allowed.";
@SuppressWarnings("unused")
Expand Down Expand Up @@ -423,29 +423,6 @@
storage.deleteArtifactRule(new GroupId(groupId).getRawGroupIdWithNull(), artifactId, rule);
}

/**
* @see io.apicurio.registry.rest.v3.GroupsResource#testUpdateArtifact(java.lang.String, java.lang.String, java.io.InputStream)
*/
@Override
@Authorized(style = AuthorizedStyle.GroupAndArtifact, level = AuthorizedLevel.Write)
public void testUpdateArtifact(String groupId, String artifactId, InputStream data) {
requireParameter("groupId", groupId);
requireParameter("artifactId", artifactId);
ContentHandle content = ContentHandle.create(data);
if (content.bytes().length == 0) {
throw new BadRequestException(EMPTY_CONTENT_ERROR_MESSAGE);
}

String ct = getContentType();
if (ContentTypeUtil.isApplicationYaml(ct)) {
content = ContentTypeUtil.yamlToJson(content);
}

String artifactType = lookupArtifactType(groupId, artifactId);
rulesService.applyRules(new GroupId(groupId).getRawGroupIdWithNull(), artifactId, artifactType, content,
RuleApplicationType.UPDATE, Collections.emptyList(), Collections.emptyMap()); //TODO:references not supported for testing update
}

/**
* @see io.apicurio.registry.rest.v3.GroupsResource#getArtifactVersionContent(java.lang.String, java.lang.String, java.lang.String, io.apicurio.registry.rest.v3.beans.HandleReferencesType)
*/
Expand Down Expand Up @@ -651,9 +628,9 @@
}

@Override
@Audited(extractParameters = {"0", KEY_GROUP_ID, "1", KEY_IF_EXISTS, "2", KEY_CANONICAL})
@Audited(extractParameters = {"0", KEY_GROUP_ID, "1", KEY_IF_EXISTS, "2", KEY_CANONICAL, "3", "dryRun"})
@Authorized(style = AuthorizedStyle.GroupOnly, level = AuthorizedLevel.Write)
public CreateArtifactResponse createArtifact(String groupId, IfArtifactExists ifExists, Boolean canonical, CreateArtifact data) {
public CreateArtifactResponse createArtifact(String groupId, IfArtifactExists ifExists, Boolean canonical, Boolean dryRun, CreateArtifact data) {

Check warning on line 633 in app/src/main/java/io/apicurio/registry/rest/v3/GroupsResourceImpl.java

View workflow job for this annotation

GitHub Actions / Qodana Community for JVM

Overly complex method

Overly complex method `createArtifact()` (cyclomatic complexity = 15)

Check warning on line 633 in app/src/main/java/io/apicurio/registry/rest/v3/GroupsResourceImpl.java

View workflow job for this annotation

GitHub Actions / Qodana Community for JVM

Overly long method

`createArtifact` is too long (# Non-comment source statements = 43)

Check warning on line 633 in app/src/main/java/io/apicurio/registry/rest/v3/GroupsResourceImpl.java

View workflow job for this annotation

GitHub Actions / Qodana Community for JVM

Method with more than three negations

`createArtifact` contains 7 negations
requireParameter("groupId", groupId);
if (data.getFirstVersion() != null) {
requireParameter("body.firstVersion.content", data.getFirstVersion().getContent());
Expand Down Expand Up @@ -723,7 +700,6 @@
// ArtifactVersionMetaDataDto vmd = storage.createArtifactWithMetadata(new GroupId(groupId).getRawGroupIdWithNull(), artifactId,
// xRegistryVersion, artifactType, content, metaData, referencesAsDtos);


// Create the artifact (with optional first version)
EditableArtifactMetaDataDto artifactMetaData = EditableArtifactMetaDataDto.builder()
.description(data.getDescription())
Expand All @@ -748,6 +724,25 @@
.build();
firstVersionBranches = data.getFirstVersion().getBranches();
}

// Don't actually do anything if "dryRun" is 'true'
if (dryRun != null && dryRun) {

Check warning on line 729 in app/src/main/java/io/apicurio/registry/rest/v3/GroupsResourceImpl.java

View workflow job for this annotation

GitHub Actions / Qodana Community for JVM

Auto-unboxing

Auto-unboxing `dryRun`
return CreateArtifactResponse.builder()
.artifact(ArtifactMetaData.builder()
.groupId(groupId)
.artifactId(artifactId)
.createdOn(new Date())

Check warning on line 734 in app/src/main/java/io/apicurio/registry/rest/v3/GroupsResourceImpl.java

View workflow job for this annotation

GitHub Actions / Qodana Community for JVM

Use of obsolete date-time API

Obsolete date-time type `Date` used
.owner(securityIdentity.getPrincipal().getName())
.modifiedBy(securityIdentity.getPrincipal().getName())
.modifiedOn(new Date())

Check warning on line 737 in app/src/main/java/io/apicurio/registry/rest/v3/GroupsResourceImpl.java

View workflow job for this annotation

GitHub Actions / Qodana Community for JVM

Use of obsolete date-time API

Obsolete date-time type `Date` used
.name(artifactMetaData.getName())
.description(artifactMetaData.getDescription())
.labels(artifactMetaData.getLabels())
.type(artifactType)
.build())
.build();
}

Pair<ArtifactMetaDataDto, ArtifactVersionMetaDataDto> storageResult = storage.createArtifact(
new GroupId(groupId).getRawGroupIdWithNull(),
artifactId, artifactType, artifactMetaData, firstVersion, firstVersionContent,
Expand Down Expand Up @@ -796,18 +791,16 @@
}

@Override
@Audited(extractParameters = {"0", KEY_GROUP_ID, "1", KEY_ARTIFACT_ID})
@Audited(extractParameters = {"0", KEY_GROUP_ID, "1", KEY_ARTIFACT_ID, "2", "dryRun"})
@Authorized(style = AuthorizedStyle.GroupAndArtifact, level = AuthorizedLevel.Write)
public VersionMetaData createArtifactVersion(String groupId, String artifactId, CreateVersion data) {
public VersionMetaData createArtifactVersion(String groupId, String artifactId, Boolean dryRun, CreateVersion data) {
requireParameter("content", data.getContent());
requireParameter("groupId", groupId);
requireParameter("artifactId", artifactId);
requireParameter("body.content", data.getContent());
requireParameter("body.content.content", data.getContent().getContent());
requireParameter("body.content.contentType", data.getContent().getContentType());

// TODO deal with ifExists!

ContentHandle content = ContentHandle.create(data.getContent().getContent());
if (content.bytes().length == 0) {
throw new BadRequestException(EMPTY_CONTENT_ERROR_MESSAGE);
Expand All @@ -833,6 +826,25 @@
.content(content)
.references(referencesAsDtos)
.build();

// Don't actually do anything if "dryRun" is 'true'
if (dryRun != null && dryRun) {

Check warning on line 831 in app/src/main/java/io/apicurio/registry/rest/v3/GroupsResourceImpl.java

View workflow job for this annotation

GitHub Actions / Qodana Community for JVM

Auto-unboxing

Auto-unboxing `dryRun`
return VersionMetaData.builder()
.groupId(groupId)
.artifactId(artifactId)
.version(data.getVersion() == null ? "0" : data.getVersion())
.createdOn(new Date())

Check warning on line 836 in app/src/main/java/io/apicurio/registry/rest/v3/GroupsResourceImpl.java

View workflow job for this annotation

GitHub Actions / Qodana Community for JVM

Use of obsolete date-time API

Obsolete date-time type `Date` used
.owner(securityIdentity.getPrincipal().getName())
.contentId(-1L)
.name(metaDataDto.getName())
.description(metaDataDto.getDescription())
.labels(metaDataDto.getLabels())
.state(VersionState.ENABLED)
.globalId(-1L)
.type(artifactType)
.build();
}

ArtifactVersionMetaDataDto vmd = storage.createArtifactVersion(new GroupId(groupId).getRawGroupIdWithNull(), artifactId, data.getVersion(),
artifactType, contentDto, metaDataDto, data.getBranches());

Expand Down
80 changes: 22 additions & 58 deletions common/src/main/resources/META-INF/openapi.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{

Check warning on line 1 in common/src/main/resources/META-INF/openapi.json

View workflow job for this annotation

GitHub Actions / Validate

oas3-api-servers

Check warning on line 1 in common/src/main/resources/META-INF/openapi.json

View workflow job for this annotation

GitHub Actions / Validate

rhoas-servers-config
"openapi": "3.0.3",
"info": {
"title": "Apicurio Registry API [v3]",
Expand All @@ -14,7 +14,7 @@
"url": "https://www.apache.org/licenses/LICENSE-2.0"
}
},
"paths": {

Check warning on line 17 in common/src/main/resources/META-INF/openapi.json

View workflow job for this annotation

GitHub Actions / Validate

oas3-valid-media-example "value" property type must be string

Check warning on line 17 in common/src/main/resources/META-INF/openapi.json

View workflow job for this annotation

GitHub Actions / Validate

oas3-valid-schema-example "version" property type must be string

Check warning on line 17 in common/src/main/resources/META-INF/openapi.json

View workflow job for this annotation

GitHub Actions / Validate

oas3-valid-schema-example "example" property must be equal to one of the allowed values: "OUTBOUND", "INBOUND". Did you mean "INBOUND"?

Check warning on line 17 in common/src/main/resources/META-INF/openapi.json

View workflow job for this annotation

GitHub Actions / Validate

oas3-valid-schema-example "example" property must have required property "group"

Check warning on line 17 in common/src/main/resources/META-INF/openapi.json

View workflow job for this annotation

GitHub Actions / Validate

oas3-valid-schema-example "content" property must have required property "contentType"

Check warning on line 17 in common/src/main/resources/META-INF/openapi.json

View workflow job for this annotation

GitHub Actions / Validate

oas3-valid-schema-example "example" property must match pattern "^[a-zA-Z0-9._\-+]{1,256}$"

Check warning on line 17 in common/src/main/resources/META-INF/openapi.json

View workflow job for this annotation

GitHub Actions / Validate

oas3-valid-schema-example "example" property must have required property "groupId"

Check warning on line 17 in common/src/main/resources/META-INF/openapi.json

View workflow job for this annotation

GitHub Actions / Validate

oas3-valid-schema-example "createdOn" property must match format "date-time"
"/ids/globalIds/{globalId}": {
"summary": "Access artifact content utilizing an artifact version's globally unique identifier.",
"get": {
Expand Down Expand Up @@ -1410,6 +1410,14 @@
"type": "boolean"
},
"in": "query"
},
{
"name": "dryRun",
"description": "When set to `true`, the operation will not result in any changes. Instead, it\nwill return a result based on whether the operation **would have succeeded**.",
"schema": {
"type": "boolean"
},
"in": "query"
}
],
"responses": {
Expand All @@ -1435,7 +1443,7 @@
},
"operationId": "createArtifact",
"summary": "Create artifact",
"description": "Creates a new artifact. The body of the request should be a `CreateArtifact` \nobject, which includes the metadata of the new artifact and, optionally, the \nmetadata and content of the first version.\n\nIf the artifact type is not provided, the registry attempts to figure out what \nkind of artifact is being added from the\nfollowing supported list:\n\n* Avro (`AVRO`)\n* Protobuf (`PROTOBUF`)\n* JSON Schema (`JSON`)\n* Kafka Connect (`KCONNECT`)\n* OpenAPI (`OPENAPI`)\n* AsyncAPI (`ASYNCAPI`)\n* GraphQL (`GRAPHQL`)\n* Web Services Description Language (`WSDL`)\n* XML Schema (`XSD`)\n\nAn artifact will be created using the unique artifact ID that can optionally be \nprovided in the request body. If not provided in the request, the server will\ngenerate a unique ID for the artifact. It is typically recommended that callers\nprovide the ID, because it is typically a meaningful identifier, and as such\nfor most use cases should be supplied by the caller.\n\nIf an artifact with the provided artifact ID already exists, the default behavior\nis for the server to reject the content with a 409 error. However, the caller can\nsupply the `ifExists` query parameter to alter this default behavior. The `ifExists`\nquery parameter can have one of the following values:\n\n* `FAIL` (*default*) - server rejects the content with a 409 error\n* `UPDATE` - server updates the existing artifact and returns the new metadata\n* `RETURN` - server does not create or add content to the server, but instead \nreturns the metadata for the existing artifact\n* `RETURN_OR_UPDATE` - server returns an existing **version** that matches the \nprovided content if such a version exists, otherwise a new version is created\n\nThis operation may fail for one of the following reasons:\n\n* An invalid `ArtifactType` was indicated (HTTP error `400`)\n* No `ArtifactType` was indicated and the server could not determine one from the content (HTTP error `400`)\n* Provided content (request body) was empty (HTTP error `400`)\n* An artifact with the provided ID already exists (HTTP error `409`)\n* The content violates one of the configured global rules (HTTP error `409`)\n* A server error occurred (HTTP error `500`)\n"
"description": "Creates a new artifact. The body of the request should be a `CreateArtifact` \nobject, which includes the metadata of the new artifact and, optionally, the \nmetadata and content of the first version.\n\nIf the artifact type is not provided, the registry attempts to figure out what \nkind of artifact is being added from the\nfollowing supported list:\n\n* Avro (`AVRO`)\n* Protobuf (`PROTOBUF`)\n* JSON Schema (`JSON`)\n* Kafka Connect (`KCONNECT`)\n* OpenAPI (`OPENAPI`)\n* AsyncAPI (`ASYNCAPI`)\n* GraphQL (`GRAPHQL`)\n* Web Services Description Language (`WSDL`)\n* XML Schema (`XSD`)\n\nAn artifact will be created using the unique artifact ID that can optionally be \nprovided in the request body. If not provided in the request, the server will\ngenerate a unique ID for the artifact. It is typically recommended that callers\nprovide the ID, because it is typically a meaningful identifier, and as such\nfor most use cases should be supplied by the caller.\n\nIf an artifact with the provided artifact ID already exists, the default behavior\nis for the server to reject the content with a 409 error. However, the caller can\nsupply the `ifExists` query parameter to alter this default behavior. The `ifExists`\nquery parameter can have one of the following values:\n\n* `FAIL` (*default*) - server rejects the content with a 409 error\n* `UPDATE` - server updates the existing artifact and returns the new metadata\n* `RETURN` - server does not create or add content to the server, but instead \nreturns the metadata for the existing artifact\n* `RETURN_OR_UPDATE` - server returns an existing **version** that matches the \nprovided content if such a version exists, otherwise a new version is created\n\nThis operation may fail for one of the following reasons:\n\n* An invalid `ArtifactType` was indicated (HTTP error `400`)\n* No `ArtifactType` was indicated and the server could not determine one from the content (HTTP error `400`)\n* Provided content (request body) was empty (HTTP error `400`)\n* An artifact with the provided ID already exists (HTTP error `409`)\n* The content violates one of the configured global rules (HTTP error `409`)\n* A server error occurred (HTTP error `500`)\n\nNote that if the `dryRun` query parameter is set to `true`, then this operation\nwill not actually make any changes. Instead it will succeed or fail based on \nwhether it **would have worked**. Use this option to, for example, check if an\nartifact is valid or if a new version passes configured compatibility checks."
},
"delete": {
"tags": [
Expand Down Expand Up @@ -1465,62 +1473,6 @@
}
]
},
"/groups/{groupId}/artifacts/{artifactId}/test": {
"summary": "Test whether content would pass update rules.",
"put": {
"requestBody": {
"description": "The content of the artifact being tested. This is often, but not always, JSON data\nrepresenting one of the supported artifact types:\n\n* Avro (`AVRO`)\n* Protobuf (`PROTOBUF`)\n* JSON Schema (`JSON`)\n* Kafka Connect (`KCONNECT`)\n* OpenAPI (`OPENAPI`)\n* AsyncAPI (`ASYNCAPI`)\n* GraphQL (`GRAPHQL`)\n* Web Services Description Language (`WSDL`)\n* XML Schema (`XSD`)\n",
"content": {
"*/*": {
"schema": {
"$ref": "#/components/schemas/FileContent"
}
}
},
"required": true
},
"tags": [
"Artifact rules"
],
"responses": {
"204": {
"description": "When successful, returns \"No Content\" to indicate that the rules passed, and the\ncontent was not updated."
},
"404": {
"$ref": "#/components/responses/NotFound"
},
"409": {
"$ref": "#/components/responses/RuleViolationConflict"
},
"500": {
"$ref": "#/components/responses/ServerError"
}
},
"operationId": "testUpdateArtifact",
"summary": "Test update artifact",
"description": "Tests whether an update to the artifact's content *would* succeed for the provided content.\nUltimately, this applies any rules configured for the artifact against the given content\nto determine whether the rules would pass or fail, but without actually updating the artifact\ncontent.\n\nThe body of the request should be the raw content of the artifact. This is typically in \nJSON format for *most* of the supported types, but may be in another format for a few \n(for example, `PROTOBUF`).\n\nThe update could fail for a number of reasons including:\n\n* Provided content (request body) was empty (HTTP error `400`)\n* No artifact with the `artifactId` exists (HTTP error `404`)\n* The new content violates one of the rules configured for the artifact (HTTP error `409`)\n* The provided artifact type is not recognized (HTTP error `404`)\n* A server error occurred (HTTP error `500`)\n\nWhen successful, this operation simply returns a *No Content* response. This response\nindicates that the content is valid against the configured content rules for the \nartifact (or the global rules if no artifact rules are enabled)."
},
"parameters": [
{
"name": "groupId",
"description": "The artifact group ID. Must be a string provided by the client, representing the name of the grouping of artifacts. Must follow the \".{1,512}\" pattern.",
"schema": {
"$ref": "#/components/schemas/GroupId"
},
"in": "path",
"required": true
},
{
"name": "artifactId",
"description": "The artifact ID. Can be a string (client-provided) or UUID (server-generated), representing the unique artifact identifier. Must follow the \".{1,512}\" pattern.",
"schema": {
"$ref": "#/components/schemas/ArtifactId"
},
"in": "path",
"required": true
}
]
},
"/groups": {
"summary": "Collection of the groups in the registry.",
"get": {
Expand Down Expand Up @@ -1956,6 +1908,16 @@
"tags": [
"Versions"
],
"parameters": [
{
"name": "dryRun",
"description": "When set to `true`, the operation will not result in any changes. Instead, it\nwill return a result based on whether the operation **would have succeeded**.",
"schema": {
"type": "boolean"
},
"in": "query"
}
],
"responses": {
"200": {
"content": {
Expand Down Expand Up @@ -4462,7 +4424,9 @@
"type": "string"
}
},
"example": {}
"example": {
"snapshotId": "snp-1137292771"
}
}
},
"responses": {
Expand Down
Loading
Loading