Here’s an example: https://middy.js.org/docs/intro/getting-started
import middy from '@middy/core'
import middleware1 from 'sample-middleware1'
import middleware2 from 'sample-middleware2'
import middleware3 from 'sample-middleware3'
const lambdaHandler = (event, context) => {
/* your business logic */
}
export const handler = middy(lambdaHandler)
handler
.use(middleware1())
.use(middleware2())
.use(middleware3())
Why export handler
first, and then further configure it in the same file in which it’s been defined in?
- Is there ever a good reason to use this pattern?
- Also does Node normalize the exports, by which I mean ignoring where export statements are located and when someone imports a package, Node somehow ensures all the exports occur after everything else?
Oddly enough they use different patterns in different examples. Here’s another one:
// import core
import middy from '@middy/core' // esm Node v14
//const middy = require('@middy/core') // commonjs Node v12
// import some middlewares
import jsonBodyParser from '@middy/http-json-body-parser'
import httpErrorHandler from '@middy/http-error-handler'
import validator from '@middy/validator'
// This is your common handler, in no way different than what you are used to doing every day in AWS Lambda
const lambdaHandler = async (event, context) => {
// we don't need to deserialize the body ourself as a middleware will be used to do that
const { creditCardNumber, expiryMonth, expiryYear, cvc, nameOnCard, amount } = event.body
// do stuff with this data
// ...
const response = { result: 'success', message: 'payment processed correctly'}
return {statusCode: 200, body: JSON.stringify(response)}
}
// Notice that in the handler you only added base business logic (no deserialization,
// validation or error handler), we will add the rest with middlewares
const eventSchema = {
type: 'object',
properties: {
body: {
type: 'object',
properties: {
creditCardNumber: { type: 'string', minLength: 12, maxLength: 19, pattern: '\\d ' },
expiryMonth: { type: 'integer', minimum: 1, maximum: 12 },
expiryYear: { type: 'integer', minimum: 2017, maximum: 2027 },
cvc: { type: 'string', minLength: 3, maxLength: 4, pattern: '\\d ' },
nameOnCard: { type: 'string' },
amount: { type: 'number' }
},
required: ['creditCardNumber'] // Insert here all required event properties
}
}
}
// Let's "middyfy" our handler, then we will be able to attach middlewares to it
const handler = middy()
.use(jsonBodyParser()) // parses the request body when it's a JSON and converts it to an object
.use(validator({eventSchema})) // validates the input
.use(httpErrorHandler()) // handles common http errors and returns proper responses
.handler(lambdaHandler)
CodePudding user response:
Wherever the export
statement appears for an identifier in a given file has no effect at all on anything, including on how/when other modules interact with it. There is no difference between
export const handler = middy(lambdaHandler)
handler
.use(middleware1())
.use(middleware2())
.use(middleware3())
and
const handler = middy(lambdaHandler)
handler
.use(middleware1())
.use(middleware2())
.use(middleware3())
export { handler };
except that the second takes a but more code (and so some prefer the first approach).
It's a bit similar to var
. No matter where var <someVarName>
appears in a given block, all the engine cares about is that someVarName
was declared in the block, not where the line with var
is. Similarly, with exports, all the engine cares about is whether something was exported, not where the export
keyword happens to be.
Node somehow ensures all the exports occur after everything else?
Yes, mostly. After importing, a module script will always run all of its (top-level) code to the end before any other module starts running its (top-level) code. If there is
console.log('1');
// 5000 lines of code
export const foo = 'foo';
// 500 lines of code
console.log('2');
Any other modules that use foo
will only do so after both 1
and 2
have been logged.
(The only exception to ensuring that everything has been exported properly before other modules use them is circular dependencies, which mess things up - with circular dependencies, if a module imports another, and that other module imports the first, one of those won't be initialized when the other starts running its top-level code - but the location of the export
keyword still has no impact)
CodePudding user response:
The
export
declaration is used when creating JavaScript modules to export live bindings to functions, objects, or primitive values. MDN:export
Live bindings is a concept introduced in ES modules. It means that when the exporting module changes a value, the change will be visible from the importer side. SO
The way I think of it, is like making a reference to an object, then editing the original object. Any changes will be reflected when calling the reference:
const a = {foo:'foo'}
const c = a; // Imagine this is the export and import in another file
a.foo = 'bar';
console.log(c.foo) // 'bar' - the change is reflected in the import
The thing here is that export
is not like return
which ends execution. The code after the export still runs.
The exported object can be considered global wherever imported, so if our importing script mutates the objects further, then these changes will also be reflected in the global object.
It could be useful to think of it as a singleton.