/
JsonRpcProtocolGenerator.java
154 lines (131 loc) · 6.04 KB
/
JsonRpcProtocolGenerator.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
/*
* Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://aws.amazon.com/apache2.0
*
* or in the "license" file accompanying this file. This file 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 software.amazon.smithy.aws.typescript.codegen;
import java.util.Set;
import software.amazon.smithy.model.shapes.OperationShape;
import software.amazon.smithy.model.shapes.ServiceShape;
import software.amazon.smithy.model.shapes.Shape;
import software.amazon.smithy.model.shapes.StructureShape;
import software.amazon.smithy.model.traits.TimestampFormatTrait.Format;
import software.amazon.smithy.typescript.codegen.TypeScriptWriter;
import software.amazon.smithy.typescript.codegen.integration.DocumentMemberDeserVisitor;
import software.amazon.smithy.typescript.codegen.integration.DocumentMemberSerVisitor;
import software.amazon.smithy.typescript.codegen.integration.HttpRpcProtocolGenerator;
import software.amazon.smithy.utils.IoUtils;
import software.amazon.smithy.utils.SmithyInternalApi;
/**
* Handles general components across the AWS JSON protocols that have do not have
* HTTP bindings. It handles reading and writing from document bodies, including
* generating any functions needed for performing serde.
*
* This builds on the foundations of the {@link HttpRpcProtocolGenerator} to handle
* standard components of the HTTP requests and responses.
*
* @see JsonShapeSerVisitor
* @see JsonShapeDeserVisitor
* @see JsonMemberSerVisitor
* @see JsonMemberDeserVisitor
* @see AwsProtocolUtils
*/
@SmithyInternalApi
abstract class JsonRpcProtocolGenerator extends HttpRpcProtocolGenerator {
/**
* Creates a AWS JSON RPC protocol generator.
*/
JsonRpcProtocolGenerator() {
// AWS JSON RPC protocols will attempt to parse error codes from response bodies.
super(true);
}
@Override
protected String getOperationPath(GenerationContext context, OperationShape operationShape) {
return "/";
}
protected Format getDocumentTimestampFormat() {
return Format.EPOCH_SECONDS;
}
@Override
protected void generateDocumentBodyShapeSerializers(GenerationContext context, Set<Shape> shapes) {
AwsProtocolUtils.generateDocumentBodyShapeSerde(context, shapes,
// AWS JSON does not support jsonName
new JsonShapeSerVisitor(context, (shape, name) -> name));
}
@Override
protected void generateDocumentBodyShapeDeserializers(GenerationContext context, Set<Shape> shapes) {
AwsProtocolUtils.generateDocumentBodyShapeSerde(context, shapes,
// AWS JSON does not support jsonName
new JsonShapeDeserVisitor(context, (shape, name) -> name));
}
@Override
public void generateSharedComponents(GenerationContext context) {
super.generateSharedComponents(context);
AwsProtocolUtils.generateJsonParseBody(context);
AwsProtocolUtils.generateJsonParseErrorBody(context);
AwsProtocolUtils.addItempotencyAutofillImport(context);
TypeScriptWriter writer = context.getWriter();
writer.addUseImports(getApplicationProtocol().getResponseType());
writer.write(IoUtils.readUtf8Resource(getClass(), "load-json-error-code-stub.ts"));
}
@Override
protected void writeDefaultHeaders(GenerationContext context, OperationShape operation) {
super.writeDefaultHeaders(context, operation);
AwsProtocolUtils.generateUnsignedPayloadSigV4Header(context, operation);
// AWS JSON RPC protocols use a combination of the service and operation shape names,
// separated by a '.' character, for the target header.
TypeScriptWriter writer = context.getWriter();
ServiceShape serviceShape = context.getService();
String target = serviceShape.getId().getName(serviceShape) + "." + operation.getId().getName(serviceShape);
writer.write("'x-amz-target': $S,", target);
}
@Override
protected void serializeInputDocument(
GenerationContext context,
OperationShape operation,
StructureShape inputStructure
) {
TypeScriptWriter writer = context.getWriter();
writer.write("body = JSON.stringify($L);", inputStructure.accept(getMemberSerVisitor(context, "input")));
}
private DocumentMemberSerVisitor getMemberSerVisitor(GenerationContext context, String dataSource) {
return new JsonMemberSerVisitor(context, dataSource, getDocumentTimestampFormat());
}
@Override
protected boolean writeUndefinedInputBody(GenerationContext context, OperationShape operation) {
TypeScriptWriter writer = context.getWriter();
writer.write("const body = '{}';");
return true;
}
@Override
protected void writeErrorCodeParser(GenerationContext context) {
TypeScriptWriter writer = context.getWriter();
// Outsource error code parsing since it's complex for this protocol.
writer.write("const errorCode = loadRestJsonErrorCode(output, parsedOutput.body);");
}
@Override
protected void deserializeOutputDocument(
GenerationContext context,
OperationShape operation,
StructureShape outputStructure
) {
TypeScriptWriter writer = context.getWriter();
writer.write("contents = $L;", outputStructure.accept(getMemberDeserVisitor(context, "data")));
}
private DocumentMemberDeserVisitor getMemberDeserVisitor(GenerationContext context, String dataSource) {
return new JsonMemberDeserVisitor(context, dataSource, getDocumentTimestampFormat());
}
@Override
public void generateProtocolTests(GenerationContext context) {
AwsProtocolUtils.generateProtocolTests(this, context);
}
}