Skip to content

Commit

Permalink
Add support for gRPC transcoding
Browse files Browse the repository at this point in the history
  • Loading branch information
zZHorizonZz committed Jan 22, 2025
1 parent 723c025 commit 107d5dc
Show file tree
Hide file tree
Showing 47 changed files with 4,008 additions and 44 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@
import io.vertx.core.buffer.Buffer;
import io.vertx.core.json.DecodeException;
import io.vertx.core.json.Json;
import io.vertx.core.json.JsonObject;
import io.vertx.core.json.JsonArray;
import io.vertx.core.json.JsonObject;

import java.nio.charset.StandardCharsets;
import java.util.function.Supplier;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package io.vertx.grpc.common;

import io.vertx.codegen.annotations.VertxGen;
import io.vertx.grpc.common.transcoding.HttpTemplateImpl;
import io.vertx.grpc.common.transcoding.HttpTemplateParser;

import java.util.ArrayList;
import java.util.List;

/**
* Represents an HTTP template used in gRPC transcoding.
* <p>
* This interface defines methods for accessing the components of a parsed HTTP template string, including the segments, verb, and variables.
*
* @author Based on <a href="https://github.com/grpc-ecosystem/grpc-httpjson-transcoding/blob/master/src/http_template.cc">grpc-httpjson-transcoding</a>
*/
@VertxGen
public interface HttpTemplate {

/**
* Parses the given HTTP template string.
*
* @param template The HTTP template string to parse.
* @return The parsed {@code HttpTemplate}, or {@code null} if the parsing failed.
*/
static HttpTemplate parse(String template) {
if (template.equals("/")) {
return new HttpTemplateImpl(new ArrayList<>(), "", new ArrayList<>());
}

HttpTemplateParser parser = new HttpTemplateParser(template);
if (!parser.parse() || !parser.validateParts()) {
return null;
}

return new HttpTemplateImpl(parser.segments(), parser.verb(), parser.variables());
}

/**
* Returns the list of segments in the parsed template.
*
* @return The list of segments.
*/
List<String> getSegments();

/**
* Returns the verb in the parsed template.
*
* @return The verb.
*/
String getVerb();

/**
* Returns the list of variables in the parsed template.
*
* @return The list of variables.
*/
List<HttpTemplateVariable> getVariables();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
package io.vertx.grpc.common;

import io.vertx.codegen.annotations.VertxGen;
import io.vertx.grpc.common.transcoding.HttpTemplateVariableImpl;

import java.util.List;

/**
* Represents a variable within an HTTP template used in gRPC transcoding.
* <p>
* This interface defines methods for accessing information about a variable, such as its field path, start and end segments, and whether it represents a wildcard path.
*
* @author Based on <a href="https://github.com/grpc-ecosystem/grpc-httpjson-transcoding/blob/master/src/http_template.cc">grpc-httpjson-transcoding</a>
*/
@VertxGen
public interface HttpTemplateVariable {

/**
* Creates a new {@code HttpTemplateVariable} instance.
*
* @param fieldPath The field path of the variable.
* @param startSegment The starting segment of the variable.
* @param endSegment The ending segment of the variable.
* @param wildcardPath {@code true} if the variable represents a wildcard path, {@code false} otherwise.
* @return The created {@code HttpTemplateVariable} instance.
*/
static HttpTemplateVariable create(List<String> fieldPath, int startSegment, int endSegment, boolean wildcardPath) {
HttpTemplateVariableImpl variable = new HttpTemplateVariableImpl();
variable.setFieldPath(fieldPath);
variable.setStartSegment(startSegment);
variable.setEndSegment(endSegment);
variable.setWildcardPath(wildcardPath);
return variable;
}

/**
* Returns the field path of the variable.
*
* @return The field path.
*/
List<String> getFieldPath();

/**
* Sets the field path of the variable.
*
* @param fieldPath The field path to set.
*/
void setFieldPath(List<String> fieldPath);

/**
* Returns the starting segment of the variable.
*
* @return The starting segment.
*/
int getStartSegment();

/**
* Sets the starting segment of the variable.
*
* @param startSegment The starting segment to set.
*/
void setStartSegment(int startSegment);

/**
* Returns the ending segment of the variable.
*
* @return The ending segment.
*/
int getEndSegment();

/**
* Sets the ending segment of the variable.
*
* @param endSegment The ending segment to set.
*/
void setEndSegment(int endSegment);

/**
* Checks if the variable represents a wildcard path.
*
* @return {@code true} if the variable represents a wildcard path, {@code false} otherwise.
*/
boolean hasWildcardPath();

/**
* Sets whether the variable represents a wildcard path.
*
* @param wildcardPath {@code true} if the variable represents a wildcard path, {@code false} otherwise.
*/
void setWildcardPath(boolean wildcardPath);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package io.vertx.grpc.common;

import io.vertx.codegen.annotations.VertxGen;
import io.vertx.grpc.common.transcoding.HttpVariableBindingImpl;

import java.util.List;

/**
* Represents a binding between an HTTP request variable (from path or query parameters)
* and its corresponding gRPC message field path. This interface is used during HTTP-to-gRPC
* transcoding to map HTTP request variables to their appropriate locations in the gRPC message.
*
* The binding consists of:
* - A field path representing the location in the gRPC message where the value should be placed
* - The actual value extracted from the HTTP request
*/
@VertxGen
public interface HttpVariableBinding {

/**
* Creates a new HttpVariableBinding instance.
*
* @param fieldPath A list of field names representing the path in the gRPC message
* where the value should be placed. For example, ["user", "address", "city"]
* would represent a path to the city field in a nested message structure
* @param value The value extracted from the HTTP request that should be bound to this location
* @return A new HttpVariableBinding instance
*/
static HttpVariableBinding create(List<String> fieldPath, String value) {
return new HttpVariableBindingImpl(fieldPath, value);
}

/**
* Gets the field path that describes where in the gRPC message the value should be placed.
*
* @return A list of field names representing the path in the gRPC message
*/
List<String> getFieldPath();

/**
* Sets the field path that describes where in the gRPC message the value should be placed.
*
* @param fieldPath A list of field names representing the path in the gRPC message
*/
void setFieldPath(List<String> fieldPath);

/**
* Gets the value that was extracted from the HTTP request.
*
* @return The string value to be bound to the specified field path
*/
String getValue();

/**
* Sets the value that should be bound to the specified field path.
*
* @param value The string value to be bound to the specified field path
*/
void setValue(String value);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package io.vertx.grpc.common;

import io.vertx.codegen.annotations.VertxGen;

import java.util.List;

/**
* Matches HTTP request paths against registered patterns to look up corresponding gRPC methods. This interface provides functionality to match incoming HTTP requests to their
* corresponding gRPC method handlers based on the HTTP method, path, and optional query parameters.
*/
public interface PathMatcher {

/**
* Simple lookup method that matches an HTTP request to a gRPC method based on HTTP method and path.
*
* @param httpMethod the HTTP method of the request (e.g., "GET", "POST")
* @param path the request path to match
* @return the corresponding gRPC method name if a match is found, null otherwise
*/
String lookup(String httpMethod, String path);

/**
* Advanced lookup method that matches an HTTP request to a gRPC method and extracts variable bindings.
*
* @param httpMethod the HTTP method of the request (e.g., "GET", "POST")
* @param path the request path to match
* @param queryParams the query parameters string from the request
* @return the corresponding gRPC method name if a match is found, null otherwise
*/
PathMatcherLookupResult lookup(String httpMethod, String path, String queryParams);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
package io.vertx.grpc.common;

import io.vertx.codegen.annotations.VertxGen;
import io.vertx.grpc.common.transcoding.PercentEncoding;
import io.vertx.grpc.common.transcoding.PathMatcherMethodData;
import io.vertx.grpc.common.transcoding.PathMatcherNode;

import java.util.List;
import java.util.Set;

/**
* Builder interface for creating {@link PathMatcher} instances. Provides methods to configure and construct a path matcher with specific behaviors for HTTP-to-gRPC transcoding,
* including URL encoding/decoding options and custom verb handling.
*/
public interface PathMatcherBuilder {

/**
* Registers a service transcoding configuration with specific query parameter names.
*
* @param transcoding the service transcoding options
* @param queryParameterNames set of query parameter names to handle
* @param method the gRPC method name to associate with this pattern
* @return true if registration was successful, false otherwise
*/
boolean register(ServiceTranscodingOptions transcoding, Set<String> queryParameterNames, String method);

/**
* Registers a service transcoding configuration with default query parameter handling.
*
* @param transcodingOptions the service transcoding options
* @param method the gRPC method name to associate with this pattern
* @return true if registration was successful, false otherwise
*/
boolean register(ServiceTranscodingOptions transcodingOptions, String method);

/**
* Gets the root node of the path matching tree.
*
* @return the root PathMatcherNode
*/
PathMatcherNode getRoot();

/**
* Gets the set of registered custom verbs.
*
* @return set of custom verb strings
*/
Set<String> getCustomVerbs();

/**
* Gets the list of registered method data.
*
* @return list of PathMatcherMethodData objects
*/
List<PathMatcherMethodData> getMethodData();

/**
* Sets the URL unescaping specification for path variables.
*
* @param pathUnescapeSpec the URL unescaping specification to use
*/
void setUrlUnescapeSpec(PercentEncoding.UrlUnescapeSpec pathUnescapeSpec);

/**
* Gets the current URL unescaping specification.
*
* @return the current URL unescaping specification
*/
PercentEncoding.UrlUnescapeSpec getUrlUnescapeSpec();

/**
* Sets whether plus signs in query parameters should be unescaped to spaces.
*
* @param queryParamUnescapePlus true to unescape plus signs, false otherwise
*/
void setQueryParamUnescapePlus(boolean queryParamUnescapePlus);

/**
* Gets whether plus signs in query parameters are being unescaped to spaces.
*
* @return current setting for plus sign unescaping in query parameters
*/
boolean getQueryParamUnescapePlus();

/**
* Sets whether unregistered custom verbs should be matched.
*
* @param matchUnregisteredCustomVerb true to match unregistered custom verbs, false otherwise
*/
void setMatchUnregisteredCustomVerb(boolean matchUnregisteredCustomVerb);

/**
* Gets whether unregistered custom verbs are being matched.
*
* @return current setting for matching unregistered custom verbs
*/
boolean getMatchUnregisteredCustomVerb();

/**
* Sets whether registration should fail when attempting to register a duplicate pattern.
*
* @param failRegistrationOnDuplicate true to fail on duplicates, false to silently continue
*/
void setFailRegistrationOnDuplicate(boolean failRegistrationOnDuplicate);

/**
* Gets whether registration fails on duplicate patterns.
*
* @return current setting for failing on duplicate registrations
*/
boolean getFailRegistrationOnDuplicate();

/**
* Builds and returns a new PathMatcher instance based on the current configuration.
*
* @return a new PathMatcher instance
*/
PathMatcher build();
}
Loading

0 comments on commit 107d5dc

Please sign in to comment.