-
Notifications
You must be signed in to change notification settings - Fork 119
feat: REST Gapic (REGAPIC) Support #1177
Changes from 16 commits
85bb35d
d6c2829
55b9f21
3c4c19d
aee533a
e02e368
7c08c24
d264bc6
3a982ff
a71e5d8
07b20ba
7f72f2b
0c0328b
5f257e6
71474be
b231f0f
d3b13f9
79c41a1
0dc2d89
169fcf2
2619f63
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
/* | ||
* Copyright 2020 Google LLC | ||
* | ||
* Redistribution and use in source and binary forms, with or without | ||
* modification, are permitted provided that the following conditions are | ||
* met: | ||
* | ||
* * Redistributions of source code must retain the above copyright | ||
* notice, this list of conditions and the following disclaimer. | ||
* * Redistributions in binary form must reproduce the above | ||
* copyright notice, this list of conditions and the following disclaimer | ||
* in the documentation and/or other materials provided with the | ||
* distribution. | ||
* * Neither the name of Google LLC nor the names of its | ||
* contributors may be used to endorse or promote products derived from | ||
* this software without specific prior written permission. | ||
* | ||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
*/ | ||
package com.google.api.gax.httpjson; | ||
|
||
import com.google.api.core.BetaApi; | ||
|
||
/** | ||
* A functional interface to be implemented for each request message to extract specific fields from | ||
* it. For advanced usage only. | ||
*/ | ||
@BetaApi | ||
public interface FieldsExtractor<RequestT, ParamsT> { | ||
miraleung marked this conversation as resolved.
Show resolved
Hide resolved
vchudnov-g marked this conversation as resolved.
Show resolved
Hide resolved
|
||
ParamsT extract(RequestT request); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,120 @@ | ||
/* | ||
* Copyright 2020 Google LLC | ||
* | ||
* Redistribution and use in source and binary forms, with or without | ||
* modification, are permitted provided that the following conditions are | ||
* met: | ||
* | ||
* * Redistributions of source code must retain the above copyright | ||
* notice, this list of conditions and the following disclaimer. | ||
* * Redistributions in binary form must reproduce the above | ||
* copyright notice, this list of conditions and the following disclaimer | ||
* in the documentation and/or other materials provided with the | ||
* distribution. | ||
* * Neither the name of Google LLC nor the names of its | ||
* contributors may be used to endorse or promote products derived from | ||
* this software without specific prior written permission. | ||
* | ||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
*/ | ||
package com.google.api.gax.httpjson; | ||
|
||
import com.google.api.core.BetaApi; | ||
import com.google.api.pathtemplate.PathTemplate; | ||
import com.google.protobuf.Message; | ||
import java.util.List; | ||
import java.util.Map; | ||
|
||
/** Creates parts of a HTTP request from a protobuf message. */ | ||
@BetaApi | ||
public class ProtoMessageRequestFormatter<RequestT extends Message> | ||
miraleung marked this conversation as resolved.
Show resolved
Hide resolved
|
||
implements HttpRequestFormatter<RequestT> { | ||
|
||
private final FieldsExtractor<RequestT, String> requestBodyExtractor; | ||
private final FieldsExtractor<RequestT, Map<String, List<String>>> queryParamsExtractor; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. triple nested generics strongly suggests that there's a more detailed object type should be created for this. I.e. avoid FieldsExtractor of Map of List. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I agree that three nested generics is too much, but unfortunately I'm forced to do it here. This field is used solely to implement the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could you please add a brief comment to this effect, so that future well-meaning readers won't try to "fix" this? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I am increasingly less and less happy with GAX and GSON. Their mistakes are cascading down the dependency tree. :-( |
||
private final PathTemplate pathTemplate; | ||
private final FieldsExtractor<RequestT, Map<String, String>> pathVarsExtractor; | ||
|
||
private ProtoMessageRequestFormatter( | ||
FieldsExtractor<RequestT, String> requestBodyExtractor, | ||
FieldsExtractor<RequestT, Map<String, List<String>>> queryParamsExtractor, | ||
PathTemplate pathTemplate, | ||
FieldsExtractor<RequestT, Map<String, String>> pathVarsExtractor) { | ||
this.requestBodyExtractor = requestBodyExtractor; | ||
this.queryParamsExtractor = queryParamsExtractor; | ||
this.pathTemplate = pathTemplate; | ||
this.pathVarsExtractor = pathVarsExtractor; | ||
} | ||
|
||
public static <RequestT extends Message> | ||
ProtoMessageRequestFormatter.Builder<RequestT> newBuilder() { | ||
return new Builder<>(); | ||
} | ||
|
||
/* {@inheritDoc} */ | ||
@Override | ||
public Map<String, List<String>> getQueryParamNames(RequestT apiMessage) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't understand why a method called getQueryParamNames is returning a map? Names would seem to be a list. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It is implementing an existing interface. As I understand it, key is a name of a parameter, List is its values (to support array query parameters):
|
||
return queryParamsExtractor.extract(apiMessage); | ||
} | ||
|
||
/* {@inheritDoc} */ | ||
@Override | ||
public String getRequestBody(RequestT apiMessage) { | ||
return requestBodyExtractor.extract(apiMessage); | ||
} | ||
|
||
/* {@inheritDoc} */ | ||
@Override | ||
public String getPath(RequestT apiMessage) { | ||
return pathTemplate.instantiate(pathVarsExtractor.extract(apiMessage)); | ||
} | ||
|
||
/* {@inheritDoc} */ | ||
@Override | ||
public PathTemplate getPathTemplate() { | ||
return pathTemplate; | ||
} | ||
|
||
// This has class has compound setter methods (multiple arguments in setters), that is why not | ||
// using @AutoValue. | ||
public static class Builder<RequestT extends Message> { | ||
private FieldsExtractor<RequestT, String> requestBodyExtractor; | ||
private FieldsExtractor<RequestT, Map<String, List<String>>> queryParamsExtractor; | ||
private String path; | ||
private FieldsExtractor<RequestT, Map<String, String>> pathVarsExtractor; | ||
|
||
public Builder<RequestT> setRequestBodyExtractor( | ||
FieldsExtractor<RequestT, String> requestBodyExtractor) { | ||
this.requestBodyExtractor = requestBodyExtractor; | ||
return this; | ||
} | ||
|
||
public Builder<RequestT> setQueryParamsExtractor( | ||
FieldsExtractor<RequestT, Map<String, List<String>>> queryParamsExtractor) { | ||
this.queryParamsExtractor = queryParamsExtractor; | ||
return this; | ||
} | ||
|
||
public Builder<RequestT> setPath( | ||
String path, FieldsExtractor<RequestT, Map<String, String>> pathVarsExtractor) { | ||
this.path = path; | ||
this.pathVarsExtractor = pathVarsExtractor; | ||
return this; | ||
} | ||
|
||
public ProtoMessageRequestFormatter<RequestT> build() { | ||
return new ProtoMessageRequestFormatter<>( | ||
requestBodyExtractor, queryParamsExtractor, PathTemplate.create(path), pathVarsExtractor); | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
/* | ||
* Copyright 2020 Google LLC | ||
* | ||
* Redistribution and use in source and binary forms, with or without | ||
* modification, are permitted provided that the following conditions are | ||
* met: | ||
* | ||
* * Redistributions of source code must retain the above copyright | ||
* notice, this list of conditions and the following disclaimer. | ||
* * Redistributions in binary form must reproduce the above | ||
* copyright notice, this list of conditions and the following disclaimer | ||
* in the documentation and/or other materials provided with the | ||
* distribution. | ||
* * Neither the name of Google LLC nor the names of its | ||
* contributors may be used to endorse or promote products derived from | ||
* this software without specific prior written permission. | ||
* | ||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
*/ | ||
package com.google.api.gax.httpjson; | ||
|
||
import com.google.api.core.BetaApi; | ||
import com.google.protobuf.Message; | ||
import java.io.InputStream; | ||
|
||
/** The implementation of {@link HttpResponseParser} which works with protobuf messages. */ | ||
@BetaApi | ||
public class ProtoMessageResponseParser<ResponseT extends Message> | ||
miraleung marked this conversation as resolved.
Show resolved
Hide resolved
|
||
implements HttpResponseParser<ResponseT> { | ||
|
||
private final ResponseT defaultInstance; | ||
|
||
private ProtoMessageResponseParser(ResponseT defaultInstance) { | ||
this.defaultInstance = defaultInstance; | ||
} | ||
|
||
public static <RequestT extends Message> | ||
ProtoMessageResponseParser.Builder<RequestT> newBuilder() { | ||
return new ProtoMessageResponseParser.Builder<>(); | ||
} | ||
|
||
/* {@inheritDoc} */ | ||
@Override | ||
public ResponseT parse(InputStream httpContent) { | ||
return ProtoRestSerializer.<ResponseT>create() | ||
.fromJson(httpContent, defaultInstance.newBuilderForType()); | ||
} | ||
|
||
/* {@inheritDoc} */ | ||
@Override | ||
public String serialize(ResponseT response) { | ||
vchudnov-g marked this conversation as resolved.
Show resolved
Hide resolved
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm curious, and maybe I'll find the answer below: when does a client need to serialize a response message into a (JSON) string? Isn't it always paring JSON into messages? Or are we making this available purely for use by servers? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I was wondering the same thing. I don't have a good answer for you =). There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. OK. Maybe a brief comment inside the function to the effect that we're not using this in prod but this is needed by the interface? |
||
return ProtoRestSerializer.create().toJson(response); | ||
} | ||
|
||
// Convert to @AutoValue if this class gets more complicated | ||
public static class Builder<ResponseT extends Message> { | ||
private ResponseT defaultInstance; | ||
|
||
public Builder<ResponseT> setDefaultInstance(ResponseT defaultInstance) { | ||
this.defaultInstance = defaultInstance; | ||
return this; | ||
} | ||
|
||
public ProtoMessageResponseParser<ResponseT> build() { | ||
return new ProtoMessageResponseParser<>(defaultInstance); | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Important: this needs a character set, typically detected from the HTTP headers in this case
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
added