OpenJS Architect is an open-source framework for writing and deploying serverless applications to AWS. Each Architect project is comprised of many small and independent Lambda functions that are executed statelessly in their own isolated runtimes.
So how do we manage shared code and dependencies between functions?
Dependencies defined in your root package.json
You are likely to use some dependencies in each Lambda function that you are deploying like including the @architect/functions
library. Architect has the ability to discover use your project's root package.json
to install dependencies into your Lambda functions. Let's take a look at an example.
First, start by creating a new Architect project
npm init @architect ./arc-example
cd arc-example
npm install @architect/functions
By installing @architect/functions
to the root package.json
it will be available to all your functions when you require it. We won't need to manage dependencies with a per-function package.json
.
So now we can use it in our get-index
function.
// src/http/get-index/index.js
let arc = require('@architect/functions')
async function route(req) {
return {
statusCode: 200,
html: `<h1> Praise Cage </h1>`
}
}
exports.handler = arc.http.async(route)
src/shared
and src/views
Another way we can handle shared code is with a special folder src/shared
. Architect provides an easy way to abstract and reuse code in your functions. Most applications need to share logic, templates, or utilities. In order to do this, Architect uses a folder convention to copy the contents of src/shared
and src/views
into each function's node_modules
directory.
It's important to note that the entire contents of src/shared
are copied recursively. I suggest you keep the directory structure as flat as possible, and the payloads as small as possible to improve performance.
Let's create an example helper function.
src/shared
example
To get started, create a new project from the command line.
npm init @architect ./arc-shared-views
Next, we can modify the app.arc
file in the root of the project with the following:
# app.arc file
@app
arc-shared
@http
get /
get /answer
Now we can start to build out our src/shared
modules by creating a new folder at src/shared/helper.js
. In this example, we need to make sure a number is converted to a string and this helper function will do the trick!
// src/shared/helper.js
function theAnswer() {
//really important number that needs to be converted to a string
let universe = 42
return universe.toString()
}
module.exports = theAnswer
We can use this helper in all of our functions by just requiring it from @architect/shared
. Modify the get-answer function with the following:
// src/http/get-answer/index.js
let Answer = require('@architect/shared/helper')
exports.handler = async function http (req) {
return {
statusCode: 200,
headers: {
'cache-control': 'no-cache, no-store, must-revalidate, max-age=0, s-maxage=0',
'content-type': 'text/html; charset=utf8'
},
body: `
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title> The Answer is </title>
</head>
<body>
<p> This is the Answer: ${Answer()} </p>
</body>
</html>
`
}
}
Run npm start
from the command line and take a look at our code structure. Sandbox will hydrate our functions with a node_modules/@architect/shared
directory which is part of the function's payload when deployed and executed.
.
├── src
│ ├── http
│ │ ├── get-index/
│ │ └── get-answer/
│ │
│ └── shared/
│ └── helper.js
│
├── app.arc
└── package.json
When you navigate to http://localhost:3333/answer you will be greeted with data from our shared module, and it can be used by any other function.
src/views
example
The src/views
folder is a special location that allows you to include code for each of your HTPP functions with a GET route. Continuing with our previous src/shared
example we will include a layout template that your HTTP functions can use.
Modify the app.arc
file to match the following:
@app
arc-shared
@http
get /
get /answer
get /about
get /css/:stylesheet
@views
get /
get /about
What we've done is added two new routes - /about
and css/:stylesheet
, then declared that two of the routes /
and /about
should receive a copy of the modules in src/views
.
Create a new folder and file, src/views/layout.js
. In this file we'll write the following contents:
module.exports = function Layout (props) {
props = props || {}
let heading = props.heading || 'Architect views!'
return `
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Architect example</title>
<link rel="stylesheet" href="/css/styles.css">
</head>
<body>
<h1>${heading}</h1>
</body>
</html>
`
}
This is our shared view template that will be used by each GET route listed under the @views
pragma in the app.arc
file.
Next, we'll modify src/http/get-index/index.js
with the following:
let Layout = require('@architect/views/layout')
exports.handler = async function http (request) {
try {
return {
statusCode: 200,
headers: {
'content-type':'text/html; charset=utf8'
},
body: Layout()
}
} catch (e) {
console.error(e)
return {
headers: {
type: 'application/json; charset=utf8',
},
status: 500,
body: JSON.stringify({
name: e.name,
message: e.message,
stack: e.stack
}, null, 2)
}
}
}
This function will call the layout file and return its output as the body of the response. Next, we can set up the about page to send a different set of props to the layout. Modify sec/http/get-about/index.js
with the following:
let Layout = require('@architect/views/layout')
exports.handler = async function http (request) {
try {
return {
statusCode: 200,
headers: {
'content-type':'text/html; charset=utf8'
},
body: Layout({heading: 'About'})
}
} catch (e) {
console.error(e)
return {
status: 500,
type: 'application/json; charset=utf8',
body: JSON.stringify({
name: e.name,
message: e.message,
stack: e.stack
}, null, 2)
}
}
}
Now when /about
is requested, this function will execute and be able to return the data being passed into Layout()
.
Finally, we have some finder control over which GET functions will have /src/views
copied into it. We do this with the @views
pragma in the app.arc
file. We want to create a URL to our style sheet, but this function doesn't need access to the layout code. Only the GET routes under @views
will have the src/views
code copied into it. Our first route of /answer
won't have src/views
modules copied into node_modules
.
Modify the code in src/http/get-css-000stylesheet/index.js
with the following:
const styles = `
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
}
`
exports.handler = async function http (request) {
return {
statusCode: 200,
type: 'text/css; charset=utf8',
body: styles
}
}
OK! Go ahead and run npm start
from the project root and navigate to http://localhost:3333 to see our app in action. Change the route to http://localhost:3333/about and you'll see that our proper were passed as expected.
See full example code in the repo: https://github.com/pchinjr/arc-shared-views-example
Top comments (0)