Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Inject request id #26

Merged
merged 4 commits into from
Aug 17, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions lib/AWS/Lambda.pm
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ use HTTP::Tiny;

our $VERSION = "0.0.6";

# the context of Lambda Function
our $context;

1;
__END__

Expand Down
2 changes: 2 additions & 0 deletions lib/AWS/Lambda/Bootstrap.pm
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use warnings;
use HTTP::Tiny;
use JSON::XS qw/decode_json encode_json/;
use Try::Tiny;
use AWS::Lambda;
use AWS::Lambda::Context;
use Scalar::Util qw(blessed);

Expand Down Expand Up @@ -70,6 +71,7 @@ sub handle_event {
$self->_init or return;
my ($payload, $context) = $self->lambda_next;
my $response = try {
local $AWS::Lambda::context = $context;
$self->{function}->($payload, $context);
} catch {
$self->lambda_error($_, $context);
Expand Down
29 changes: 23 additions & 6 deletions lib/AWS/Lambda/PSGI.pm
Original file line number Diff line number Diff line change
Expand Up @@ -55,17 +55,21 @@ sub wrap {
}

sub call {
my($self, $env) = @_;
my $input = $self->format_input($env);
my($self, $env, $ctx) = @_;

# $ctx is added by #26
# fall back to $AWS::Lambda::context because of backward compatibility.
$ctx ||= $AWS::Lambda::context;

my $input = $self->format_input($env, $ctx);
my $res = $self->app->($input);
return $self->format_output($res);
}

# API Gateway https://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-lambda-proxy-integrations.html
# Application Load Balancer https://docs.aws.amazon.com/elasticloadbalancing/latest/application/lambda-functions.html
sub format_input {
my $self = shift;
my $payload = shift;
my ($self, $payload, $ctx) = @_;
my $env = {};

# merge queryStringParameters and multiValueQueryStringParameters
Expand Down Expand Up @@ -112,6 +116,12 @@ sub format_input {
$env->{'psgix.harakiri'} = Plack::Util::TRUE;
$env->{'psgix.input.buffered'} = Plack::Util::TRUE;

# inject the request id that compatible with Plack::Middleware::RequestId
if ($ctx) {
$env->{'psgix.request_id'} = $ctx->aws_request_id;
$env->{'HTTP_X_REQUEST_ID'} = $ctx->aws_request_id;
}

my $body = $payload->{body};
if ($payload->{isBase64Encoded}) {
$body = decode_base64 $body;
Expand Down Expand Up @@ -208,15 +218,22 @@ Add the following script into your Lambda code archive.
my $func = AWS::Lambda::PSGI->wrap($app);

sub handle {
my $payload = shift;
return $func->($payload);
return $func->(@_);
}

1;

And then, L<Set up Lambda Proxy Integrations in API Gateway|https://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-lambda-proxy-integrations.html> or
L<Lambda Functions as ALB Targets|https://docs.aws.amazon.com/elasticloadbalancing/latest/application/lambda-functions.html>

=head1 DESCRIPTION

=head2 Request ID

L<AWS::Lambda::PSGI> injects the request id that compatible with L<Plack::Middleware::RequestId>.

env->{'psgix.request_id'} # It is same value with $context->aws_request_id

=head1 LICENSE

The MIT License (MIT)
Expand Down
15 changes: 15 additions & 0 deletions t/20_psgi.t
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ use Test::Deep qw(cmp_deeply);
use JSON::Types;
use Encode;

use AWS::Lambda::Context;
use AWS::Lambda::PSGI;

my $app = AWS::Lambda::PSGI->new;
Expand Down Expand Up @@ -211,4 +212,18 @@ subtest "query string enconding" => sub {
is $req->query_string, 'gif+ref+=', 'query string';
};

# inject the request id that compatible with Plack::Middleware::RequestId
subtest "request id" => sub {
my $context = AWS::Lambda::Context->new(
deadline_ms => 1000,
aws_request_id => '8476a536-e9f4-11e8-9739-2dfe598c3fcd',
invoked_function_arn => 'arn:aws:lambda:us-east-2:123456789012:function:custom-runtime',
);
my $input = decode_json(slurp("$FindBin::Bin/testdata/apigateway-get-request.json"));
my $output = $app->format_input($input, $context);
my $req = Plack::Request->new($output);
is $req->env->{'psgix.request_id'}, '8476a536-e9f4-11e8-9739-2dfe598c3fcd', 'get request id from the env';
is $req->header('X-Request-Id'), '8476a536-e9f4-11e8-9739-2dfe598c3fcd', 'get request id from the header';
};

done_testing;
6 changes: 5 additions & 1 deletion t/test_handlers/echo.pl
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
use utf8;
use strict;
use warnings;
use AWS::Lambda;

sub handle {
my $payload = shift;
my ($payload, $context) = @_;
die "payload is empty" unless $payload;
die "context is empty" unless $context;
die "AWS::Lambda::context is invalid" if $AWS::Lambda::context != $context;
return $payload;
}

Expand Down