In case of Lambda proxy integration, there are two requirements:
The binary should be base64-encoded on the function's response, include the 'isBase64Encoded' attribute set to 'true' and a 'Content-Type' header to indicate to the client the type of data that it returns. See example in [1].
The 'binaryMediaTypes' on the API settings must support such 'Content-Type' so the payload could be handle as binary [2].
Note: For proxy integrations, API Gateway passes the entire request through to your backend, and you do not have the option to modify the passthrough behaviors [3].
If you use '/' wildcard as the binary media type and the response from the Lambda is flagged as not base64 encoded, then the Lambda response will not be treated as binary, and the response will be returned in text format ( e.g. base64 encoded in case you encoded the file). Please note if your client is not prepared to handle the text response, it may see your binary as corrupted..
API Gateway applies a base64 decode for mime-type registered for binary support, if the payload received by the backend integration is base64 encoded.
Returning binary with a mapping template(in general):
The issue with returning binary with a mapping template if that if you need to select "CONVERT_TO_BINARY" in the Integration response, this will be applied before the mapping template is applied and this will result in the failure. Mapping template are meant to be used only and exclusively for application/json payloads. Using it with other content types and binary does not work well as mapping templates were not meant to work with those.
The mapping template you mentioned will not work. If you want to have a binary file as response, the CONVERT_TO_BINARY will be applied before the mapping template, hence this will not work. This is a limitation of mapping templates and hence it would be recommend to use Lambda Proxy Integration, or retuning from your Lambda template only the base64 encoded payload, no JSON or other data in it. Using $util.base64Decode will also not result in a valid binary file as API Gateway would still try to interpret it as application/json and hence the payload will be corrupted.
Following are the options you can consider:
1- Return the application/pdf as base64 encoded string from your lambda and then apply CONVERT_TO_BINARY in the Integration Response Passthrough. You will also need to statically specify the Content-Type response header in the integration response and method responses. Leave the response mapping template empty so the body is passed through and converted to a proper binary file.
2- Use Lambda proxy integration and return the payload as you were doing, with the headers, body as base64 encoded payload and 'isBase64Encoded': true. API Gateway will take care of setting the proper headers and return the file as binary.