RedwoodJS

中国镜像

# Serverless Functions

Work in Progress ⚠️

There's more to document here. In the meantime, you can check our community forum for answers.

Want to contribute? Redwood welcomes contributions and loves helping people become contributors. You can edit this doc here. If you have any questions, just ask for help! We're active on the forums and on discord.

Redwood looks for serverless functions in api/src/functions. Each function is mapped to a URI based on its filename. For example, you can find api/src/functions/graphql.js at http://localhost:8911/graphql.

# Creating Serverless Functions

Creating serverless functions is easy with Redwood's function generator:

yarn rw g function <name>

It'll give you a stub that exports a handler that returns a status code—the bare minimum you need to get going:

export const handler = async (event, context) => {
  return {
    statusCode: 200,
    headers: {
      'Content-Type': 'application/json',
    },    
    body: JSON.stringify({
      data: '${name} function',
    }),
  }
}

# The handler

For a lambda function to be a lambda function, it must export a handler that returns a status code. The handler receives two arguments: event and context. Whatever it returns is the response, which should include a statusCode at the very least.

Note that you can use code in api/src in your serverless function, such as importing the db from src/lib/db.

# Developing locally

When you're developing locally, the dev server watches the api directory for modifications; when it detects any, it re-imports all the modules.

# Security considerations

When deployed, a custom serverless function is an open API endpoint and is your responsibility to secure appropriately. 🔐

That means anyone can access your function and perform any tasks it's asked to do. In many cases, this is completely appropriate and desired behavior.

But, in some cases, for example when the function interacts with third parties, like sending email, or when it retrieves sensitive information from a database, you may want to ensure that only verified requests from trusted sources can invoke your function.

And, in some other cases, you may even want to limit how often the function is called over a set period of time to avoid denial-of-service-type attacks.

# Authentication

If you invoke your function from your web side, you can use requireAuth() to ensure that function is allowed to execute by passing your auth provider's access token and the provider method in the request headers:

auth-provider: <your provider>
authorization: Bearer <access_token>

This will then decode the Bearer token and check to see if the request is authorized.

import { requireAuth } from 'src/lib/auth'
import { AuthenticationError, ForbiddenError } from '@redwoodjs/api'

export const handler = async (event, context) => {
  try {
    requireAuth({ role: 'admin' })

    return {
      statusCode: 200,
      headers: {
        'Content-Type': 'application/json',
      },      
      body: JSON.stringify({
        data: 'Permitted',
      }),
    }
  } catch (e) {
    if (e instanceof AuthenticationError) {
      return {
        statusCode: 401,
      }
    } else if (e instanceof ForbiddenError) {
      return {
        statusCode: 403,
      }
    } else {
      return {
        statusCode: 400,
      }
    }
  }
}

# Webhooks

If your function receives an incoming Webhook from a third party, see Webhooks in the RedwoodJS documentation to verify and trust its payload.

# Other considerations

In addition to securing your serverless functions, you may consider logging, rate limiting and whitelisting as ways to protect your functions from abuse or misuse.

# Visibility via Logging

Logging in production — and monitoring for suspicious activity, unknown IP addresses, errors, etc. — can be a critical part of keeping your serverless functions and your application safe.

Third-party log services like logFlare, Datadog and LogDNA all have features that store logs for inspection, but also can trigger alerts and notifications if something you deem untoward occurs.

See Logger in the RedwoodJS docs for more information about how to setup and use logging services.

# Rate Limiting

Rate limiting (or throttling) how often a function executes by a particular IP addresses or user account is a common way of stemming api abuse (for example, a distributed Denial-of-Service, or DDoS, attack).

As LogRocket says:

Rate limiting is a very powerful feature for securing backend APIs from malicious attacks and for handling unwanted streams of requests from users. In general terms, it allows us to control the rate at which user requests are processed by our server.

API Gateways like Kong offer plugins to configure how many HTTP requests can be made in a given period of seconds, minutes, hours, days, months, or years.

Currently, RedwoodJS does not offer rate limiting in the framework, but your deployment target infrastructure may. This is a feature RedwoodJS will investigate for future releases.

For more information about Rate Limiting in Node.js, consider:

# IP Address Whitelisting

Because the event passed to the function handler contains the request's IP address, you could decide to whitelist only certain known and trusted IP addresses.


const ipAddress = ({ event }) => {
  return (
    event?.headers?.['client-ip'] ||
    event?.requestContext?.identity?.sourceIp ||
    'localhost'
  )
}

If the IP address in the event does not match, then you can raise an error and return 401 Unauthorized status.