Giter Site home page Giter Site logo

dherault / serverless-offline Goto Github PK

View Code? Open in Web Editor NEW
5.1K 63.0 791.0 53.06 MB

Emulate AWS λ and API Gateway locally when developing your Serverless project

License: MIT License

JavaScript 96.61% Python 0.87% Ruby 0.53% Shell 0.72% TypeScript 0.22% Makefile 0.07% Go 0.44% Groovy 0.16% Kotlin 0.15% Scala 0.18% Dockerfile 0.07%
serverless aws-lambda aws-apigateway

serverless-offline's People

Contributors

apancutt avatar bilal-s avatar bryantbiggs avatar bytekast avatar chardos avatar computerpunc avatar daniel-cottone avatar darthtrevino avatar dherault avatar dl748 avatar dnalborczyk avatar dorianmazur avatar dortega3000 avatar frozenbonito avatar frsechet avatar gertjvr avatar johncmckim avatar jormaechea avatar juanjodiaz avatar leonardoalifraco avatar medikoo avatar mikestaub avatar miltador avatar moroine avatar nicolasseiler avatar pgrzesik avatar qswinson avatar thisisnozaku avatar thomaschaaf avatar zoellner avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

serverless-offline's Issues

Problem with CORS support

I have a problem with CORS. I’ve got it as far as returning 200 from OPTIONS, but then get this in Chrome:

    XMLHttpRequest cannot load https://localhost.xxx.com:3000/accounts. 
    Response to preflight request doesn't pass access control check: 
    No 'Access-Control-Allow-Origin' header is present on the requested resource. 
    Origin 'https://localhost.xxx.com:3001' is therefore not allowed access.

Where xxx is my domain name for my SSL cert. Note that the ports are different on the origin and XMLHttpRequest, therefore, $.ajax adds 'Origin'. This seems to be the case even if I specify crossDomain: false.

I'm invoking serverless offline like this:

    sls offline start --corsAllowOrigin '*' --corsAllowHeaders 'x-amz-date,authorization,content-type,accepts' -H {path to my cert/key}

Charles Proxy gets this response:

    {
      "message": "CORS error: Some headers are not allowed"
    } 

Looking at the code, I suspect this is happening somewhere in hapi, which I have not used before. I installed node-debug, but didn't even hit a breakpoint in the handler.

Before I dig further into debugging, wonder if anyone else has run into this?

This is failing in Chrome Version 51.0.2704.63 (64-bit) on Mac, which is my main debug environment. It seems to work on Mac Firefox.

BTW, thanks for your quick response on my other issue, yesterday.

$util.escapeJavaScript inconsistency

When using $util.escapeJavaScript('Hello%0AWorld') in a template,
APIG parses: Hello↵World
Offline parses: Hello\nWorld

This is due to the Offline dependency js-string-escape that does not match APIG's $util.escapeJavaScript.

Will fix. Until then this does the trick: foo.replace(/\\n/g, '\n');

Overwriting Content-Type header in response not working

I'm serving web content (css, js) through my Lambda. For this I have defined a central endpoint that handles various different content types. The actual one is set dynamically in the response. Take this endpoint response as an example:

      "responses": {
        "404.*": {
          "statusCode": "404",
          "responseParameters": {},
          "responseModels": {},
          "responseTemplates": {
            "application/json": "#set($inputRoot = $input.path('$.errorMessage'))\n$inputRoot"
          }
        },
        "default": {
          "statusCode": "200",
          "responseParameters": {
            "method.response.header.Content-Type": "integration.response.body.contentType"
          },
          "responseModels": {},
          "responseTemplates": {
            "application/json": "#set($inputRoot = $input.path('$.content'))\n$inputRoot"
          }
        }
      }

The json response from my Lambda looks something like this:

{ "contentType": "text/css", "content": "h1 { ... }" }

The expected behavior is that the HTTP Content-Type header is set to text/css (as defined in the responseParameters section) and the response body to h1 { ... }. This works fine when deployed to AWS API Gateway. However, the serverless-offline-plugin doesn't seem to handle the responseParameters properly. Instead it always uses the default application/json; chartset=utf-8. If I set any other random header instead of Content-Type (e.g. X-Content-Type), it does contain the correct and expected value.

I'm using v2.3.0 of the plugin.

GET by id doesn't seem to work

Hi,

I try call follow API address http://localhost:3000/locations/1 but it seems offline plugin is not passing id param to the lambda handler.

s-functions.json

    {
      "path": "locations/{id}",
      "method": "GET",
      "type": "AWS",
      "authorizationType": "none",
      "apiKeyRequired": false,
      "requestParameters": {
        "integration.request.path.id": "method.request.path.id"
      },
      "requestTemplates": {
        "application/json": "{\"operation\":\"read\",\"id\":\"$input.params('id')\"}"
      },
      "responses": {
        "400": {
          "statusCode": "400"
        },
        "default": {
          "statusCode": "200",
          "responseParameters": {},
          "responseModels": {},
          "responseTemplates": {
            "application/json": ""
          }
        }
      }
    }

handler

function handler(event, context) {
    console.log('Received event:', JSON.stringify(event, null, 2));
}

output

 Received event: {
  "isOffline": true
}

Add CORs support

I'm using serverless-cors-plugin to add CORs support to my AAG endpoints, so that I can test/use my API in the browser and on hostnames/ports that differ from my API.

I am using swagger-ui to test the live endpoints, and would also like to use swagger-ui to do the same with my serverless-offline server, and, yet, I get the following error:

XMLHttpRequest cannot load http://localhost:3092/SomeEndpoint. Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:3091' is therefore not allowed access.

I noticed mention of setting response headers in the docs, and I am about to test this out now, but I worry that my efforts will affect my live deployments, so I am hesistant.

Either way, if CORs support could be added as a fundamental feature of this plugin, that would be really nice.

CORS OPTIONS preflight request does not have cors headers set

Ok, so what I posted here, is actually this:

If a CORS preflight request (OPTIONS) is sent to an endpoint, serverless-offline fails to set the appropriate CORS headers.

"Normal" GET request (CORS headers are present):

$ curl -H "Origin: http://localhost:2702" -H "Access-Control-Request-Method: GET" -H "Access-Control-Request-Headers: X-Requested-With" -X GET --verbose http://localhost:2703/Travellers/version
*   Trying ::1...
* connect to ::1 port 2703 failed: Connection refused
*   Trying 127.0.0.1...
* Connected to localhost (127.0.0.1) port 2703 (#0)
> GET /Travellers/version HTTP/1.1
> Host: localhost:2703
> User-Agent: curl/7.43.0
> Accept: */*
> Origin: http://localhost:2702
> Access-Control-Request-Method: GET
> Access-Control-Request-Headers: X-Requested-With
>
< HTTP/1.1 200 OK
< content-type: application/json;charset=UTF-8
< vary: origin
< access-control-allow-origin: http://localhost:2702
< access-control-allow-credentials: true
< access-control-expose-headers: WWW-Authenticate,Server-Authorization
< cache-control: no-cache
< content-length: 19
< Date: Wed, 29 Jun 2016 15:55:43 GMT
< Connection: keep-alive
<
* Connection #0 to host localhost left intact
{"version":"0.2.7"}

versus

CORS preflight OPTIONS request (CORS headers are not present):

$ curl -H "Origin: http://localhost:2702" -H "Access-Cod: GET" -H "Access-Control-Request-Headers: X-Requested-With" -X OPTIONS --verbose http://localhost:2703/Travellers/version
*   Trying ::1...
* connect to ::1 port 2703 failed: Connection refused
*   Trying 127.0.0.1...
* Connected to localhost (127.0.0.1) port 2703 (#0)
> OPTIONS /Travellers/version HTTP/1.1
> Host: localhost:2703
> User-Agent: curl/7.43.0
> Accept: */*
> Origin: http://localhost:2702
> Access-Control-Request-Method: GET
> Access-Control-Request-Headers: X-Requested-With
>
< HTTP/1.1 200 OK
< content-type: application/json; charset=utf-8
< cache-control: no-cache
< content-length: 54
< Date: Wed, 29 Jun 2016 15:56:44 GMT
< Connection: keep-alive
<
* Connection #0 to host localhost left intact
{"message":"CORS error: Some headers are not allowed"}

Thus, requests which require a CORS preflight will fail with something like this:

XMLHttpRequest cannot load http://localhost:2703/Travellers/version. Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:2702' is therefore not allowed access.

Cheers,
Chris

x-form-url-encoded body should not be parsed by offline server

I have an API Gateway endpoint that accepts form POST data (ie, w/ mime application/x-form-url-encoded). API Gateway will not parse this data, instead this has to be done in the lambda, so the event payload in AWS is a string.

The problem is that the Hapi server always parses this data into a JavaScript object. Which means my lambda code that works on AWS will not work through serverless offline.

I tried to find a way to get the raw request body through the Hapi server, but couldn't figure out how.

EDIT: Using serverless offline version 2.5.1 & serverless version 0.5.5.

Question - how can we use post method with this plugin

I can read this comment from author

When no Content-Type header is set on a request, API Gateway defaults to application/json, and so does the plugin. But if you send a application/x-www-form-urlencoded or a multipart/form-data body with a application/json (or no) Content-Type, API Gateway won't parse your data (you'll get the ugly raw as input) whereas the plugin will answer 400 (malformed JSON). Please consider explicitly setting your requests' Content-Type and using separates templates.

but don't know what i have to do.can you please explain.

my try

s-templates.json

{
  "apiGatewayRequestTemplate": {
    "application/json": {
      "test": "$input.params('test')"
    }
  }
}

part of s-function.json

"endpoints": [
    {
      "path": "user/login",
      "method": "POST",
      "type": "AWS",
      "authorizationType": "none",
      "authorizerFunction": false,
      "apiKeyRequired": false,
      "requestParameters": {},
      "requestTemplates": "$${apiGatewayRequestTemplate}",
      "responses": {
        "400": {
          "statusCode": "400"
        },
        "default": {
          "statusCode": "200",
          "responseParameters": {},
          "responseModels": {},
          "responseTemplates": {
            "application/json": ""
          }
        }
      }
    }
  ],

but issue like above

post_method

what i have to change to fix this issue ?

Content-type override

On non-GET and non-HEAD request (typically a POST), the content type for incoming requests is overridden to 'application/json'.
Will be fixed in v2.3.

Does not work with node v0.10.44

A pretty minor issue but on node 0.10.44 when running the sls offline start

/usr/local/lib/node_modules/serverless/bin/serverless:5
let argv   = require('minimist')(process.argv.slice(2));
^^^
SyntaxError: Unexpected strict mode reserved word

Why even, do you ask?
Because Lambda only supports node 0.10.x

I was trying to be diligent and develop against the target platform.

Set env var when Offline

Hi there,

Lambda best practices suggest setting up database connections (in my case, DynamoDB Local) outside of the event handler. I noticed that isOffline is appended to the event object, but we have no other way to determine if we're running offline before that.

My suggestion would be to set a process.env.IS_OFFLINE or similar within the server code, so we can check for it within init code, before calling the handler.

Problem is, I have no idea where in src/index.js this would go. I'll take a look and open a PR, but I wanted your opinion first.

Doesn't seem to support the MOCK endpoint type (for CORS)

The MOCK endpoint type would be super helpful, enabling us to implement the CORS preflight OPTIONS endpoint without invoking the handler.

Examples:

Note that for our current use case, we only need CORS for offline.

Finally, I'm new to serverless, so I could be missing something important and/or obvious...

Array in $input.json('$.value') expanded as double array

Hi. I'm testing with a simple template like this:

  "requestTemplates": {
    "application/json": "{\"value\":$input.json('$.value')}"
  },

It expands as expected with a string value:

curl -H 'Content-Type: application/json' -d '{"value":"hello"}' 'http://localhost:3000/echo'
{"value":"hello"}

However, with an array value, the array is expanded as a double array:

curl -H 'Content-Type: application/json' -d '{"value":["hello"]}' 'http://localhost:3000/echo'
{"value":[["hello"]]}

The problem seems to trace to this line in jsonPath.js:

const result = JSONPath({ json, path, wrap: false });

When I modify it like this, expansion works properly also for array values:

const result = JSONPath({ json, path, wrap: true })[0];

Could it be changed in the official version without breaking anything?

support for scheduled events

is there a way to get scheduled events supported?
ie;=:
"events": [
{
"name": "schedule",
"type": "schedule",
"config": {
"schedule": "rate(5 minutes)"
}
}
]

Ability to run lambda functions offline "locally"

Sorry for empty post in your emails, ill edit this now.

is there a way to use lambda functions that are not deployed, via invoke in serverless offline mode?

eg .then(() => invoke('timeout', {user, delay: 70})), would execute the lambda function. But it would call it in AWS and not try running it in offline mode.

like theres a command to run sls function run timeout that runs the function locally
so could this be abstracted to be used inside the code so that when you run serverless offline it would run the functions called in the code locally.

Not able to specify timeout with a template value

While this work for deploys this does not work for local dev

// s-function.json
{
  "name": "parts-read",
  "runtime": "nodejs4.3",
  "description": "",
  "customName": false,
  "customRole": false,
  "handler": "handler.handler",
  "timeout": "$${defaultTimeout}",
  "memorySize": "$${defaultMb}",
  "authorizer": {},
  "custom": {
    "excludePatterns": []
  },
  "endpoints": [/*...*/],
  "events": [],
  "environment": "$${envVars}",
  "vpc": {
    "securityGroupIds": [],
    "subnetIds": []
  }
}
// s-templates.json
{
  "apiRequestTemplate": {
    "application/json": {
      "httpMethod": "$context.httpMethod",
      "body": "$input.json('$')",
      "queryParams": "$input.params().querystring",
      "headerParams": "$input.params().header",
      "headerParamNames": "$input.params().header.keySet()",
      "contentTypeValue": "$input.params().header.get('Content-Type')"
    }
  },
  "defaultMb": 128,
  "defaultTimeout": 6,
  "envVars": {
    "DATABASE_URL": "${dbConnectionString}",
    "MANDRILL_API_KEY": "${mandrillApiKey}",
    "SERVERLESS_PROJECT": "${project}",
    "SERVERLESS_STAGE": "${stage}",
    "SERVERLESS_REGION": "${region}"
  }
}

JSON using VTL different between serverless on API Gateway vs offline

I am using this construct in my s-templates.json as part of my requestParameters:

    "params": "{#foreach($param in $input.params().path.keySet())\"$param\": \"$util.escapeJavaScript($input.params().path.get($param))\" #if($foreach.hasNext),#end#end}",

When I call my API from API Gateway, my Lambda receives the params as a string, and I have to call JSON.parse on the string.

When I call my API from serverless-offline, my Lambda receives the params as an object (which I actually prefer).

Would be great if both returned the same response, which I guess means offline should match API Gateway/Lambda.

optionally disable timeout

I have a use case for there being an optionally to disable or lengthen the timeout when running offline.

Specifically I have function that has to load a sizeable file from s3 to process requests. This of course takes very little time from lambda but can easily timeout locally. I can of course adjust the config for when I'm running it locally but this isn't really a good solution.

I think the ideal would be to be able to run the server with a command line option to set the timeout to another length or 0 for infinite.

environment variables aren't set

Hi again,

I noticed that when running with serverless-offline none of the in s-function.json specified environment variables like SERVERLESS_STAGE or SERVERLESS_REGION are popuplated. Is this on purpose? Is there a way to have them populated? In some functions I'm kind of relying on the stage to determine NODE_ENV and would really appreciate having this available while in serverless-offline as well :)

Thanks,
Chris

eslint support, and watch files

It would be good to have the option to parse the code through eslint when starting the offline command, and show the lint warnings/errors as you save the files (watch).

responseParameters support

Would like support for responseParameters.

Not sure if the example below is valid but would like to dynamically load responses to the header, such as location for a newly created item.

"responses": {
   "default": {
      "statusCode": "201",
      "responseParameters": {
         "method.response.header.Location": "integration.response.body.location"
      },
      "responseModels": {},
      "responseTemplates": {
         "application/json": "$input.path('$.body')"
      }
   }
}

Error - internal, implementation, error

Debug: internal, implementation, error
    TypeError: response.send is not a function
  at Offline._reply500 (E:\wamp\www\project\node_modules\serverless-offline\src\index.js:470:16)
  at server.route.handler.Object.keys.forEach.createLambdaContext (E:\wamp\www\project\node_modules\serverless-offline\src\index.js:444:29)
  at Object.exports.execute.internals.prerequisites.internals.handler.callback [as handler] (E:\wamp\www\project\node_modules\serverless-offline\node_modules\hapi\lib\handler.js:96:36)
  at E:\wamp\www\project\node_modules\serverless-offline\node_modules\hapi\lib\handler.js:30:23
  at [object Object].internals.Protect.run.finish [as run] (E:\wamp\www\project\node_modules\serverless-offline\node_modules\hapi\lib\protect.js:64:5)
  at exports.execute.finalize (E:\wamp\www\project\node_modules\serverless-offline\node_modules\hapi\lib\handler.js:24:22)
  at each (E:\wamp\www\project\node_modules\serverless-offline\node_modules\hapi\lib\request.js:383:16)
  at iterate (E:\wamp\www\project\node_modules\serverless-offline\node_modules\hapi\node_modules\items\lib\index.js:36:13)
  at done (E:\wamp\www\project\node_modules\serverless-offline\node_modules\hapi\node_modules\items\lib\index.js:28:25)
  at [object Object].internals.Auth.test.internals.Auth._authenticate (E:\wamp\www\project\node_modules\serverless-offline\node_modules\hapi\lib\auth.js:210:16)
  at internals.Auth.test.internals.Auth.authenticate (E:\wamp\www\project\node_modules\serverless-offline\node_modules\hapi\lib\auth.js:202:17)
  at each (E:\wamp\www\project\node_modules\serverless-offline\node_modules\hapi\lib\request.js:383:16)
  at iterate (E:\wamp\www\project\node_modules\serverless-offline\node_modules\hapi\node_modules\items\lib\index.js:36:13)
  at done (E:\wamp\www\project\node_modules\serverless-offline\node_modules\hapi\node_modules\items\lib\index.js:28:25)
  at internals.state.next (E:\wamp\www\project\node_modules\serverless-offline\node_modules\hapi\lib\route.js:350:16)
  at each (E:\wamp\www\project\node_modules\serverless-offline\node_modules\hapi\lib\request.js:383:16)
  at iterate (E:\wamp\www\project\node_modules\serverless-offline\node_modules\hapi\node_modules\items\lib\index.js:36:13)
  at Object.exports.serial (E:\wamp\www\project\node_modules\serverless-offline\node_modules\hapi\node_modules\items\lib\index.js:39:9)
  at [object Object].internals.Request.internals.Request._execute.internals.Request._lifecycle.each [as _lifecycle] (E:\wamp\www\project\node_modules\serverless-offline\node_modules\hapi\lib\request.js:386:11)
  at [object Object].internals.Request.internals.Request._execute (E:\wamp\www\project\node_modules\serverless-offline\node_modules\hapi\lib\request.js:301:21)
  at Domain.<anonymous> (E:\wamp\www\project\node_modules\serverless-offline\node_modules\hapi\lib\connection.js:244:25)
  at Domain.run (domain.js:228:14)
  at [object Object].internals.Protect.run.internals.Protect.enter (E:\wamp\www\project\node_modules\serverless-offline\node_modules\hapi\lib\protect.js:80:17)
  at Server.<anonymous> (E:\wamp\www\project\node_modules\serverless-offline\node_modules\hapi\lib\connection.js:242:30)
  at emitTwo (events.js:87:13)
  at Server.emit (events.js:172:7)
  at HTTPParser.parserOnIncoming [as onIncoming] (_http_server.js:528:12)
  at HTTPParser.parserOnHeadersComplete (_http_common.js:88:23)

can you please explain why i am getting this error,is this bug or i have issue with my code

i love your work :)

Debuggers support

The --debugOffline flag seems to only print some debug info to console. I would expect that to also send the --debug flag to the node process, so it exposes the debugger listening in the default port (5858), or setting --debug=PORT, to use a custom port, just as it happens with the node command. This way we could use any debugging tool to attach to that port and debug line by line from our code editor.

Custom Authorizer HowTo

Hi there,

I'm using a custom authorizer and it works great when deployed to lambda and API Gateway, but serverless-offline never invokes my authorizer. So, my question is whether there is more configuration work to be done on my part or whether you could provide a simple walk-through of how to make serverless-offline respect a custom authorizer :)

Thanks a lot,
Chris

Uncaught error: Cannot set property 'isOffline' of null if payload is empty

Hello there,

I just discovered that if you fire a POST request with no payload at all it will throw the following error:

Serverless: POST /Invite (λ: Invite-post)
Debug: internal, implementation, error
    TypeError: Uncaught error: Cannot set property 'isOffline' of null
  at server.route.handler.error (/Users/cspeer/Development/Atameo/api/node_modules/serverless-offline/src/index.js:389:31)
  at Object.internals.handler (/Users/cspeer/Development/Atameo/api/node_modules/hapi/lib/handler.js:96:36)
  at request._protect.run (/Users/cspeer/Development/Atameo/api/node_modules/hapi/lib/handler.js:30:23)
  at internals.Protect.run (/Users/cspeer/Development/Atameo/api/node_modules/hapi/lib/protect.js:64:5)
  at exports.execute (/Users/cspeer/Development/Atameo/api/node_modules/hapi/lib/handler.js:24:22)
  at each (/Users/cspeer/Development/Atameo/api/node_modules/hapi/lib/request.js:383:16)
  at iterate (/Users/cspeer/Development/Atameo/api/node_modules/hapi/node_modules/items/lib/index.js:36:13)
  at done (/Users/cspeer/Development/Atameo/api/node_modules/hapi/node_modules/items/lib/index.js:28:25)
  at internals.Auth.payload (/Users/cspeer/Development/Atameo/api/node_modules/hapi/lib/auth.js:223:16)
  at each (/Users/cspeer/Development/Atameo/api/node_modules/hapi/lib/request.js:383:16)
  at iterate (/Users/cspeer/Development/Atameo/api/node_modules/hapi/node_modules/items/lib/index.js:36:13)
  at done (/Users/cspeer/Development/Atameo/api/node_modules/hapi/node_modules/items/lib/index.js:28:25)
  at onParsed (/Users/cspeer/Development/Atameo/api/node_modules/hapi/lib/route.js:395:20)
  at Subtext.parse (/Users/cspeer/Development/Atameo/api/node_modules/hapi/lib/route.js:416:20)
  at next (/Users/cspeer/Development/Atameo/api/node_modules/hapi/node_modules/subtext/lib/index.js:43:16)
  at internals.object (/Users/cspeer/Development/Atameo/api/node_modules/hapi/node_modules/subtext/lib/index.js:164:20)
  at Object.internals.jsonParse (/Users/cspeer/Development/Atameo/api/node_modules/hapi/node_modules/subtext/lib/index.js:270:16)
  at Object.internals.object (/Users/cspeer/Development/Atameo/api/node_modules/hapi/node_modules/subtext/lib/index.js:254:26)
  at Wreck.read (/Users/cspeer/Development/Atameo/api/node_modules/hapi/node_modules/subtext/lib/index.js:156:19)
  at finish (/Users/cspeer/Development/Atameo/api/node_modules/hapi/node_modules/subtext/node_modules/wreck/lib/index.js:299:20)
  at wrapped (/Users/cspeer/Development/Atameo/api/node_modules/hapi/node_modules/hoek/lib/index.js:867:20)
  at onReaderFinish (/Users/cspeer/Development/Atameo/api/node_modules/hapi/node_modules/subtext/node_modules/wreck/lib/index.js:370:16)
  at g (events.js:286:16)
  at emitNone (events.js:91:20)
  at emit (events.js:185:7)
  at finishMaybe (_stream_writable.js:488:14)
  at endWritable (_stream_writable.js:498:3)
  at Writable.end (_stream_writable.js:463:5)
  at IncomingMessage.onend (_stream_readable.js:517:10)
  at IncomingMessage.g (events.js:286:16)
  at emitNone (events.js:91:20)
  at IncomingMessage.emit (events.js:185:7)
  at endReadableNT (_stream_readable.js:926:12)
  at _combinedTickCallback (internal/process/next_tick.js:74:11)
  at process._tickDomainCallback (internal/process/next_tick.js:122:9)

If you however supply a payload as simple as {} everything is fine!
Thanks for this awesome plugin!

Cheers,
Chris

Request template not parsed/rendered correctly

First of all, thanks a lot for this plugin! It's an awesome time saver and makes development and debugging so much easier!

I am however having some issues with the request templates, which I hope you can help with.

The template I am using is very basic:

{
  "apiRequestTemplate": {
    "application/json": {
      "httpMethod": "$context.httpMethod",
      "body": "$input.json('$')",
      "queryParams": "$input.params().querystring",
      "headerParams": "$input.params().header",
      "headerParamNames": "$input.params().header.keySet()",
      "contentTypeValue": "$input.params().header.get('Content-Type')"
    }
  }
}

So when I hit my endpoint with the query string "?first=12&other=34" I was expecting the "queryParams" property to give me an array or an object, but what I am getting is a string like this one: "{first=12, other=34}". This is obviously not valid json, so it doesn't get parsed once merged with the template

I'm new to all this, but while debugging, it looked like the velocity context did have an object as input, so something happened at rendering time.

The same thing happens for headerParams and headerParamNames.

If this help, I am using serverless-offline v2.3.2 on Windows

Thanks!

Bug in renderVelocityTemplateObject.js and quick fix

Hi,

I have follow request template which is not parsed properly by offline plugin:

{
  "requestTemplates": {
    "application/json": "{\n \"body\" : $input.json('$'),\n \"headers\": {\n #foreach($header in $input.params().header.keySet())\n \"$header\": \"$util.escapeJavaScript($input.params().header.get($header))\" #if($foreach.hasNext),#end\n \n #end\n },\n \"method\": \"$context.httpMethod\",\n \"params\": {\n #foreach($param in $input.params().path.keySet())\n \"$param\": \"$util.escapeJavaScript($input.params().path.get($param))\" #if($foreach.hasNext),#end\n \n #end\n },\n \"query\": {\n #foreach($queryParam in $input.params().querystring.keySet())\n \"$queryParam\": \"$util.escapeJavaScript($input.params().querystring.get($queryParam))\" #if($foreach.hasNext),#end\n \n #end\n } \n}"
  }
}

To fix the problem make change on code line 43 and add context parameter:

from:

const alternativeResult = tryToParseJSON(renderVelocityString(toProcess));

to:

const alternativeResult = tryToParseJSON(renderVelocityString(toProcess, context));

None of my JSON parameters come through in event object

I can't seem to figure out what is going on I have a simple Serverless function like:

var aws = require('aws-sdk');


exports.handler = function (event, context) {


      var tpl = event.tpl || "";

      var resp = {
        "status":   "success",
        "message": tpl
      }
      context.succeed(JSON.stringify(event));
};

and I'm using Postman to call it with this JSON:

{
"tpl" : "blog-template"
}

But the response I get back is missing the tpl param as this is all I get back:

{
  "isOffline": true
}

Does anyone have an idea what could be going on?

Babel runtime requires return Promise?

Hi guys, thanks again a great plugin, this is compulsory for development using Gateway & Lambda. Currently I'm having a function with babel runtime. However, I always get the following error when using context.done. This is really a show-stopper.
Serverless: Warning: context.done called twice within handler 'user_bookmark_create'!

My function is very simple though:

'use strict';

export default (event, context) => {
    setTimeout(function(){
        context.done(null, 'DONE');
    }, 2000);
};

It looks like we require a Promise to be returned from handler here:
From src\index.js:

// Promise support
                if (funRuntime === 'babel' && !this.requests[requestId].done) {
                  if (x && typeof x.then === 'function' && typeof x.catch === 'function') {
                    x.then(lambdaContext.succeed).catch(lambdaContext.fail);
                  }
                  else if (x instanceof Error) lambdaContext.fail(x);
                  else lambdaContext.succeed(x);
                }

The handler above is working perfectly with Lamdba.

So my questions is why do we require returning a promise if we use babel runtime?.

Looking at the code here:

// Promise support
                if (funRuntime === 'babel' && !this.requests[requestId].done) {
                  if (x && typeof x.then === 'function' && typeof x.catch === 'function') {
                    x.then(lambdaContext.succeed).catch(lambdaContext.fail);
                  }
                  else if (x instanceof Error) lambdaContext.fail(x);
                  else lambdaContext.succeed(x);
                }

Looks like the last else is causing problem, I think we shouldn't call lambdaContext.succeed(x); as the handler might be still working and going to execute context.done as my code above.

Thanks again!!! ( I'm more than happy to PR to fix this. )

Cannot read property 'serverlessPath' of undefined

For serverless v0.5

Added the plugin, then ran sls offline start and got this error.

C:\Users\Hyr\AppData\Roaming\npm\node_modules\serverless\node_modules\bluebird\js\release\async.js:49
        fn = function () { throw arg; };
                           ^

TypeError: Cannot read property 'serverlessPath' of undefined
  at module.exports.S.classes.Plugin._createRoutes.functions.forEach.fun.endpoints.forEach.ep.server.route (C:\Users\Hyr\Desktop\www\hyr\client-api\node_modules\serverless-offline\src\index.js:13:51)
  at Serverless._loadPlugins (C:\Users\Hyr\AppData\Roaming\npm\node_modules\serverless\lib\Serverless.js:284:25)
  at Serverless.loadProjectPlugins (C:\Users\Hyr\AppData\Roaming\npm\node_modules\serverless\lib\Serverless.js:253:12)
  at C:\Users\Hyr\AppData\Roaming\npm\node_modules\serverless\lib\Serverless.js:110:15
  at processImmediate [as _immediateCallback] (timers.js:383:17)
From previous event:
  at Serverless.init (C:\Users\Hyr\AppData\Roaming\npm\node_modules\serverless\lib\Serverless.js:105:8)
  at Object.<anonymous> (C:\Users\Hyr\AppData\Roaming\npm\node_modules\serverless\bin\serverless:17:12)
  at Module._compile (module.js:413:34)
  at Object.Module._extensions..js (module.js:422:10)
  at Module.load (module.js:357:32)
  at Function.Module._load (module.js:314:12)
  at Function.Module.runMain (module.js:447:10)
  at startup (node.js:141:18)
  at node.js:933:3

authorizer function support

It would be great to add support for customer authorizer functions so I can simulate authorization/authentication locally.

Does not work with POST?

I tried to access data in event object but it's undefined.
Thanks for creating this awesome plugin 👍

Pass METHOD and PATH to event

In the serverless docs, there is a part about how to structure your endpoints and functions to consolidate the code. It mentions that API Gateway can pass the METHOD and PATH of the endpoint to the lambda event. Those can then be used to route the request to a specific chunk of code instead of having multiple lambdas. It would be nice if this plugin could do that too.
Thanks

Problem with parsing requestTemplate

It seems that serverless-offline is not correctly handling my request template.

In my s-function.json, I have the following:

"requestParameters": {
    "integration.request.path.id": "method.request.path.id"
},
"requestTemplates": {
    "application/json": "{\"id\":\"$input.params('id')\"}"
},

But the end result is the handler is receiving a crazy object:

{ '0': undefined,
  '1': undefined,
  '2': undefined,
  '3': undefined,
  '4': undefined,
  '5': undefined,
  '6': undefined,
  '7': undefined,
  '8': undefined,
  '9': undefined,
  '10': undefined,
  '11': undefined,
  '12': undefined,
  '13': undefined,
  '14': undefined,
  '15': undefined,
  '16': undefined,
  '17': undefined,
  '18': undefined,
  '19': undefined,
  '20': undefined,
  '21': undefined,
  '22': undefined,
  '23': undefined,
  '24': undefined,
  '25': undefined,
  '26': undefined,
  '27': undefined,
  bold: undefined,
  to: [Function],
  toEnd: [Function],
  underline: undefined,
  strikethrough: undefined,
  italic: undefined,
  inverse: undefined,
  grey: undefined,
  black: undefined,
  yellow: undefined,
  red: undefined,
  green: undefined,
  blue: undefined,
  white: undefined,
  cyan: undefined,
  magenta: undefined,
  greyBG: undefined,
  blackBG: undefined,
  yellowBG: undefined,
  redBG: undefined,
  greenBG: undefined,
  blueBG: undefined,
  whiteBG: undefined,
  cyanBG: undefined,
  magentaBG: undefined,
  rainbow: undefined,
  zebra: undefined,
  stripColors: undefined,
  zalgo: undefined,
  isOffline: true }

Trying to debug it, it looks like the issue is within renderVelocityTemplateObject.js as the templateObject parameter passed in is actually a string, so the following line iterates over every character:

for (let key in templateObject) {

Am I doing something wrong or is this an issue in serverless-offline?

Thanks!

Does not work given serverless getting started doc

When using "sls function create", the s-function.json created contains this fragment:

  "endpoints": [
    {
      "path": "ivgen2",
      "method": "POST",  // <--- I CHANGED THIS TO SUITE MY FUNCTION
      "type": "AWS",
      "authorizationType": "none",
      "authorizerFunction": false,
      "apiKeyRequired": false,
      "requestParameters": {},
      "requestTemplates": {
        "application/json": ""
      },
      "responses": "$${apiGatewayResponseTemplate}"  // <-- THIS TOO
    }
  ],

In particular, "requestTemplates" has a template for "application/json" which is set to "". This seems fine for AWS. But not for offline ...

In index.js we have:

              let event = {};

              if (requestTemplate) {
                try {
                  debugLog('_____ REQUEST TEMPLATE PROCESSING _____');
                  // Velocity templating language parsing
                  const velocityContext = createVelocityContext(request, this.velocityContextOptions, request.payload || {});
                  event = renderVelocityTemplateObject(requestTemplate, velocityContext);
                } catch (err) {
                  return this._reply500(response, `Error while parsing template "${contentType}" for ${funName}`, err, requestId);
                }
              }

              event.isOffline = true;
              debugLog('event:', event);

In this case, requestTemplate is "", which resolves to false (node 4.4.4), and the if block is not executed, leaving event equal to { isOffline: true } and nothing else! Here is the offline debug for my case:

[debug] requestId: 7351255607791245
[debug] contentType: application/json
[debug] requestTemplate: 
[debug] payload: { code: 'BadRequest', message: 'oops' }
[debug] Invalidating cache...
[debug] Loading handler... (/Users/peebles/serverless/functions/ivgen2/handler)
[debug] event: { isOffline: true }

See how the "payload" is ignored, not passed into "event". My function then does not see my payload.

If requestTemplate is not defined, or if it is set to "" (as sls seems to do when creating a new function), then a POST will never see the payload.

In case you are wondering, this is how I called my function:

$ curl -v -X POST -H "Content-Type: application/json" --data '{"code":"BadRequest","message": "oops"}' http://localhost:3000/ivgen2

Serverless v0.5.0 env breaking changes

The Serverless has released v0.5.0 with env breaking changes and dropped serverless-helpers-js module so my question is if the offline plugin should be responsible to load these env variables from s-function.json as I tried run my app but it doesn't seem the env variables are passed.

s-function.json

  "environment": {
    "SERVERLESS_PROJECT": "${project}",
    "SERVERLESS_STAGE": "${stage}",
    "SERVERLESS_REGION": "${region}"
  }

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.