juanjodiaz / serverless-middleware Goto Github PK
View Code? Open in Web Editor NEWServerless plugin to allow middleware handlers configured directly in serverless.yaml
License: MIT License
Serverless plugin to allow middleware handlers configured directly in serverless.yaml
License: MIT License
we're on Serverless 2.5 and trying to configure the middleware plugin.
here is the test configuration
custom:
middleware:
pre:
- api/helpers/version-manager-2.checkVersion
functions:
test-middleware:
handler: api/http/discover/testmw.handler
description: GET test-middleware
events:
- http:
path: test-middleware
method: get
and it works fine when we call a function like this:
serverless invoke local --function test-middleware
but when we're trying to start sls offline
and call the same function using postman GET http://localhost:3000/test-middleware
the middleware function is not being called.
what are we doing wrong?
When using serverless-middleware Im getting this error when i want to start serverless offline
No matching handler found for 'src/middlewares/verifyToken.verifyToken,src/functions/resetPassword/resetPassword'
Here is how i have it setup at the moment:
serverless.yml:
service: app
# Create an optimized package for our functions
package:
individually: true
plugins:
- serverless-webpack # Package our functions with Webpack
- serverless-middleware
- serverless-offline
- serverless-dotenv-plugin # Load .env as environment variables
provider:
name: aws
runtime: nodejs12.x
stage: dev
region: eu-west-1
functions:
resetPassword: ${file(src/functions/resetPassword/resetPassword.yml):resetPassword}
resetPassword.yml
resetPassword:
handler:
- src/middlewares/verifyToken.verifyToken
- src/functions/resetPassword/resetPassword.resetExport
events:
- http:
path: resetPassword
method: put
- schedule:
rate: rate(5 minutes)
enabled: true
verifyToken.ts
const verifyToken = async (event, context) => {
// my logic here
};
export { verifyToken };
resetPassword.ts
const resetPassword = async (event) => {
// after middleware logic here
};
const resetExport = runWarm(resetPassword);
export { resetExport };
When i leave only one handler the error does not appear, however then i cannot use the middleware as described in the docs.
Serverless-offilne version: 6.8.0
Serverless-middleware version: 0.0.10
Node version: 14.0.0
P.S: When i try to do it with the then: keyword like this:
resetPassword:
handler:
- src/middlewares/verifyToken.verifyToken
- then: src/functions/resetPassword/resetPassword.resetExport
events:
- http:
path: resetPassword
method: put
- schedule:
rate: rate(5 minutes)
enabled: true
I'm getting this error:
TypeError: handler.substr is not a function
I have started the application locally and in a function getUser i want to add a middleware and i have added it like shown below
getUsers:
handler: ORM.lambdas.createUser.getUsers
events:
- http:
path: /getUser/{id}
method: get
cors: true
middleware:
pre:
- ORM.lambdas.createUser.middleware2
"ORM.lambdas.createUser.middleware2" this is the path of the middleware function
but middleware does not get invoked
here is the whole yml file
org: sardik
app: serverless-auth-mongo
service: Auth-MongoDB
frameworkVersion: '3'
plugins:
- serverless-python-requirements
- serverless-offline
- serverless-middleware
custom:
pythonRequirements:
dockerizePip: false
serverless-offline:
httpPort: 4000
middleware:
pre:
- ORM.lambdas.createUser.middleware2
provider:
name: aws
runtime: python3.9
environment:
JWT_ALGORITHM: 'HS256'
JWT_SECRET: 'secret'
functions:
hello:
handler: handler.hello
events:
- httpApi:
path: /
method: get
createUser:
handler: ORM.lambdas.createUser.createUser
events:
- http:
path: /createUser
method: post
cors: true
login:
handler: ORM.lambdas.createUser.login
events:
- http:
path: /login
method: post
cors: true
getUsers:
handler: ORM.lambdas.createUser.getUsers
events:
- http:
path: /getUser/{id}
method: get
cors: true
middleware:
pre:
- ORM.lambdas.createUser.middleware2
updateUsers:
handler: ORM.lambdas.createUser.updateUsers
events:
- http:
path: /updateUser/{id}
method: put
cors: true
deleteUsers:
handler: ORM.lambdas.createUser.deleteUsers
events:
- http:
path: /deleteUsers/{id}
method: delete
cors: true
serverless middleware version => ^3.1.0
Serverless says handler should be a string. So does this mean that this middleware might not work with upcoming versions ?
Serverless: Configuration warning at 'functions.home_get.handler': should be string
Serverless:
Serverless: Learn more about configuration validation here: http://slss.io/configuration-validation
Serverless:
Serverless: Deprecation warning: Starting with next major, Serverless will throw on configuration errors by default. Adapt to this behavior now by adding "configValidationMode: error" to service configuration
More Info: https://www.serverless.com/framework/docs/deprecations/#CONFIG_VALIDATION_MODE_DEFAULT
Hi, I've spotted that the serverless-plugin-warmup plugin stopped working after I've installed serverless-middleware and configured a global 'pre' function.
the idea was to extract the warmup check into a global middleware 'pre' function like this:
// ./utils/warmup.js
exports.handler = async (event) => {
if (event.source === 'serverless-plugin-warmup') {
console.log(`Keeping lambda warm`);
await new Promise(r => setTimeout(r, 25));
throw new Error("WarmupOK"); // this is to stop the rest of the function from executing
}
}
then I configured serverless.yml like this:
plugins:
- serverless-offline
- serverless-plugin-warmup
- serverless-middleware
custom:
warmup:
officeHours:
enabled: false
events:
- schedule: cron(0/3 3-18 ? * MON-FRI *)
middleware:
pre:
- api/utils/warmup.handler
functions:
callback:
handler: api/http/callback.handler
warmup:
officeHours:
enabled: false
events:
- http:
path: callback
method: get
after deploy I have the warmup lambda function created, but it looks like the warmup function was wrapped up by the middleware plugin and in the lambda runtime settings I have HandlerInfo
set to .middleware/influencer-index-api-staging-warmup-plugin-officeHours.handler
whereas normally it would be set to .warmup/officeHours/index.warmUp
therefore I now have the next error in the warmup lambda logs:
{
"errorType": "Runtime.ImportModuleError",
"errorMessage": "Error: Cannot find module 'api-staging-warmup-plugin-officeHours'\nRequire stack:\n- /var/runtime/UserFunction.js\n- /var/runtime/index.js",
"stack": [
"Runtime.ImportModuleError: Error: Cannot find module 'api-staging-warmup-plugin-officeHours'",
"Require stack:",
"- /var/runtime/UserFunction.js",
"- /var/runtime/index.js",
" at _loadUserApp (/var/runtime/UserFunction.js:100:13)",
" at Object.module.exports.load (/var/runtime/UserFunction.js:140:17)",
" at Object.<anonymous> (/var/runtime/index.js:43:30)",
" at Module._compile (internal/modules/cjs/loader.js:1072:14)",
" at Object.Module._extensions..js (internal/modules/cjs/loader.js:1101:10)",
" at Module.load (internal/modules/cjs/loader.js:937:32)",
" at Function.Module._load (internal/modules/cjs/loader.js:778:12)",
" at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:76:12)",
" at internal/main/run_main_module.js:17:47"
]
}
is there anything I can do to make it work?
p.s. sorry for duplicating this issue here, just wasn't sure where this should be reported...
We are using non-async handlers with a callback function. Not a fan of it, but it's what I've been given. Anyways, it seems the handler is only sending back event and context and not the callback so the callback keeps getting the error done is not a function
. Done being our callback name.
Thanks for all the work you do on this! Would it be possible to add Node 15 runtime support to this plugin?
Every time that i run serverless offline, the webpack creates a folder .webpack in root and i get this is error:
"Error: Cannot find module 'c:\\Users\\xpto\\Desktop\\PQM\\aurora-serverless-api\\.webpack\\service\\.middleware\\proxy'",
"Require stack:",
"- c:\\Users\\sbtrry\\Desktop\\PQM\\aurora-serverless-api\\node_modules\\serverless-offline\\src\\functionHelper.js",
"- c:\\Users\\sbtrry\\Desktop\\PQM\\aurora-serverless-api\\node_modules\\serverless-offline\\src\\createAuthScheme.js",
"- c:\\Users\\sbtrry\\Desktop\\PQM\\aurora-serverless-api\\node_modules\\serverless-offline\\src\\index.js",
"- c:\\Users\\sbtrry\\Desktop\\PQM\\aurora-serverless-api\\node_modules\\serverless\\lib\\classes\\PluginManager.js",
"- c:\\Users\\sbtrry\\Desktop\\PQM\\aurora-serverless-api\\node_modules\\serverless\\lib\\Serverless.js",
"- c:\\Users\\sbtrry\\Desktop\\PQM\\aurora-serverless-api\\node_modules\\serverless\\lib\\utils\\autocomplete.js",
"- c:\\Users\\sbtrry\\Desktop\\PQM\\aurora-serverless-api\\node_modules\\serverless\\bin\\serverless.js",
"- c:\\Users\\sbtrry\\Desktop\\PQM\\aurora-serverless-api\\node_modules\\serverless\\bin\\serverless",
"at Function.Module._resolveFilename (internal/modules/cjs/loader.js:794:15)",
"at Function.Module._load (internal/modules/cjs/loader.js:687:27)",
"at Module.require (internal/modules/cjs/loader.js:849:19)",
"at require (internal/modules/cjs/helpers.js:74:18)",
"at Object.createHandler (c:\\Users\\sbtrry\\Desktop\\PQM\\aurora-serverless-api\\node_modules\\serverless-offline\\src\\functionHelper.js:192:17)",
"at handler (c:\\Users\\sbtrry\\Desktop\\PQM\\aurora-serverless-api\\node_modules\\serverless-offline\\src\\index.js:624:40)",
"at Object.internals.handler (c:\\Users\\sbtrry\\Desktop\\PQM\\aurora-serverless-api\\node_modules\\hapi\\lib\\handler.js:101:51)",
"at c:\\Users\\sbtrry\\Desktop\\PQM\\aurora-serverless-api\\node_modules\\hapi\\lib\\handler.js:32:23",
"at module.exports.internals.Protect.internals.Protect.run (c:\\Users\\sbtrry\\Desktop\\PQM\\aurora-serverless-api\\node_modules\\hapi\\lib\\protect.js:60:12)",
"at exports.execute (c:\\Users\\sbtrry\\Desktop\\PQM\\aurora-serverless-api\\node_modules\\hapi\\lib\\handler.js:26:22)",
"at each (c:\\Users\\sbtrry\\Desktop\\PQM\\aurora-serverless-api\\node_modules\\hapi\\lib\\request.js:401:16)",
"at iterate (c:\\Users\\sbtrry\\Desktop\\PQM\\aurora-serverless-api\\node_modules\\items\\lib\\index.js:36:13)",
"at done (c:\\Users\\sbtrry\\Desktop\\PQM\\aurora-serverless-api\\node_modules\\items\\lib\\index.js:28:25)",
"at internals.Auth.payload (c:\\Users\\sbtrry\\Desktop\\PQM\\aurora-serverless-api\\node_modules\\hapi\\lib\\auth.js:235:16)",
"at each (c:\\Users\\sbtrry\\Desktop\\PQM\\aurora-serverless-api\\node_modules\\hapi\\lib\\request.js:401:16)",
"at iterate (c:\\Users\\sbtrry\\Desktop\\PQM\\aurora-serverless-api\\node_modules\\items\\lib\\index.js:36:13)",
"at done (c:\\Users\\sbtrry\\Desktop\\PQM\\aurora-serverless-api\\node_modules\\items\\lib\\index.js:28:25)",
"at onParsed (c:\\Users\\sbtrry\\Desktop\\PQM\\aurora-serverless-api\\node_modules\\hapi\\lib\\route.js:341:20)",
"at c:\\Users\\sbtrry\\Desktop\\PQM\\aurora-serverless-api\\node_modules\\hapi\\lib\\route.js:380:20",
"at next (c:\\Users\\sbtrry\\Desktop\\PQM\\aurora-serverless-api\\node_modules\\subtext\\lib\\index.js:46:26)",
"at c:\\Users\\sbtrry\\Desktop\\PQM\\aurora-serverless-api\\node_modules\\subtext\\lib\\index.js:243:16",
"at finish (c:\\Users\\sbtrry\\Desktop\\PQM\\aurora-serverless-api\\node_modules\\wreck\\lib\\index.js:374:20)",
"at wrapped (c:\\Users\\sbtrry\\Desktop\\PQM\\aurora-serverless-api\\node_modules\\wreck\\node_modules\\hoek\\lib\\index.js:879:20)",
"at module.exports.internals.Recorder.onReaderFinish (c:\\Users\\sbtrry\\Desktop\\PQM\\aurora-serverless-api\\node_modules\\wreck\\lib\\index.js:449:16)",
"at Object.onceWrapper (events.js:299:28)",
"at module.exports.internals.Recorder.emit (events.js:215:7)",
"at module.exports.internals.Recorder.EventEmitter.emit (domain.js:499:23)",
"at finishMaybe (_stream_writable.js:656:14)",
"at endWritable (_stream_writable.js:673:3)",
"at module.exports.internals.Recorder.Writable.end (_stream_writable.js:604:5)",
"at IncomingMessage.onend (_stream_readable.js:691:10)",
"at Object.onceWrapper (events.js:299:28)",
"at IncomingMessage.emit (events.js:215:7)",
"at IncomingMessage.EventEmitter.emit (domain.js:476:20)",
"at endReadableNT (_stream_readable.js:1183:12)"
we're on Serverless 2.5 and trying to configure the middleware plugin.
here is the test configuration
test-middleware:
handler:
- api/helpers/version-manager-2.checkVersion
- api/http/discover/testmw.handler
description: GET test-middleware
events:
- http:
path: test-middleware
method: get
but when we're starting sls offline
we get this error:
TypeError: handler.substr is not a function
at splitHandlerPathAndName (/code/pr_2/node_modules/serverless-offline/dist/utils/splitHandlerPathAndName.js:13:24)
at HttpServer.createRoutes (/code/pr_2/node_modules/serverless-offline/dist/events/http/HttpServer.js:371:63)
at Http._create (//code/pr_2/node_modules/serverless-offline/dist/events/http/Http.js:43:65)
at /code/pr_2/node_modules/serverless-offline/dist/events/http/Http.js:52:12
at Array.forEach (<anonymous>)
at Http.create (/code/pr_2/node_modules/serverless-offline/dist/events/http/Http.js:47:12)
at ServerlessOffline._createHttp (/code/pr_2/node_modules/serverless-offline/dist/ServerlessOffline.js:230:53)
at processTicksAndRejections (internal/process/task_queues.js:93:5)
at async Promise.all (index 0)
at ServerlessOffline.start (/code/pr_2/node_modules/serverless-offline/dist/ServerlessOffline.js:145:5)
at ServerlessOffline._startWithExplicitEnd (/code/pr_2/node_modules/serverless-offline/dist/ServerlessOffline.js:194:5)
Hi @juanjoDiaz , thanks for the support the last time. Now, I have to set a middleware for most of my lambda functions and i would like to know if the plugin supports a standard way to introduce a blacklist for excluding lambda functions in pre and pos, something like this:
custom:
middleware:
pre:
- auth.authenticate
- auth.authorize
exclude:
- myExcludedFunction.handler
pos:
- catch: utils.handlerError
Given a serverless configuration like:
provider:
name: aws
runtime: nodejs18.x
stage: ${opt:stage, 'local'}
region: us-east-1
middleware:
pos:
- catch: handlers/middleware/error.handler
plugins:
- serverless-middleware
How can I get the error object thrown by the caller handler?
Looking at the generated code in .middleware
folder I see this:
return Promise.resolve().then(wrappedHandler(handler.bind(auth_exports))).then(wrappedHandler(handler2.bind(profile_id_exports))).then(wrappedHandler(handler3.bind(list_exports))).catch(wrappedHandler(handler4.bind(error_exports)));
The .catch
method is there but I am not sure how to get hold of the actual error object in the error handler function.
upgraded to 3.2.0 from 3.1.0, and not working since, throwing errors like
in ./.middleware/SERVICENAME-dev-validateUnit.ts 4:0-119
Module not found: Error: Can't resolve '../PATH/validate-unit.js' in '/Users/zooli/SERVICEDIR/.middleware'
resolve '../PATH/validate-unit.js' in '/Users/zooli/SERVICEDIR/.middleware'
using description file: /Users/zooli/SERVICEDIR/package.json (relative path: ./.middleware)
using description file: /Users/zooli/SERVICEDIR/package.json (relative path: ./PATH/validate-unit.js)
no extension
/Users/zooli/SERVICEDIR/PATH/validate-unit.js doesn't exist
.ts
/Users/zooli/SERVICEDIR/PATH/validate-unit.js.ts doesn't exist
.js
/Users/zooli/SERVICEDIR/PATH/validate-unit.js.js doesn't exist
as directory
/Users/zooli/SERVICEDIR/PATH/validate-unit.js doesn't exist
it's a TS project, node 18, serverless 3.33.0
I'm on windows, I'm not putting the code since it's just an empty project with nothing more than copy/paste from the docs of serverless-middleware, so it's not remarkable special code
When using serverless-middleware
with serverless offline
there are some problems:
whenever I try to run the command serverless offline
it would throw an error regarding the handler being an array, when this should be normal when using middlewares
serverless offline start
as the starting command, but then another problem appearsfollowed the previous steps, now whenever I try to cancel the process in git bash or powershell I got the error:
Error: ENOTEMPTY: directory not empty, rmdir 'C:\Users\ ... \.middleware'
cleanFolder: false
in the serverless.yml (option that I actually don't want)I want to test my application locally so I use serverless-online.
Without attaching a middleware, any endpoint work fine, but when I attach the middleware it fails to find the module built:
here there is the releant part of my serverless.yaml file
processGet:
handler: src/process/getOne.handler
events:
- http:
path: /${env:APP_DOMAIN}/process/{pid}
method: GET
cors: true
documentation:
summary: 'Retrieves one process by its unique identifier'
pathParams:
- name: pid
description: 'The process id'
in: path
schema:
type: 'string'
format: 'uuid'
methodResponses:
- statusCode: 200
responseBody:
description: 'The process with that identifier'
responseModels:
application/json: 'Process'
- statusCode: 400
responseBody:
description: 'Bad Request'
responseModels:
application/json: 'BadRequest'
- statusCode: 404
responseBody:
description: 'Not Found'
responseModels:
application/json: 'ErrorResponse'
- statusCode: 500
responseBody:
description: 'Internal Server Error'
responseModels:
application/json: 'ErrorResponse'
private: true
middleware:
pre:
- src/middleware/logger.handler
I noticed that running npm install && serverless offline
works fine until I call my endpoint
โ Unhandled exception in handler 'processGet'.
โ Runtime.ImportModuleError: Error: Cannot find module 'fa-api-proxy-dev-processGet'
Require stack:
- <omitted>/node_modules/serverless-offline/src/lambda/handler-runner/in-process-runner/aws-lambda-ric/UserFunction.js
at _loadUserApp (<omitted>/node_modules/serverless-offline/src/lambda/handler-runner/in-process-runner/aws-lambda-ric/UserFunction.js:310:15)
at async module.exports.load (<omitted>/node_modules/serverless-offline/src/lambda/handler-runner/in-process-runner/aws-lambda-ric/UserFunction.js:341:21)
at async InProcessRunner.run (<omitted>/node_modules/serverless-offline/src/lambda/handler-runner/in-process-runner/InProcessRunner.js:41:21)
at async MessagePort.<anonymous> (<omitted>/node_modules/serverless-offline/src/lambda/handler-runner/worker-thread-runner/workerThreadHelper.js:24:14)
โ Error: Cannot find module 'fa-api-proxy-dev-processGet'
Require stack:
- /<omitted>/node_modules/serverless-offline/src/lambda/handler-runner/in-process-runner/aws-lambda-ric/UserFunction.js
The module is correctly created in the directory, but seems that cannot be loaded correctly.
Firstly nice plugin @juanjoDiaz
I'm using serverless-webpack to compile a typescript serverless app. So my directory is something like
serverless.yml
webpack.config.js
src/
functions/
create.ts
middleware.ts
My serverless.yml
looks like
service: serverless-stack
package:
individually: true
plugins:
- serverless-middleware
- serverless-webpack
- serverless-offline
- serverless-dotenv-plugin
provider:
name: aws
runtime: nodejs12.14
stage: prod
region: us-east-1
iamRoleStatements:
- Effect: Allow
Action:
- lambda:InvokeFunction
Resource: "*"
custom:
middleware:
pre:
- src/middleware.bodyJson
webpack:
webpackConfig: ./webpack.config.js
includeModules: true
packager: "yarn"
functions:
create:
handler: src/functions/create.default
events:
- http:
path: notes
method: post
cors: true
authorizer: aws_iam
And my middleware.ts
is simply
export const bodyJson: AWSLambda.Handler = async (event, _context) => {
console.log('ZE MIDDLE--->', event.body);
event.body = JSON.parse(event.body);
return event;
}
Having set the pre
hook for the custom middleware plugin options, the bodyJson
in middleware.ts
should run before every function, but it isn't. This is when I'm running using the serverless-offline
plugin. Any ideas why this would be?
Complete project here
Hi,
I am getting an error when adding the middleware as a handler array in my function.
I am using typescript therefore my serverless file is a typescript file instead of yml:
Cannot load "serverless.ts": Initialization error: TSError: โจฏ Unable to compile TypeScript:
serverless.ts:45:4 - error TS2322: Type 'string[]' is not assignable to type 'string'.
functions: {
index: {
handler: [
'lambdas/endpoints/common/middleware.publicAuth',
'lambdas/endpoints/common/default.index'],
events: [{
http: {
method: 'get',
path: '',
}
}]
},
I am doing something wrong?
Thanks!
Hi, first of all nice work! :)
I have an issue. I am using custom tsconfig.json file and generated middleware causes conflicts (e.g. when noImplicitAny is set to true).
Any thoughts? :)
Does this support the serverless commands sls deploy function
or sls invoke
?
Hi,
I've encountered an issue today when using "serverless-middleware". The plugin works well in general, but I cannot seem to do any dynamic imports in my app using "import()".
The problem is that the path in the compiled app changes to "/.middleware", but the imports are file in the level below.
Here is an example error:
GET /accounts/me (ฮป: getAccount)
ร Cannot find module './8.js'
Require stack:
- /usr/src/app/services/accounts/.webpack/service/.middleware/accounts-api-local-getAccount.js
- /usr/src/app/node_modules/serverless-offline/dist/lambda/handler-runner/in-process-runner/InProcessRunner.js
- /usr/src/app/node_modules/serverless-offline/dist/lambda/handler-runner/in-process-runner/index.js
- /usr/src/app/node_modules/serverless-offline/dist/lambda/handler-runner/HandlerRunner.js
- /usr/src/app/node_modules/serverless-offline/dist/lambda/handler-runner/index.js
- /usr/src/app/node_modules/serverless-offline/dist/lambda/LambdaFunction.js
- /usr/src/app/node_modules/serverless-offline/dist/lambda/LambdaFunctionPool.js
- /usr/src/app/node_modules/serverless-offline/dist/lambda/Lambda.js
- /usr/src/app/node_modules/serverless-offline/dist/lambda/index.js
- /usr/src/app/node_modules/serverless-offline/dist/ServerlessOffline.js
- /usr/src/app/node_modules/serverless-offline/dist/index.js
- /usr/src/app/node_modules/serverless-offline/dist/main.js
- /usr/src/app/node_modules/serverless/lib/utils/import-module.js
- /usr/src/app/node_modules/serverless/lib/classes/plugin-manager.js
- /usr/src/app/node_modules/serverless/lib/serverless.js
- /usr/src/app/node_modules/serverless/scripts/serverless.js
- /usr/src/app/node_modules/serverless/bin/serverless.js
In this case the "8.js" would be in "/usr/src/app/services/accounts/.webpack/service/" and not in "/usr/src/app/services/accounts/.webpack/service/.middleware/".
Is there any known work around to this?
Thank you.
Node supports require
without an extension, but does not support import
without an extension. The built middleware files all have no extension on the imports. This is fine when they're compiled to an ES5 target because they are rewritten to require
s, but when targeting ES6 they are not rewritten and remain without an extension. This means running a function in Serverless throws a ERR_MODULE_NOT_FOUND.
My tsconfig.json looks like this:
{
"compilerOptions": {
"esModuleInterop": true,
"preserveConstEnums": true,
"strictNullChecks": true,
"sourceMap": true,
"allowJs": true,
"target": "es6",
"outDir": ".build",
"moduleResolution": "node",
"lib": ["es2021"],
"rootDir": "./",
"forceConsistentCasingInFileNames": true,
"noImplicitReturns": true,
"strict": true,
"noUnusedLocals": true
}
}
And Serverless is targetting nodejs18.x.
It seems that adding .js
in the import template path in /src/typescript.js:26
solves this. It may also need adding to /src/javascript.js:26
. I'm not sure if this will cause more problems than it solves if people are importing non-js files here (which they shouldn't be as middleware), but changing this line makes everything work for me.
I am trying to implement middleware at function level by following this doc.
But the middleware function I have written in a separate file and referenced in the serverless.yml is not even getting deployed (I checked by downloading the lambda function) i.e. middleware at function level not even getting registered.
Any idea where I am missing something?
Note: the middleware at package level is working perfectly but I have a requirement to implement it at function level.
Node version used: 14
"serverless": "^2.66.0",
"serverless-domain-manager": "^5.1.0",
"serverless-dotenv-plugin": "^3.10.0",
"serverless-middleware": "^0.0.15",
"serverless-offline": "^8.5.0",
"serverless-openapi-documentation-v2": "^0.4.6",
"serverless-plugin-typescript": "2.1.0",
"serverless-prune-plugin": "^1.6.1",
Below is the sample code of the serveless file:
provider:
name: aws
runtime: nodejs14.x
functions:
my-function:
middleware:
pre:
- src/authMiddleware.authenticate
post:
- catch: src/catchHandler.catchErrors
handler: src/handler.users
timeout: 30
events:
-service: your-service-name
plugins:
- serverless-dotenv-plugin
- serverless-offline
- serverless-middleware
- serverless-domain-manager
- serverless-plugin-typescript
- serverless-openapi-documentation-v2
- serverless-prune-plugin
custom:
middleware:
pre:
- src/initialMiddleware.init
pos:
- catch: src/catchHandler.catchErrors
I have function
getCategories:
middleware:
pre:
- ./src/middleware/auth.middleware
handler: ./src/handlers/categories/getAll.handler
events:
- http:
path: /api/categories
method: GET
cors: true
src/middleware/auth.ts
export const middleware = async (event: any, context: any) => {
try {
console.log("hello from auth middleware");
console.log(event);
console.log(context);
} catch (err) {
console.log(err);
}
};
when i trigger my function it ignores the middleware
Hi nice work with this, it is awesome.
I spent a good while figuring out why this wasn't working, it came down to the project I am working was being started with sls offline
and needed to be started with sls offline start
in order for this project to be initiated.
After a long wait, Serverless finally supports nodejs16.x
, but this plugin errors if that value is used.
Hi guys, i am experimenting issues in AWS that i dont have in local (running serverless offline). When i hit an endpoint with middleware in local, everything works as expected, not the case in AWS, that i got 502 Bad Gateway and :
{ "message": "Internal server error" }
Looking at the cloudwatch service in the lambda function i see this:
Bad handler .middleware/remoteIndex.handler
This is my lambda function, basically all of them return a promise:
remoteIndex:
handler:
- api/controllers/AuthController.authorize
- api/controllers/advanced/SiteOptionsController.remoteIndex
- catch: api/controllers/ErrorController.unauthorize
events:
- http:
path: api/siteOptions/
And the generated remoteIndex.js
const api_controllers_AuthController = require('../api/controllers/AuthController');
const api_controllers_advanced_SiteOptionsController = require('../api/controllers/advanced/SiteOptionsController');
const api_controllers_ErrorController = require('../api/controllers/ErrorController');
module.exports.handler = async (event, context) => {
let end = false;
context.end = () => end = true;
const wrappedHandler = handler => prev => {
if (end) return prev;
context.prev = prev;
return handler(event, context);
};
return Promise.resolve()
.then(wrappedHandler(api_controllers_AuthController.authorize.bind(api_controllers_AuthController)))
.then(wrappedHandler(api_controllers_advanced_SiteOptionsController.remoteIndex.bind(api_controllers_advanced_SiteOptionsController)))
.catch(wrappedHandler(api_controllers_ErrorController.unauthorize.bind(api_controllers_ErrorController)));};
If you guys could take a look to this issue.
Hey, thanks for the speedy update to v3. I'm getting an error on deploy though:
Error:
UPDATE_FAILED: WebhookLambdaFunction (AWS::Lambda::Function)
Properties validation failed for resource WebhookLambdaFunction with message:
#/Handler: expected type: String, found: JSONArray
My yml config looks something like:
auth:
handler:
- middleware/getConfig.handler
- middleware/validateAuthRequest.handler
- handlers/auth/auth.handler
events:
- httpApi:
path: /{appName}/auth
method: get
Serverless also complains about this config (as it always has) when you run deploy:
Warning: Invalid configuration encountered
at 'functions.auth.handler': must be string
Thank you!
@juanjoDiaz Thanks once again for a great package. Since AWS Lambda now supports Node v12, are there plans to support Node v12?
I have configured both pre
and pos
middleware handlers which work fine when invoking the function that hosts our HTTP API. But when I invoke any other function, it appears the middleware does not run.
Plugins are configured like this:
plugins:
- serverless-middleware
- serverless-domain-manager
- serverless-offline
- serverless-plugin-aws-alerts
- serverless-plugin-typescript
- serverless-plugin-datadog
- serverless-plugin-resource-tagging
Middleware is configured universally:
custom:
middleware:
pre:
- src/lambdas/middleware/initialize.handler
pos:
- src/lambdas/middleware/teardown.handler
The initialize function loads async bindings into my IOC container, and teardown unbinds them. The function that behaves correctly is declared like this:
functions:
api:
name: ${self:service}-api-${sls:stage}
handler: src/api/Api.handle
timeout: 30 # 30 seconds, limited by API gateway
events:
- http:
path: /{proxy+}
method: any
When I add console.log
statements in my initialize
and teardown
handlers, I can see the console output when I make a request with Postman. But it does not work correctly when I use aws lambda invoke
to test this other function:
transferOrderShippedHandler:
handler: src/transfer/queue/transfer-order-shipped-handler/TransferOrderShippedHandlerLambda.handle
name: transfer-order-shipped-handler-${sls:stage}
reservedConcurrency: 1 # configured to cap max concurrency, to protect downstreams
description: Handler for processing transfer order shipments.
timeout: 300 # 5 min; Not an expensive operation, no need for setting to max timeout
events:
- sqs:
arn:
Fn::GetAtt:
- FulfillmentOrderShippedQueue
- Arn
batchSize: 1
When I invoke this function, I know that initialize
does not run because. Partly because I don't see the console output, but also because the exception that gets thrown by the handler indicates that my IOC container was not initialized. Take a look at the bottom line of that stack trace:
' at Object.<anonymous> (/Users/sam/src/github.com/deliverr/transfer-service/.build/.middleware/transfer-order-shipped-handler-dev.js:5:93)'
That line shows that the new handler that was generated by serverless-middleware
is the one that's being invoked. The contents of that file look exactly like you'd expect them to:
'use strict';
Object.defineProperty(exports, "__esModule", { value: true });
exports.handler = void 0;
const src_lambdas_middleware_initialize = require("../src/lambdas/middleware/initialize");
const src_transfer_queue_transfer_order_shipped_handler_TransferOrderShippedHandlerLambda = require("../src/transfer/queue/transfer-order-shipped-handler/TransferOrderShippedHandlerLambda");
const src_lambdas_middleware_teardown = require("../src/lambdas/middleware/teardown");
const handler = (event, context) => {
let end = false;
context.end = () => end = true;
const wrappedHandler = (handler) => (prev) => {
if (end)
return prev;
context.prev = prev;
return handler(event, context);
};
return Promise.resolve()
.then(wrappedHandler(src_lambdas_middleware_initialize.handler.bind(src_lambdas_middleware_initialize)))
.then(wrappedHandler(src_transfer_queue_transfer_order_shipped_handler_TransferOrderShippedHandlerLambda.handle.bind(src_transfer_queue_transfer_order_shipped_handler_TransferOrderShippedHandlerLambda)))
.then(wrappedHandler(src_lambdas_middleware_teardown.handler.bind(src_lambdas_middleware_teardown)));
};
exports.handler = handler;
//# sourceMappingURL=transfer-order-shipped-handler-dev.js.map%
They chain the original handler together with the middleware handlers, in the exact same way that they do in the handler defined by .build/.middleware/transfer-api-dev.js
. So it is extremely puzzling to me that the initialize
function is not getting invoked.
When running this plugin with serverless v3, the following error shows:
Error:
At least one of the plugins defines a validation schema that is invalid. Try disabling plugins one by one to identify the problematic plugin and report it to the plugin maintainers.
I don't know what level of effort this involves or what exactly SLS 3 doesn't like, just wanted to post here so it could be tracked.
Env info: Environment: darwin, node 16.10.0, framework 3.0.1 (local), plugin 6.0.0, SDK 4.3.0
Thanks for library mate @juanjoDiaz
So for my project I have a custom Handler interface as I JSON.parse every body request in a middleware:
interface APIGatewayEvent<IBody = null> extends Omit<AWSLambda.APIGatewayEvent, 'body'> {
body: IBody;
}
export type AWSLambdaHandler<IBody = {}> = AWSLambda.Handler<APIGatewayEvent<IBody>>;
Usage in functions like
interface Body {
content: string;
attachment: string;
}
const create: AWSLambdaHandler<Body> = async (event) => { ... }
However i get typing errors as you declare a custom Handler
in typescript.js which I can't import and set my own custom Event. How can have my own custom handler typings?
Maybe is it better if you just drop your Handler
interface and leave typings to be sorted out by us? So maybe just give handler any
type so typescript.js
becomes
/**
* @description Create TypeScript middleware handler
*
* @param {Array<string>} handlers - handlers to be run as middleware
*np
* @return {string} TypeScript Middleware handler
* */
function createTSMiddlewareHandler(handlers, pathToRoot) {
const handlersInfo = handlers
.reduce((modules, handler) => {
if (handler.then && handler.catch) {
const { name, module } = handler.then;
const { name: name2, module: module2 } = handler.catch;
return { ...modules, [module]: name, [module2]: name2 };
}
if (handler.then) {
const { name, module } = handler.then;
return { ...modules, [module]: name };
}
const { name, module } = handler.catch;
return { ...modules, [module]: name };
}, {});
const imports = Object.keys(handlersInfo)
.map((handler) => `import * as ${handlersInfo[handler]} from '${pathToRoot}/${handler}';`).join('\n');
const promiseChain = handlers.map((handler) => {
if (handler.then && handler.catch) {
const { name, fn } = handler.then;
const { name: name2, fn: fn2 } = handler.catch;
return ` .then(wrappedHandler(${name}.${fn}.bind(${name})))
.catch(wrappedHandler(${name2}.${fn2}.bind(${name2})))`;
}
if (handler.then) {
const { name, fn } = handler.then;
return ` .then(wrappedHandler(${name}.${fn}.bind(${name})))`;
}
const { name, fn } = handler.catch;
return ` .catch(wrappedHandler(${name}.${fn}.bind(${name})))`;
}).join('\n');
return `'use strict';
${imports}
export const handler = (event: any, context: any) => {
let end = false;
context.end = () => end = true;
const wrappedHandler = (handler: any) => (prev: any): Promise<any> => {
if (end) return prev;
context.prev = prev;
return handler(event, context);
};
return Promise.resolve()
${promiseChain};
};`;
}
module.exports = createTSMiddlewareHandler;
getItems:
handler: src/serverless/items/handler.getItems
events:
- http:
path: items
method: get
cors: true
middleware:
pre:
- src/middleware/index.checkHeader
setItems:
handler: src/serverless/items/handler.setItesm
events:
- http:
path: items
method: post
cors: true
middleware:
pre:
- src/middleware/index.checkHeader
when applying the code above, in the code of getItems, there are setItems.js and map files in .middleware, setItems also has js and map files for getItems.
what should i check more?
Does this plugin work along with serverless-typescript or serverless-esbuild? It doesn't seem like the auth and log is being called at all for me
plugins:
- serverless-esbuild
- serverless-middleware
hello:
handler: src/Hello/hello.hello
events:
- http:
path: hello
method: get
cors: true
middleware:
pre:
- src/Middleware/auth.auth
pos:
- catch: src/Middleware/log.log
I've been trying to use middleware with serverless-webpack
and encountered some issues that almost make it impossible to combine serverless-middleware
, serverless-webpack
, and TypeScript.
The problem arises when placing serverless-middleware
before serverless-webpack
in the plugins
list within serverless.yml
. This causes the function's entry point to change from /path/to/invoked.handler
to .middleware/functionxxx/
, a clever behavior. However, a hurdle emerges: the outcome of the middleware contains imports like:
import * as src_middlewares_logger from '../src/middlewares/logger.js';
import * as src_handlers_index from '../src/handlers/index.js';
import * as src_middlewares_errorHandler from '../src/middlewares/errorHandler.js';
Later, when Webpack attempts to bundle these files, it results in an error. The cause of the error is that, unlike serverless-typescript-plugin
which transpiles TypeScript to JavaScript and doesn't mind if files exist or not, Webpack expects JS files and throws a MODULE NOT FOUND
error.
To address this, I need to either transpile those files using tsc
to create JS files, or set up a separate Webpack build to bundle them into JS before invoking serverless-middleware
. This way, when the actual serverless-webpack
processes the serverless-middleware
-wrapped functions, it encounters JS files and avoids the MODULE NOT FOUND
error.
Another approach is to reorder the plugins, placing serverless-webpack
after serverless-plugin-typescript
. This resolves the issue by generating JS files, but it contradicts the initial intent of using serverless-webpack
to avoid the overhead introduced by serverless-plugin-typescript
.
A potential solution might involve modifying how files are imported in serverless-middleware
wrapped functions, and removing the file extension to ensure compatibility with middleware placement. Additionally, if serverless-middleware
could be configured to read bundled files by specifying the root, it might offer a cleaner solution.
For now, I've positioned serverless-middleware
after serverless-plugin-typescript
, though this creates unnecessary overhead due to middleware wrapping, building, and bundling in sequence, which doesn't seem ideal.
also, there should be a way to include middleware in webpack build, by reading middleware directory or providing them from middleware plugin to webpack cause right now my approach to include middleware in webpack is by adding them to entry object in webpack, it's not necessary to do it if serverless-middleware was mentioned after serverless-typescrypt-plugin (which is not a good practice at all)
entry: {
...slsw.lib.entries,
'src/middlewares/errorHandler': './src/middlewares/errorHandler.js',
'src/middlewares/logger': './src/middlewares/logger.js',
},
The path of the .middleware folder using the default configuration is broken in serverless 3.0 + serverless-middleware 3.0.
Framework Core: 3.22.0 (local) 3.21.0 (global)
Plugin: 6.2.2
SDK: 4.3.2
Error: Error: Cannot find module '/project-name/.build/.middleware/service-name-functionName'
Serverless for some reason is assuming that the /.middleware/
directory is located inside of /.build/.middleware/
and that is not the default location of the folder.
The pathToRoot
variable resolves to just ..
without a preceding slash, (../
) and I thought that was the problem although manually altering the following did not fix it. Although, it does print out the preceding slash in the logs and doesn't seem to hurt anything. Not sure if not adding a preceding slash was intentional or not.
const pathToRoot = path.relative(pathFolder, this.serviceDir);
- original
const pathToRoot = path.relative(pathFolder, this.serviceDir) + '/';
- modified
If I find a fix, I'm happy to commit it but since you likely can pinpoint it faster, I'm posting this for visibility into the issue as well as for archival purposes.
serverless.yml has this configuration:
- serverless-middleware # Must stay before serverless-offline and serverless-webpack
- serverless-webpack
- serverless-offline
- serverless-prune-plugin
custom:
middleware:
pre:
- src/common/request_middleware/index.beforeRequest
pos:
- then: src/common/request_middleware/index.afterRequest
- catch: src/common/request_middleware/index.errorHandler
It works well when running locally, but when running in production, all api requests return a status code 500, Internal Server Error. What might be the cause?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.