Skip to content

Commit 77edbb1

Browse files
committed
fix missing signingName in service metadata; Add content-type of rest-json
1 parent 0dd9cda commit 77edbb1

File tree

4 files changed

+124
-4
lines changed

4 files changed

+124
-4
lines changed

packages/protocol-rest/src/RestSerializer.spec.ts

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
import {RestSerializer} from './RestSerializer';
2-
import {HttpEndpoint} from '@aws-sdk/types';
2+
import {HttpEndpoint, Structure} from '@aws-sdk/types';
33

44
import {
55
complexGetOperation,
66
containsSubresourceGetOperation,
77
minimalPostOperation,
88
streamingPostOperation,
99
simpleGetOperation,
10-
simpleHeadOperation
10+
simpleHeadOperation,
11+
restJsonOperation
1112
} from './operations.fixture';
1213

1314
describe('RestMarshaller', () => {
@@ -460,6 +461,48 @@ describe('RestMarshaller', () => {
460461
expect(utf8Decoder.mock.calls.length).toBe(1);
461462
expect(serialized.headers['x-amz-json']).toBe('base64');
462463
});
464+
465+
describe('content-type header', () => {
466+
it('should not set Content-Type if payload is not supplied', () => {
467+
const toSerialize = {};
468+
const serialized = restMarshaller.serialize(restJsonOperation, toSerialize);
469+
expect(serialized.headers['Content-Type']).toBeUndefined();
470+
});
471+
472+
it('should set Content-Type to \'application/json\' if payload is a structure', () => {
473+
const toSerialize = {Payload: {}};
474+
const serialized = restMarshaller.serialize(restJsonOperation, toSerialize);
475+
expect(serialized.headers['Content-Type']).toBe('application/json');
476+
});
477+
478+
it('should set Content-Type to \'binary/octet-stream\' if payload is a blob', () => {
479+
const originPayload = (restJsonOperation.input.shape as Structure).members.Payload;
480+
(restJsonOperation.input.shape as Structure).members.Payload = {
481+
shape: {type: 'blob'}
482+
}
483+
const toSerialize = {Payload: 'payload blob'};
484+
const serialized = restMarshaller.serialize(restJsonOperation, toSerialize);
485+
expect(serialized.headers['Content-Type']).toBe('binary/octet-stream');
486+
(restJsonOperation.input.shape as Structure).members.Payload = originPayload;
487+
});
488+
489+
it('generated content-type should not override the header serialized from input', () => {
490+
const toSerialize = {
491+
Payload: {},
492+
ContentType: 'ShouldNotOverride'
493+
};
494+
const serialized = restMarshaller.serialize(restJsonOperation, toSerialize);
495+
expect(serialized.headers['Content-Type']).toBe('ShouldNotOverride');
496+
});
497+
498+
it('should default to use \'application/json\' Content-Type if no payload', () => {
499+
const payloadMember = (restJsonOperation.input.shape as Structure).payload;
500+
delete (restJsonOperation.input.shape as Structure).payload;
501+
const serialized = restMarshaller.serialize(restJsonOperation, {});
502+
expect(serialized.headers['Content-Type']).toBe('application/json');
503+
if (payloadMember) (restJsonOperation.input.shape as Structure).payload = payloadMember;
504+
})
505+
});
463506
});
464507
});
465508
});

packages/protocol-rest/src/RestSerializer.ts

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,9 @@ import {
1313
QueryParameterBag,
1414
RequestSerializer,
1515
SerializationModel,
16-
Structure as StructureShape
16+
Structure as StructureShape,
17+
SupportedProtocol,
18+
Structure
1719
} from '@aws-sdk/types';
1820

1921
import {
@@ -55,7 +57,10 @@ export class RestSerializer<StreamType> implements
5557
return {
5658
...this.endpoint,
5759
body,
58-
headers: serializedParts.headers,
60+
headers: {
61+
...this.populateContentTypeHeader(operation, input),
62+
...serializedParts.headers
63+
},
5964
method: httpTrait.method,
6065
query: serializedParts.query,
6166
path: serializedParts.uri
@@ -244,4 +249,34 @@ export class RestSerializer<StreamType> implements
244249
}
245250
}
246251
}
252+
253+
/**
254+
* Add Content-Type header for rest-json protocol explicitly
255+
* If payload is supplied in input, the content-type should be set according to payload shape;
256+
* If payload is specified but not supplied in input, no content-type header is needed;
257+
* If there's no payload in input shape, set content-type as 'application/json';
258+
* @param operation
259+
*/
260+
private populateContentTypeHeader(operation: OperationModel, input: any): HeaderBag {
261+
const contentTypeHeader = {};
262+
const {
263+
input: inputShape,
264+
metadata: {protocol}
265+
} = operation;
266+
if (protocol !== 'rest-json') return contentTypeHeader
267+
if (typeof (inputShape.shape as Structure).payload === 'string') {
268+
const payloadMemberName = (inputShape.shape as Structure).payload!;
269+
const payloadMember = (inputShape.shape as Structure).members[payloadMemberName];
270+
const payload = input[payloadMemberName];
271+
if (!payload) return contentTypeHeader;
272+
if (payloadMember.shape.type === 'structure') {
273+
return {'Content-Type': 'application/json'};
274+
} else if (payloadMember.shape.type === 'blob') {
275+
return {'Content-Type': 'binary/octet-stream'};
276+
}
277+
} else {
278+
return {'Content-Type': 'application/json'};
279+
}
280+
return contentTypeHeader;
281+
}
247282
}

packages/protocol-rest/src/operations.fixture.ts

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -442,4 +442,45 @@ export const simpleHeadOperation: OperationModel = {
442442
},
443443
},
444444
errors:[]
445+
}
446+
447+
export const restJsonOperation: OperationModel = {
448+
metadata: {
449+
...minimumMetadata,
450+
protocol: 'rest-json'
451+
},
452+
name: 'RestJsonOperation',
453+
http: {
454+
method: 'GET',
455+
requestUri: '/'
456+
},
457+
input: {
458+
shape: {
459+
type: 'structure',
460+
required: [],
461+
members: {
462+
ContentType: {
463+
shape: {type: 'string'},
464+
location: 'headers',
465+
locationName: 'Content-Type'
466+
},
467+
Payload: {
468+
shape: {
469+
type: 'structure',
470+
required: [],
471+
members: {}
472+
}
473+
}
474+
},
475+
payload: 'Payload'
476+
}
477+
},
478+
output: {
479+
shape: {
480+
type: 'structure',
481+
required: [],
482+
members: {}
483+
},
484+
},
485+
errors:[]
445486
}

packages/service-model/src/TreeModel/normalizeModel.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ function pruneServiceMetadata<T extends ServiceMetadata>(metadata: T): ServiceMe
9898
'serviceFullName',
9999
'serviceId',
100100
'signatureVersion',
101+
'signingName',
101102
'targetPrefix',
102103
'timestampFormat',
103104
'uid',

0 commit comments

Comments
 (0)