A. Tewatia
A. Tewatia

Reputation: 11

Calling Laravel Routes hosted on AWS Lambda using AWS API Gateway

I am trying to host a laravel application on aws lambda and call it's routes using aws api gateway. The application is basically a web crawler which fetches web pages from rss feeds.

When I make a call to a laravel route using the url generated by api gateway, laravel redirects the request to '/home' path. However, when I test it on ec2 instance using "node debug" , it works like a charm. Below are the details of the steps I followed.

I followed a fantastic blog written by Chris White for hosting a laravel application on aws lambda.

Steps:

  1. Generating a PHP CGI Binary

    I used "amzn-ami-hvm-2016.03.3.x86_64-gp2" ec2 instance to build my php-cgi binary file

./configure --prefix=/tmp/php-7.0.11/compiled/ --without-pear --enable-shared=no --enable-static=yes --enable-phar --enable-json --disable-all --with-openssl --with-curl --enable-libxml --enable-simplexml --enable-xml --with-mhash --with-gd --enable-exif --with-freetype-dir --enable-mbstring --enable-sockets --enable-pdo --with-pdo-mysql --enable-tokenizer --enable-session --enable-filter

  1. NodeJS Lambda function to spawn PHP CGI process - php.js file

process.env['PATH'] = process.env['PATH'] + ':' + process.env['LAMBDA_TASK_ROOT'];

var parser = require('http-string-parser');
var spawn = require('child_process').spawn;
exports.handler = function(event, context) {

  var requestMethod = event.httpMethod || 'GET';
  var serverName = event.headers ? event.headers.Host : '';
  var requestUri = event.path || '';
  var headers = {};

  if (event.headers) {
    Object.keys(event.headers).map(function(key) {
      headers['HTTP_' + key.toUpperCase()] = event.headers[key];
    });
  }

  var request_env = Object.assign({
    REDIRECT_STATUS: 1,
    REQUEST_METHOD: requestMethod,
    SCRIPT_FILENAME: 'api/public/index.php',
    SCRIPT_NAME: '/index.php',
    PATH_INFO: '/',
    SERVER_NAME: serverName,
    SERVER_PROTOCOL: 'HTTP/1.1',
    REQUEST_URI: requestUri
  }, headers);

  var php = spawn('./php-cgi', ['api/public/index.php'], {
    env: request_env
  });

  var response = '';

  php.stdout.on('data', function(data) {
    response += data.toString('utf-8');
  });

  php.stderr.on('data', function(data) {
    console.log("STDERR: " + data.toString());
  });

  php.on('close', function(code) {

    var parsedResponse = parser.parseResponse(response);
    context.succeed({
      isBase64Encoded: false,
      statusCode: parsedResponse.statusCode || 200,
      headers: parsedResponse.headers,
      body: parsedResponse.body
    });

  });

}

  1. Prepare AWS Lambda bundle

    The directory structure of my HelloLambda.zip bundle is

├── api

├── node_modules

├── php-cgi

└── php.js

The api folder consists of my laravel application.

  1. API Gateway - I created a api gateway for my HelloLambda function. The api has league & channel as path parameters. The GET method uses lambda proxy integration. The api shows following url in stages view

https://***.execute-api.us-east-1.amazonaws.com/prod/HelloLambda/espnheadlinesimage/{league}/{channel}

api-gateway-screenshot.jpg

  1. Make a GET request to api providing the league and channel parameter.

https://***.execute-api.us-east-1.amazonaws.com/prod/HelloLambda/espnheadlinesimage/nhl/28

When I make this get request, the browser shows a message

Redirecting to http://***.execute-api.us-east-1.amazonaws.com/home

My laravel routes.php file consists of below route

Route::get('espnheadlinesimage/{league}/{channel}', 'EspnController@headlinesimage');

Any help would be highly appreciated. Thanks in advance.


Here's the console output of content of my event object in my test API call

{
    "resource": "/HelloLambda/espnheadlinesimage/{league}/{channel}",
    "path": "/HelloLambda/espnheadlinesimage/nhl/48",
    "httpMethod": "GET",
    "headers": {
        "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8",
        "Accept-Encoding": "gzip, deflate, sdch, br",
        "Accept-Language": "en-GB,en;q=0.8,en-US;q=0.6,hi;q=0.4",
        "CloudFront-Forwarded-Proto": "https",
        "CloudFront-Is-Desktop-Viewer": "true",
        "CloudFront-Is-Mobile-Viewer": "false",
        "CloudFront-Is-SmartTV-Viewer": "false",
        "CloudFront-Is-Tablet-Viewer": "false",
        "CloudFront-Viewer-Country": "IN",
        "Host": "x7pdbfnzsg.execute-api.us-east-1.amazonaws.com",
        "upgrade-insecure-requests": "1",
        "User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36",
        "Via": "2.0 0e9493f2bcf9035541b227fce2ae5798.cloudfront.net (CloudFront)",
        "X-Amz-Cf-Id": "93vabUcIQzqON2X5ive3a0nHmqcO47wFzNEBR0SMs39Wo1qlNK9bIA==",
        "X-Amzn-Trace-Id": "Root=1-592e3ff4-132417a71f64bb62205997f7",
        "X-Forwarded-For": "103.243.10.67, 54.182.231.71",
        "X-Forwarded-Port": "443",
        "X-Forwarded-Proto": "https"
    },
    "queryStringParameters": null,
    "pathParameters": {
        "channel": "48",
        "league": "nhl"
    },
    "stageVariables": null,
    "requestContext": {
        "path": "/prod/HelloLambda/espnheadlinesimage/nhl/48",
        "accountId": "729779362209",
        "resourceId": "kbrsfu",
        "stage": "prod",
        "requestId": "bd922c44-45b5-11e7-81ca-777f94f39a98",
        "identity": {
            "cognitoIdentityPoolId": null,
            "accountId": null,
            "cognitoIdentityId": null,
            "caller": null,
            "apiKey": "",
            "sourceIp": "103.243.10.67",
            "accessKey": null,
            "cognitoAuthenticationType": null,
            "cognitoAuthenticationProvider": null,
            "userArn": null,
            "userAgent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36",
            "user": null
        },
        "resourcePath": "/HelloLambda/espnheadlinesimage/{league}/{channel}",
        "httpMethod": "GET",
        "apiId": "x7pdbfnzsg"
    },
    "body": null,
    "isBase64Encoded": false
} 

Upvotes: 0

Views: 2621

Answers (2)

A. Tewatia
A. Tewatia

Reputation: 11

This issue is resolved as suggested by Jack.

The issue was that the API url being generated by API Gateway was

/HelloLambda/espnheadlinesimage/{league}/{channel}

However the route in my Laravel routes file was

/espnheadlinesimage/{league}/{channel}

My misconception was that the base url of for the lambda function is

https://***.execute-api.us-east-1.amazonaws.com/prod/HelloLambda/

and I should add route after this path to my laravel routes file, i.e.,

/espnheadlinesimage/{league}/{channel}

However, the path in my route file should include '/HelloLambda' ,i.e., it should be

/HelloLambda/espnheadlinesimage/{league}/{channel}

Upvotes: 1

jackko
jackko

Reputation: 7354

I don't really know anything about laravel but you have configured a route for espnheadlinesimage/.... but you are actually calling the route HelloLambda/espnheadlinesimage/{league}/{channel} via API GW. The value of requestUri (and event.path) in the Lambda function will be HelloLambda/espnheadlinesimage/nhl/28 in your test API call.

Upvotes: 1

Related Questions