diff --git a/grpc-validation-utils/build.gradle.kts b/grpc-validation-utils/build.gradle.kts new file mode 100644 index 0000000..c21ea59 --- /dev/null +++ b/grpc-validation-utils/build.gradle.kts @@ -0,0 +1,9 @@ +plugins { + `java-library` +} + +dependencies { + api(project(":grpc-context-utils")) + api("io.grpc:grpc-api") + implementation("com.google.protobuf:protobuf-java-util:3.21.7") +} diff --git a/grpc-validation-utils/src/main/java/org/hypertrace/core/grpcutils/validation/GrpcValidatorUtils.java b/grpc-validation-utils/src/main/java/org/hypertrace/core/grpcutils/validation/GrpcValidatorUtils.java new file mode 100644 index 0000000..b5047a0 --- /dev/null +++ b/grpc-validation-utils/src/main/java/org/hypertrace/core/grpcutils/validation/GrpcValidatorUtils.java @@ -0,0 +1,58 @@ +package org.hypertrace.core.grpcutils.validation; + +import com.google.protobuf.Descriptors.FieldDescriptor; +import com.google.protobuf.Message; +import com.google.protobuf.util.JsonFormat; +import io.grpc.Status; +import org.hypertrace.core.grpcutils.context.RequestContext; + +public class GrpcValidatorUtils { + private static final JsonFormat.Printer JSON_PRINTER = JsonFormat.printer(); + + private GrpcValidatorUtils() {} + + public static void validateRequestContextOrThrow(RequestContext requestContext) { + if (requestContext.getTenantId().isEmpty()) { + throw Status.INVALID_ARGUMENT + .withDescription("Missing expected Tenant ID") + .asRuntimeException(); + } + } + + public static void validateNonDefaultPresenceOrThrow( + T source, int fieldNumber) { + FieldDescriptor descriptor = source.getDescriptorForType().findFieldByNumber(fieldNumber); + + if (descriptor.isRepeated()) { + validateNonDefaultPresenceRepeatedOrThrow(source, descriptor); + } else if (!source.hasField(descriptor) + || source.getField(descriptor).equals(descriptor.getDefaultValue())) { + throw Status.INVALID_ARGUMENT + .withDescription( + String.format( + "Expected field value %s but not present:%n %s", + descriptor.getFullName(), printMessage(source))) + .asRuntimeException(); + } + } + + private static void validateNonDefaultPresenceRepeatedOrThrow( + T source, FieldDescriptor descriptor) { + if (source.getRepeatedFieldCount(descriptor) == 0) { + throw Status.INVALID_ARGUMENT + .withDescription( + String.format( + "Expected at least 1 value for repeated field %s but not present:%n %s", + descriptor.getFullName(), printMessage(source))) + .asRuntimeException(); + } + } + + public static String printMessage(Message message) { + try { + return JSON_PRINTER.print(message); + } catch (Exception exception) { + return message.toString(); + } + } +} diff --git a/settings.gradle.kts b/settings.gradle.kts index 10b98c5..c13b603 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -17,3 +17,4 @@ include(":grpc-client-rx-utils") include(":grpc-server-rx-utils") include(":grpc-context-utils") include(":grpc-server-utils") +include(":grpc-validation-utils")