Mixing Deno and Node with Serverless Functions on Begin
Published: 2021-03-02 14:12:44

One of the promises of serverless functions is the ability to bring your own runtime. You can even mix and match runtimes within the same application. In this post, we'll show a reduced example of a serverless side rendered HTML using Deno and a single POST endpoint written with Node.js. 

Start with a Deno Hello World example by clicking the button below to deploy a fresh app to Begin. 
[![Deploy to Begin](https://static.begin.com/deploy-to-begin.svg)](https://begin.com/apps/create?template=https://github.com/begin-examples/deno-hello-world)

Behind the scenes, Begin will provision a new GitHub repo and set up your CI/CD all in a single click. Once your app is provisioned clone the repo and install some dependencies.

```bash
npm install @architect/functions @begin/data
```

We'll first modify the `app.arc` file. This file is our infrastructure as code manifest. It defines the routes we want to declare as well as where the code for each function. 

```
@app
begin-app

@http
get /
post /pray

@tables
data
  scopeID *String
  dataID **String
  ttl TTL
```

In our app we have two HTTP functions, a `get-index` function and a `post-pray` function. We will start with the `get-index` function. 

```javascript
// src/http/get-index/index.js

import HTML from "./components/html.js";
import Main from "./components/main.js"

export async function handler(req /*object*/) {
  return {
    headers: {
      "content-type": "text/html; charset=utf8",
    },
    statusCode: 200,
    body: HTML({
      title: "SSR in Deno",
      children: Main({name: 'Cage'})
    }),
  };
}
```

Notice that we're using Deno for this function so we can use import statements. Next, we will create the two components that our app is created with. `HTML` is the HTML container code and `Main` will be our main app container. These components will have state passed into them from our `get-index` function.

```javascript
// src/http/get-index/components/html.js

export default function document(state={}) {
  let {children, title } = state
  return `
<!DOCTYPE html>
<html>
<head>
  <title>${title}</title>
</head>
 <body>
  ${children}
 </body>

</html>
`
}
```

```javascript
// src/http/get-index/components/main.js
export default function Main(state={}) {
  let { name } = state
  
  let time = new Date().toLocaleTimeString()

  return `
<div>
  <h1>Praise ${name}</h1>
  <p>${time}<p>
  <form action='/pray' method="POST">
  <input type="text" name="prayer">
  <button>Submit</button>
  </form>
</div>
`
}

```

The `Main` component is a form element that will POST the input text to our serverless function. So let's take a look at the POST function. 

```javascript
// src/http/post-pray/index.js

const arc = require('@architect/functions')
const data = require('@begin/data')

async function route(req) {
  console.log(req.body.prayer)

  let save = await data.set({
    table: 'prayers',
    item: req.body.prayer
  })

  console.log(save)

  return {
    location: `/?success=${req.body.prayer}`
  }
}

exports.handler = arc.http.async(route)
```
Our POST function catches the request body and saves it to a DynamoDB table and returns a success query param to illustrate that the server did it's part.

You can view the completed code repo here: [https://github.com/pchinjr/deno-mixed-runtimes](https://github.com/pchinjr/deno-mixed-runtimes)