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

relates to C2-2197: setup the command serialization with tests #7

Merged
merged 8 commits into from
Dec 1, 2022
Merged
Show file tree
Hide file tree
Changes from 2 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
54 changes: 54 additions & 0 deletions src/main/java/io/stargate/sgv3/docsapi/StargateDocsApi.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,13 @@
import javax.ws.rs.core.Application;
import org.eclipse.microprofile.openapi.annotations.Components;
import org.eclipse.microprofile.openapi.annotations.OpenAPIDefinition;
import org.eclipse.microprofile.openapi.annotations.enums.ParameterIn;
import org.eclipse.microprofile.openapi.annotations.enums.SecuritySchemeIn;
import org.eclipse.microprofile.openapi.annotations.enums.SecuritySchemeType;
import org.eclipse.microprofile.openapi.annotations.info.Info;
import org.eclipse.microprofile.openapi.annotations.media.ExampleObject;
import org.eclipse.microprofile.openapi.annotations.media.Schema;
import org.eclipse.microprofile.openapi.annotations.parameters.Parameter;
import org.eclipse.microprofile.openapi.annotations.security.SecurityScheme;

@OpenAPIDefinition(
Expand All @@ -25,6 +29,56 @@
type = SecuritySchemeType.APIKEY,
in = SecuritySchemeIn.HEADER,
apiKeyName = HttpConstants.AUTHENTICATION_TOKEN_HEADER_NAME)
},

// reusable parameters
parameters = {
@Parameter(
in = ParameterIn.PATH,
name = "database",
required = true,
schema = @Schema(implementation = String.class, pattern = "\\w+"),
description = "The database where the collection is located.",
example = "cycling"),
@Parameter(
in = ParameterIn.PATH,
name = "collection",
required = true,
schema = @Schema(implementation = String.class, pattern = "\\w+"),
description = "The name of the collection.",
example = "events")
},

// reusable examples
examples = {
@ExampleObject(
name = "findOne",
summary = "`findOne` command",
value =
"""
{
"findOne": {
"sort": ["-race.competitors"]
}
}
"""),
@ExampleObject(
name = "insertOne",
summary = "`insertOne` command",
value =
"""
{
"insertOne": {
"document": {
"location": "London",
"race": {
"competitors": 100,
"start_date": "2022-08-15"
}
}
}
}
"""),
}))
public class StargateDocsApi extends Application {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is related to the bigger naming question but... Isn't it bit confusing to have 2 completely different "Docs API" instances? If we do decide to go with "DocsV3" then at least add V3 in the name here, to tell from our existing "DocsV2".

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Package is different, would this be enough? I am happy to hear the suggestions?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah it's different for many uses. Not a big deal but I'd go with just StargateDocsV3Api. Bit of redundancy in just one place.
I do not propose to use it everywhere, just here.


Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package io.stargate.sgv3.docsapi.api.configuration;

import com.fasterxml.jackson.databind.MapperFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.json.JsonMapper;
import io.quarkus.jackson.ObjectMapperCustomizer;
import javax.enterprise.inject.Instance;
import javax.enterprise.inject.Produces;
import javax.inject.Singleton;

/** Configures the {@link ObjectMapper} instance that going to be injectable and used in the app. */
public class ObjectMapperConfiguration {

/** Replaces the CDI producer for ObjectMapper built into Quarkus. */
@Singleton
@Produces
ObjectMapper objectMapper(Instance<ObjectMapperCustomizer> customizers) {
ObjectMapper mapper = createMapper();

// apply all ObjectMapperCustomizer beans (incl. Quarkus)
for (ObjectMapperCustomizer customizer : customizers) {
customizer.customize(mapper);
}

return mapper;
}

private ObjectMapper createMapper() {
// enabled:
// case insensitive enums, so "before" will match to "BEFORE" in an enum
return JsonMapper.builder().enable(MapperFeature.ACCEPT_CASE_INSENSITIVE_ENUMS).build();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we really want to allow case-insensitive enum values? (I guess question for Aaron)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added it for the returnDocument option of the findOneAndUpdate command. While the enum name would be BEFORE or AFTER we would not want to force that in the JSON encoding

Copy link
Contributor

@tatu-at-datastax tatu-at-datastax Nov 29, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One thing to note: instead of globally allowing all Enum values to be case-insensitive, it is possible to annotate just ones that do. It's with something like:

@JsonFormat(with = [ JsonFormat.Feature.ACCEPT_CASE_INSENSITIVE_VALUES ])
public MyEnum value; // on field or accessor/method

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But then you must no forget it on every enum, globally it is imo..

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, true. This would be only if a small number of places allowed this which is sometimes the case.

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package io.stargate.sgv3.docsapi.api.model.command;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import io.stargate.sgv3.docsapi.api.model.command.impl.FindOneCommand;
import io.stargate.sgv3.docsapi.api.model.command.impl.InsertOneCommand;

/**
* POJO object (data no behavior) that represents a syntactically and grammatically valid command as
* defined in the API spec.
*
* <p>The behavior about *how* to run a Command is in the {@link CommandResolver}.
*
* <p>Commands <b>should not</b> include JSON other than for documents we want to insert. They
* should represent a translate of the API request into an internal representation. e.g. this
* insulates from tweaking JSON on the wire protocol, we would only need to modify how we create the
* command and nothing else.
*
* <p>These may be created from parsing the incoming message and could also be created
* programmatically for internal and testing purposes.
*
* <p>Each command should validate itself using the <i>javax.validation</i> framework.
*/
@JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
include = JsonTypeInfo.As.WRAPPER_OBJECT,
property = "commandName")
@JsonSubTypes({
@JsonSubTypes.Type(value = FindOneCommand.class),
@JsonSubTypes.Type(value = InsertOneCommand.class),
})
@JsonIgnoreProperties({"commandName"})
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll test this at a later point but I don't think this ignoral is needed.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes you are correct, simply copied from the poc code and did not give a lot of thought here..

public interface Command {}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be called CollectionCommand as we need to differentiate between commands that can be used on the /v3/{database} and /v3/{database}/{collection}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we put that after Command so we have a common base for all Commands.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yea would need to define the hierarchy then on the new class, keeping it like this, we can adapt when we add the DatabaseCommands.

Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package io.stargate.sgv3.docsapi.api.model.command;

/** Base for any commands that modify, such as insert, delete, update, etc. */
public interface ModifyCommand extends Command {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package io.stargate.sgv3.docsapi.api.model.command;

public interface ReadCommand extends Command {}
ivansenic marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package io.stargate.sgv3.docsapi.api.model.command.clause.sort;

import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import io.stargate.sgv3.docsapi.api.model.command.deserializers.SortClauseDeserializer;
import java.util.List;
import javax.validation.Valid;

/**
* Internal model for the sort clause that can be used in the commands.
*
* @param sortExpressions Ordered list of sort expressions.
*/
@JsonDeserialize(using = SortClauseDeserializer.class)
public record SortClause(@Valid List<SortExpression> sortExpressions) {}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This needs proper schema defining this is a array of strings in the swagger

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have been wondering about this: I thought the intent is for "DocsV3" to be backend for Mongoose drivers but not a general-purpose REST API. If so, would Swagger even be needed/useful?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes for the target is not HTTP REST.

We also want to avoid putting the JSON encoding attribution on the commands. The commands should just represent the object model, serialisation is seperate.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here there are few things that we should discuss:

  • do you both imply that we don't need swagger ui here? why is that, seems quite handy? how would this be applied to Astra prod where we do need the swagger ui?
  • avoid putting the JSON encoding attribution on the commands, what does this mean? is this for going back on the mixins way? so you would rather not have model and serialization in one place, easy to understand and look at, but rather split this into another, effectively not needed, class that you need to search and find to understand how's everything working?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@tatu-at-datastax @amorton Aaron and I kinda agreed to keep the swagger UI for now and try to define the schemas correctly.. We would not only have the benefit of supporting astra-prod requirements, but also gain benefits from the open API spec that can be used in postman, to generate clients or display docs in redoc or other similar tools..

Regarding the JSON encoding attribution, we agreed that we need to think for a day or two about extracting engine out of the http stuff. This would mean having two projects in this repo, one pure engine, another HTTP wrapper around.. IF we do so, the JSON encoding attribution would be done in the HTTP project using mixins.

Copy link
Contributor

@tatu-at-datastax tatu-at-datastax Nov 29, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I am not dead against Swagger, but also want to help avoid significant effort being spent on something that won't be needed (if that's the case).
Sort of like why GraphQL doesn't have Swagger definitions even though technically speaking one could add definitions (but no one would use Swagger).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On JSON bindings: to me most of annotation metadata is not a form of tight coupling. There are exceptions (specifying custom (de)serializers f.ex), but for basic external naming of properties where needed (overrides with @JsonProperty) externalization seems like unnecessary work.
There's only a single dependency (jackson-annotations) package (which itself has no deps), for annotations themselves and any library/framework is free to use or not those (that is: there is no need to depend on Jackson library for parsing/generation of JSON at all; only annotation types). Model itself could be used with other libraries too (but possibly adding annotation/configuration they need).
I can help minimizing need for annotations and maybe avoid most or all mix-ins.

Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package io.stargate.sgv3.docsapi.api.model.command.clause.sort;

import javax.validation.constraints.NotBlank;

public record SortExpression(

// TODO correct typing for the path, we could use some kind of a common class
// we also need a validation of a correct path here
@NotBlank String path,

// this can be modeled in different ways, would this be enough for now
boolean ascending) {}
Comment on lines +7 to +12
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@amorton Look for suggestions here

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We cannot implement sort until we get sort in the core DB next year so I had not thought about it. But this is basically it, there is a list of field and sort order.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Keep like this until further notice..

Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package io.stargate.sgv3.docsapi.api.model.command.deserializers;

import com.fasterxml.jackson.core.JacksonException;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
import io.stargate.sgv3.docsapi.api.model.command.clause.sort.SortClause;
import io.stargate.sgv3.docsapi.api.model.command.clause.sort.SortExpression;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

/** {@link StdDeserializer} for the {@link SortClause}. */
public class SortClauseDeserializer extends StdDeserializer<SortClause> {

/** No-arg constructor explicitly needed. */
public SortClauseDeserializer() {
super(SortClause.class);
}

/** {@inheritDoc} */
@Override
public SortClause deserialize(JsonParser parser, DeserializationContext ctxt)
throws IOException, JacksonException {
JsonNode node = parser.getCodec().readTree(parser);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can fix this, but better version is

JsonNode node = ctxt.readTree(parser);


// if missing or null, return null back
if (node.isMissingNode() || node.isNull()) {
return null;
}

// TODO, should we have specific exceptions, or throw generic JSON ones?
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@amorton wdyt, can you have a look on our BusinessRuntimeException idea in the v2?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I kept all the exceptions as RuntimeException to be consistency wrong as I was not aware how we wanted to model them. We will need something like that, I would guess there are Syntax errors and InvalidRequest for this sort of area, based on the CQL error states.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's discuss and agree on this..

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not being discussed, will create an issue for this.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#9

Copy link
Contributor

@tatu-at-datastax tatu-at-datastax Nov 29, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that there absolutely should be at least one custom exception (base) type beyond JDK provided ones. Can start with a single "document exception" type which can be RuntimeException if we want to avoid checked exceptions (which seems to be where most Java devs are leaning).


// otherwise, if it's not array throw exception
if (!node.isArray()) {
throw new JsonMappingException(
parser, "Sort clause must be submitted as the array of strings.");
}

// safe iterate, we know it's array
List<SortExpression> expressions = new ArrayList<>();
for (JsonNode inner : node) {
if (!inner.isTextual()) {
throw new JsonMappingException(
parser, "Sort clause expression must be represented as strings.");
}

String text = inner.asText();
if (text.isBlank()) {
throw new JsonMappingException(
parser, "Sort clause expression must be represented as not-blank strings.");
}

boolean ascending = text.charAt(0) != '-';
String path = ascending ? text : text.substring(1);
if (path.isBlank()) {
throw new JsonMappingException(parser, "A sort clause expression path must not be blank.");
}

SortExpression exp = new SortExpression(path.trim(), ascending);
expressions.add(exp);
}

return new SortClause(expressions);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package io.stargate.sgv3.docsapi.api.model.command.impl;

import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonTypeName;
import io.stargate.sgv3.docsapi.api.model.command.ReadCommand;
import io.stargate.sgv3.docsapi.api.model.command.clause.sort.SortClause;
import javax.validation.Valid;
import org.eclipse.microprofile.openapi.annotations.media.Schema;

@Schema(description = "Command that finds a single JSON document from a collection.")
Copy link
Contributor

@amorton amorton Nov 29, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm a -1 on swagger annotations like this in the code. We want the Doc API library to be a library like the CQL Native Binary driver, it's with a HTTP/JSON interface is just one use. There could also be gRPC or included as a library in a client code.

I have the same thoughts on sprint boot attributions like @Valid. It limits the library to working in a spring boot environment, which I would like to avoid for core business logic like this.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again, not sure I am following that you want not to have swagger? And how would this work with astra-prod? I see a benefit of having it, because you can simply start the app, go to swagger and start executing commands.. You don't need postman, collections, client, nothing.. But again let's discuss and agree..

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed that swagger annotations in the code make sense since they force programmer to change docs if the code changes.. It also ensures docs and code are merged together.. If we decide to split the engine in the separate project, then we need to see where should the annotation reside.

@JsonTypeName("findOne")
public record FindOneCommand(@Valid @JsonProperty("sort") SortClause sortClause)
implements ReadCommand {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package io.stargate.sgv3.docsapi.api.model.command.impl;

import com.fasterxml.jackson.annotation.JsonTypeName;
import com.fasterxml.jackson.databind.JsonNode;
import io.stargate.sgv3.docsapi.api.model.command.Command;
import io.stargate.sgv3.docsapi.api.model.command.ModifyCommand;
import javax.validation.constraints.NotNull;
import org.eclipse.microprofile.openapi.annotations.enums.SchemaType;
import org.eclipse.microprofile.openapi.annotations.media.Schema;

/**
* Representation of the insertOne API {@link Command}.
*
* @param document The document to insert.
*/
@Schema(description = "Command that inserts a single JSON document to a collection.")
@JsonTypeName("insertOne")
public record InsertOneCommand(
@NotNull
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this should contain a proper error message..

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to put the validate() methods back and do validation in there, for a couple of reasons.

  • there will be complex validation steps, e.g. check that nothing in an update clause tries to change the _id of a document, or that the data types for an _id document are those we support.
  • we want the document library to work outside of a spring boot environment.

Copy link
Contributor Author

@ivansenic ivansenic Nov 29, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can achieve anything you want as you can easily create your own annotations, validations and rules.

This had nothing to do with spring boot, this is javax.validation, a framework that helps you validate things easier.. Meaning, that you can still use the framework outside of spring boot or quarkus.

therwise, you can avoid having it, but then create you own validation framework, meaning you need to have vlidations in place, you need a way to validate those, create error messages and translate that to the response with errors.. Wouldn't this be an overkill, especially when we are so fragile about the time?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed to keep the javax.validation. For now we will let Quarkus validate commands. In the future, we want to integrate this into engine, so that commands are validated no matter how are they created. We have a ticket for validation, so we will do it there: https://datastax.jira.com/browse/C2-2280

@Schema(
description = "JSON document to insert.",
implementation = Object.class,
type = SchemaType.OBJECT)
JsonNode document)
implements ModifyCommand {}
Original file line number Diff line number Diff line change
@@ -1,25 +1,56 @@
package io.stargate.sgv3.docsapi.api.v3;

import io.smallrye.mutiny.Uni;
import io.stargate.sgv3.docsapi.api.model.command.Command;
import io.stargate.sgv3.docsapi.api.model.command.impl.FindOneCommand;
import io.stargate.sgv3.docsapi.api.model.command.impl.InsertOneCommand;
import io.stargate.sgv3.docsapi.config.constants.OpenApiConstants;
import javax.validation.Valid;
import javax.validation.constraints.NotNull;
import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import org.eclipse.microprofile.openapi.annotations.Operation;
import org.eclipse.microprofile.openapi.annotations.media.Content;
import org.eclipse.microprofile.openapi.annotations.media.ExampleObject;
import org.eclipse.microprofile.openapi.annotations.media.Schema;
import org.eclipse.microprofile.openapi.annotations.parameters.Parameter;
import org.eclipse.microprofile.openapi.annotations.parameters.Parameters;
import org.eclipse.microprofile.openapi.annotations.parameters.RequestBody;
import org.eclipse.microprofile.openapi.annotations.security.SecurityRequirement;
import org.eclipse.microprofile.openapi.annotations.tags.Tag;
import org.jboss.resteasy.reactive.RestResponse;

@Path(CollectionResource.BASE_PATH)
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
@SecurityRequirement(name = OpenApiConstants.SecuritySchemes.TOKEN)
@Tag(name = "Documents", description = "Executes document commands against a single collection.")
public class CollectionResource {

public static final String BASE_PATH = "/v3/{database}/{collection}";

@Operation(
summary = "Execute command",
description = "Executes a single command against a collection.")
@Parameters(
value = {
@Parameter(name = "database", ref = "database"),
@Parameter(name = "collection", ref = "collection")
})
@RequestBody(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A Question - I quickly looked at the OpenAPI spec when I was looking at postman, and it looked like we would need to define the whole query API was that a correct assumption ?

Happy for this to be here, we will not be promoting the Doc V3 API as a HTTP API to start with. To start with will be promoting and expecting all calls to come from Mongoose, I'm sure we will later expand to other ORM's and direct calls.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did not get this one sorry..

content =
@Content(
mediaType = MediaType.APPLICATION_JSON,
schema = @Schema(anyOf = {FindOneCommand.class, InsertOneCommand.class}),
examples = {
@ExampleObject(ref = "findOne"),
@ExampleObject(ref = "insertOne"),
}))
@POST
public Uni<RestResponse<?>> postCommand() {
public Uni<RestResponse<?>> postCommand(@NotNull @Valid Command command) {
return Uni.createFrom().item(RestResponse.ok());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,14 @@
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import org.eclipse.microprofile.openapi.annotations.security.SecurityRequirement;
import org.eclipse.microprofile.openapi.annotations.tags.Tag;
import org.jboss.resteasy.reactive.RestResponse;

@Path(DatabaseResource.BASE_PATH)
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
@SecurityRequirement(name = OpenApiConstants.SecuritySchemes.TOKEN)
@Tag(name = "Databases", description = "Executes database commands.")
public class DatabaseResource {

public static final String BASE_PATH = "/v3/{database}";
Expand Down
Loading