org.finos.tracdap.gateway.proxy.rest.RestApiFields Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of tracdap-gateway Show documentation
Show all versions of tracdap-gateway Show documentation
TRAC D.A.P. gateway component, provides authentication, routing, load balancing and API translation
/*
* Copyright 2022 Accenture Global Solutions Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.finos.tracdap.gateway.proxy.rest;
import org.finos.tracdap.common.exception.EStartup;
import com.google.protobuf.Descriptors;
import com.google.protobuf.Message;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Function;
import java.util.regex.Pattern;
public class RestApiFields {
// For now, only support simple variables, e.g. /path/to/{request.field1}/{request.field2}
// Captures of the form {request.field=some/path/*} require more work
public static final Pattern SEGMENT_CAPTURE_PATTERN = Pattern.compile(
"\\A\\{(?\\w+(?:\\.\\w+)*)}\\Z");
public static boolean
isSegmentCapture(String pathSegment) {
return SEGMENT_CAPTURE_PATTERN.matcher(pathSegment).matches();
}
public static List
prepareFieldsForPathSegment(Descriptors.Descriptor requestDescriptor, String pathSegment) {
var segmentCapture = RestApiFields.SEGMENT_CAPTURE_PATTERN.matcher(pathSegment);
if (!segmentCapture.matches())
return List.of();
var fullFieldName = segmentCapture.group("fieldName");
return prepareFieldDescriptors(requestDescriptor, fullFieldName);
}
public static List
prepareFieldDescriptors(Descriptors.Descriptor messageDescriptor, String fullFieldName) {
// body = * means fold the body into the top level object
// In this case, the sub-field selector should be an empty list
if (fullFieldName.equals("*"))
return List.of();
var fieldNames = Arrays.asList(fullFieldName.split("\\."));
var fieldDescriptors = new ArrayList();
for (var fieldLevel = 0; fieldLevel < fieldNames.size(); fieldLevel++) {
var fieldName = fieldNames.get(fieldLevel);
var fieldDescriptor = messageDescriptor.findFieldByName(fieldName);
if (fieldDescriptor == null) {
// TODO: Error message
var message = String.format("Invalid URL template for Rest API: Unknown request field [%s]", fieldName);
throw new EStartup(message);
}
fieldDescriptors.add(fieldDescriptor);
if (fieldLevel < fieldNames.size() - 1)
messageDescriptor = fieldDescriptor.getMessageType();
if (messageDescriptor == null) {
// TODO: Error message
var message = String.format("Invalid URL template for Rest API: Not a nested field [%s]", fieldName);
throw new EStartup(message);
}
}
return fieldDescriptors;
}
public static Function
prepareSubFieldMapper(List fields) {
if (fields.size() == 1)
return req -> req;
return req -> mapSubfield(req, fields);
}
private static Message.Builder
mapSubfield(TRequest.Builder request, List fields) {
for (var fieldLevel = 0; fieldLevel < fields.size() - 1; fieldLevel++) {
var field = fields.get(fieldLevel);
var subField = request.getFieldBuilder(field);
if (subField == null) {
subField = request.newBuilderForField(field);
request.setField(field, subField);
}
request = subField;
}
return request;
}
}