in codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/integration/HttpRpcProtocolGenerator.java [110:231]
protected abstract void generateEventStreamSerializers(
GenerationContext context,
UnionShape eventUnion,
Set<EventStreamInfo> eventStreamInfos
);
/**
* Generate the event stream deserializers for the given event stream target and asscioated operations.
*
* @param context the generation context
* @param eventUnion the event stream union
* @param eventStreamInfos the event stream infos
*/
protected abstract void generateEventStreamDeserializers(
GenerationContext context,
UnionShape eventUnion,
Set<EventStreamInfo> eventStreamInfos
);
private void generateOperationSerializer(GenerationContext context, OperationShape operation) {
SymbolProvider symbolProvider = context.getSymbolProvider();
Model model = context.getModel();
ServiceShape service = context.getService();
Shape inputShape = ProtocolUtils.expectInput(model, operation);
Symbol inputSymbol = symbolProvider.toSymbol(inputShape);
ApplicationProtocol applicationProtocol = getApplicationProtocol();
Symbol requestType = applicationProtocol.getRequestType();
GoWriter writer = context.getWriter().get();
writer.pushState();
GoStackStepMiddlewareGenerator middleware = GoStackStepMiddlewareGenerator.createSerializeStepMiddleware(
ProtocolGenerator.getSerializeMiddlewareName(operation.getId(), service, getProtocolName()),
ProtocolUtils.OPERATION_SERIALIZER_MIDDLEWARE_ID);
middleware.writeMiddleware(context.getWriter().get(), (generator, w) -> {
writer.addUseImports(SmithyGoDependency.SMITHY);
writer.addUseImports(SmithyGoDependency.FMT);
writer.addUseImports(SmithyGoDependency.SMITHY_HTTP_BINDING);
writer.write(goTemplate("""
_, span := $T(ctx, "OperationSerializer")
endTimer := startMetricTimer(ctx, "client.call.serialization_duration")
defer endTimer()
defer span.End()
""", SMITHY_TRACING.func("StartSpan")));
// TODO: refactor the http binding encoder to be split up into its component parts
// This would allow most of this shared code to be split off into its own function
// to reduce duplication, and potentially allowing it to be a static function.
// For example, a HeaderBag type could handle all the headers.
// Cast the input request to the transport request type and check for errors.
writer.write("request, ok := in.Request.($P)", requestType);
writer.openBlock("if !ok {", "}", () -> {
writer.write("return out, metadata, "
+ "&smithy.SerializationError{Err: fmt.Errorf(\"unknown transport type %T\", in.Request)}"
);
}).write("");
// Cast the input parameters to the operation request type and check for errors.
writer.write("input, ok := in.Parameters.($P)", inputSymbol);
writer.write("_ = input");
writer.openBlock("if !ok {", "}", () -> {
writer.write("return out, metadata, "
+ "&smithy.SerializationError{Err: fmt.Errorf(\"unknown input parameters type %T\","
+ " in.Parameters)}");
}).write("");
writer.putContext("opPath", getOperationPath(context, operation));
writer.putContext("pathJoin", SymbolUtils.createValueSymbolBuilder("Join",
SmithyGoDependency.PATH).build());
writer.write("""
operationPath := $opPath:S
if len(request.Request.URL.Path) == 0 {
request.Request.URL.Path = operationPath
} else {
request.Request.URL.Path = $pathJoin:T(request.Request.URL.Path, operationPath)
if request.Request.URL.Path != "/" && operationPath[len(operationPath)-1] == '/' {
request.Request.URL.Path += "/"
}
}""");
writer.write("request.Request.Method = \"POST\"");
writer.write("httpBindingEncoder, err := httpbinding.NewEncoder(request.URL.Path, "
+ "request.URL.RawQuery, request.Header)");
writer.openBlock("if err != nil {", "}", () -> {
writer.write("return out, metadata, &smithy.SerializationError{Err: err}");
});
Optional<EventStreamInfo> optionalEventStreamInfo = EventStreamIndex.of(model).getInputInfo(operation);
// Skip and Handle Input Event Stream Setup Separately
if (optionalEventStreamInfo.isEmpty()) {
writeRequestHeaders(context, operation, writer);
writer.write("");
// delegate the setup and usage of the document serializer function for the protocol
serializeInputDocument(context, operation);
// Skipping calling serializer method for the input shape is responsibility of the
// serializeInputDocument implementation.
if (!CodegenUtils.isStubSynthetic(ProtocolUtils.expectInput(context.getModel(), operation))) {
serializingDocumentShapes.add(ProtocolUtils.expectInput(model, operation));
}
} else {
writeDefaultHeaders(context, operation, writer);
writeOperationSerializerMiddlewareEventStreamSetup(context, optionalEventStreamInfo.get());
}
writer.write("");
writer.openBlock("if request.Request, err = httpBindingEncoder.Encode(request.Request); err != nil {",
"}", () -> {
writer.write("return out, metadata, &smithy.SerializationError{Err: err}");
});
// Ensure the request value is updated if modified for a document.
writer.write("in.Request = request");
writer.write("");
writer.write("endTimer()");
writer.write("span.End()");
writer.write("return next.$L(ctx, in)", generator.getHandleMethodName());
});
writer.popState();
}