DEV Community

Cover image for Mixing Deno and Node with Serverless Functions on Begin
Paul Chin Jr.
Paul Chin Jr.

Posted on

Mixing Deno and Node with Serverless Functions on Begin

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

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.

npm install @architect/functions @begin/data
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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.

// 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'})
    }),
  };
}
Enter fullscreen mode Exit fullscreen mode

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.

// 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>
`
}
Enter fullscreen mode Exit fullscreen mode
// 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>
`
}

Enter fullscreen mode Exit fullscreen mode

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.

// 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)
Enter fullscreen mode Exit fullscreen mode

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

Top comments (0)