Code Monkey home page Code Monkey logo

netlify-faunadb-example's Introduction

Netlify + FaunaDB    

Example of using FaunaDB with Netlify functions

Expand Table of Contents

About this application

This application is using React for the frontend, Netlify Functions for API calls, and FaunaDB as the backing database.

faunadb netlify

Deploy with one click

Click the Deploy to Netlify Button

Deploy to Netlify

Setup & Run Locally

  1. Clone down the repository

    git clone https://github.com/netlify/netlify-faunadb-example.git
  2. Enter the repo directory

    cd netlify-faunadb-example
  3. Install the dependencies

    npm install
  4. Sign up for a FaunaDB account

    https://dashboard.fauna.com/accounts/register

  5. Create a database

    In the Fauna Cloud Console:

    • Click “New Database”
    • Enter “Netlify” as the “Database Name”
    • Click “Save”
  6. Create a database access key

    In the Fauna Cloud Console:

    • Click “Security” in the left navigation
    • Click “New Key”
    • Make sure that the “Database” field is set to “Netlify”
    • Make sure that the “Role” field is set to “Admin”
    • Enter “Netlify” as the “Key Name”
    • Click “Save”
  7. Copy the database access key’s secret

    Save the secret somewhere safe; you won’t get a second chance to see it.

  8. Set your database access secret in your terminal environment

    In your terminal, run the following command:

    export FAUNADB_SERVER_SECRET=YourFaunaDBSecretHere

    Replace YourFaunaDBSecretHere with the value of the secret that you copied in the previous step.

  9. Bootstrap your FaunaDB collection and indexes

    npm run bootstrap
  10. Run project locally

    npm start

TLDR; Quick Deploy

  1. Click the Deploy to Netlify button

Deploy to Netlify

  1. Click “Connect to GitHub”. Authorize Netlify, when asked.

  2. Paste your FaunaDB database access secret into the “Your FaunaDB Server Secret” field.

  3. Click “Save & Deploy”. Netlify clones your repo, then builds and deploys your app. All done!

setup steps

Tutorial

Background

This application is using React for the frontend, Netlify Functions for API calls, and FaunaDB as the backing database.

We are going to explore how to get up and running with Netlify Functions and how to deploy your own serverless backend.

1. Create React app

We are using React for this demo app, but you can use whatever you want to manage the frontend.

Into VueJS? Awesome use that.

Miss the days of jQuery? Righto, jQuery away!

Fan of VanillaJS? By all means, have at it!

  1. Install create react app

    npm install create-react-app -g
  2. Create the react app!

    create-react-app my-app
  3. The react app is now setup!

    # change directories into my-app
    cd my-app

2. Set up FaunaDB

We are using FaunaDB to hold and store all of our todo data.

To setup a FaunaDB account and get the API key we'll use to scaffold out our todos database, head over to https://dashboard.fauna.com/accounts/register and create a free Fauna Cloud account.

  1. Sign up

    Sign up for Fauna

  2. Create a key

    Create a fauna key

  3. Name your key and create

    Name the fauna key and create

  4. Copy this API key for later use, or use the Deploy to Netlify Button and plugin this API key.

    Copy API key for future use

  5. Create your FaunaDB database

    Set the FaunaDB API key locally in your terminal

    # on mac
    export FAUNADB_SERVER_SECRET=YourFaunaDBKeyHere
    # on windows
    set FAUNADB_SERVER_SECRET=YourFaunaDBKeyHere

    Replace YourFaunaDBSecretHere with the value of the secret that you copied in the previous step.

    Add the /scripts/bootstrap-fauna-database.js to the root directory of the project. This is an idempotent script that you can run one million times and have the same result (one todos database)

    Next up, add the bootstrap command to npm scripts in your package.json file

    {
      "scripts": {
        "bootstrap": "node ./scripts/bootstrap-fauna-database.js"
      }
    }

    Now we can run the bootstrap command to setup our Fauna database in our FaunaDB account.

    npm run bootstrap

    If you log in to the FaunaDB dashboard you will see your todo database.

3. Create a function

Now, let’s create a function for our app and wire that up to run locally.

The functions in our project are going to live in a /functions folder. You can set this to whatever you'd like but we like the /functions convention.

Anatomy of a Lambda function

All AWS Lambda functions have the following signature:

exports.handler = (event, context, callback) => {
  // "event" has information about the path, body, headers, etc. of the request
  console.log('event', event)
  // "context" has information about the lambda environment and user details
  console.log('context', context)
  // The "callback" ends the execution of the function and returns a response back to the caller
  return callback(null, {
    statusCode: 200,
    body: JSON.stringify({
      data: '⊂◉‿◉つ'
    })
  })
}

We are going to use the faunadb npm package to connect to our Fauna Database and create an item.

Setting up functions for local development

Let's rock and roll.

  1. Create a ./functions directory

    # make functions directory
    mdkir functions
  2. Install netlify-lambda

    Netlify lambda is a tool for locally emulating the serverless function for development and for bundling our serverless function with third party npm modules (if we are using those)

    npm i netlify-lambda --save-dev
    

    To simulate our function endpoints locally, we need to setup a proxy for webpack to use.

    In package.json add:

    {
      "name": "react-lambda",
      ...
      "proxy": {
        "/.netlify/functions": {
          "target": "http://localhost:9000",
          "pathRewrite": {
            "^/\\.netlify/functions": ""
          }
        }
      }
    }

    This will proxy requests we make to /.netlify/functions to our locally-running function server at port 9000.

  3. Add our start & build commands

    Let's go ahead and add our start & build command to npm scripts in package.json. These will let us run things locally and give a command for Netlify to build our app and functions when we are ready to deploy.

    We are going to be using the npm-run-all npm module to run our frontend and backend in parallel in the same terminal window.

    So install it!

    npm install npm-run-all --save-dev
    

    About npm start

    The start:app command will run react-scripts start to run our react app

    The start:server command will run netlify-lambda serve functions -c ./webpack.config.js to run our function code locally. The -c webpack-config flag lets us set a custom webpack config to fix a module issue with FaunaDB module.

    Running npm start in our terminal will run npm-run-all --parallel start:app start:server to fire them both up at once.

    About npm build

    The build:app command will run react-scripts build to run our React app.

    The build:server command will run netlify-lambda build functions -c ./webpack.config.js to run our function code locally.

    Running npm run build in our terminal will run npm-run-all --parallel build:** to fire them both up at once.

    Your package.json should look like

    {
      "name": "netlify-fauna",
      "scripts": {
        "👇 ABOUT-bootstrap-command": "💡 scaffold and setup FaunaDB #",
        "bootstrap": "node ./scripts/bootstrap-fauna-database.js",
        "👇 ABOUT-start-command": "💡 start the app and server #",
        "start": "npm-run-all --parallel start:app start:server",
        "start:app": "react-scripts start",
        "start:server": "netlify-lambda serve functions -c ./webpack.config.js",
        "👇 ABOUT-prebuild-command": "💡 before 'build' runs, run the 'bootstrap' command #",
        "prebuild": "echo 'setup faunaDB' && npm run bootstrap",
        "👇 ABOUT-build-command": "💡 build the react app and the serverless functions #",
        "build": "npm-run-all --parallel build:**",
        "build:app": "react-scripts build",
        "build:functions": "netlify-lambda build functions -c ./webpack.config.js",
      },
      "dependencies": {
        "faunadb": "^0.2.2",
        "react": "^16.4.0",
        "react-dom": "^16.4.0",
        "react-scripts": "1.1.4"
      },
      "devDependencies": {
        "netlify-lambda": "^0.4.0",
        "npm-run-all": "^4.1.3"
      },
      "proxy": {
        "/.netlify/functions": {
          "target": "http://localhost:9000",
          "pathRewrite": {
            "^/\\.netlify/functions": ""
          }
        }
      }
    }
    
  4. Install FaunaDB and write the create function

    We are going to be using the faunadb npm module to call into our todos index in FaunaDB.

    So install it in the project.

    npm i faunadb --save

    Then create a new function file in /functions called todos-create.js

    /* code from functions/todos-create.js */
    import faunadb from 'faunadb' /* Import faunaDB sdk */
    
    /* configure faunaDB Client with our secret */
    const q = faunadb.query
    const client = new faunadb.Client({
      secret: process.env.FAUNADB_SECRET
    })
    
    /* export our lambda function as named "handler" export */
    exports.handler = (event, context, callback) => {
      /* parse the string body into a useable JS object */
      const data = JSON.parse(event.body)
      console.log("Function `todo-create` invoked", data)
      const todoItem = {
        data: data
      }
      /* construct the fauna query */
      return client.query(q.Create(q.Ref("classes/todos"), todoItem))
      .then((response) => {
        console.log("success", response)
        /* Success! return the response with statusCode 200 */
        return callback(null, {
          statusCode: 200,
          body: JSON.stringify(response)
        })
      }).catch((error) => {
        console.log("error", error)
        /* Error! return the error with statusCode 400 */
        return callback(null, {
          statusCode: 400,
          body: JSON.stringify(error)
        })
      })
    }

4. Connect the function to the frontend app

Inside of the React app, we can now wire up the /.netlify/functions/todos-create endpoint to an AJAX request.

// Function using fetch to POST to our API endpoint
function createTodo(data) {
  return fetch('/.netlify/functions/todos-create', {
    body: JSON.stringify(data),
    method: 'POST'
  }).then(response => {
    return response.json()
  })
}

// Todo data
const myTodo = {
  title: 'My todo title',
  completed: false,
}

// create it!
createTodo(myTodo).then((response) => {
  console.log('API response', response)
  // set app state
}).catch((error) => {
  console.log('API error', error)
})

Requests to /.netlify/function/[Function-File-Name] will work seamlessly on localhost and on the live site because we are using the local proxy with webpack.

We will be skipping over the rest of the frontend parts of the app because you can use whatever framework you'd like to build your application.

All the demo React frontend code is available here.

5. Finishing the backend Functions

So far we have created our todo-create function and we've seen how we make requests to our live function endpoints. It's now time to add the rest of our CRUD functions to manage our todos.

  1. Read Todos by ID

    Then create a new function file in /functions called todos-read.js

    /* code from functions/todos-read.js */
    import faunadb from 'faunadb'
    import getId from './utils/getId'
    
    const q = faunadb.query
    const client = new faunadb.Client({
      secret: process.env.FAUNADB_SECRET
    })
    
    exports.handler = (event, context, callback) => {
      const id = getId(event.path)
      console.log(`Function 'todo-read' invoked. Read id: ${id}`)
      return client.query(q.Get(q.Ref(`classes/todos/${id}`)))
      .then((response) => {
        console.log("success", response)
        return callback(null, {
          statusCode: 200,
          body: JSON.stringify(response)
        })
      }).catch((error) => {
        console.log("error", error)
        return callback(null, {
          statusCode: 400,
          body: JSON.stringify(error)
        })
      })
    }
  2. Read All Todos

    Then create a new function file in /functions called todos-read-all.js

    /* code from functions/todos-read-all.js */
    import faunadb from 'faunadb'
    
    const q = faunadb.query
    const client = new faunadb.Client({
      secret: process.env.FAUNADB_SECRET
    })
    
    exports.handler = (event, context, callback) => {
      console.log("Function `todo-read-all` invoked")
      return client.query(q.Paginate(q.Match(q.Ref("indexes/all_todos"))))
      .then((response) => {
        const todoRefs = response.data
        console.log("Todo refs", todoRefs)
        console.log(`${todoRefs.length} todos found`)
        // create new query out of todo refs. http://bit.ly/2LG3MLg
        const getAllTodoDataQuery = todoRefs.map((ref) => {
          return q.Get(ref)
        })
        // then query the refs
        return client.query(getAllTodoDataQuery).then((ret) => {
          return callback(null, {
            statusCode: 200,
            body: JSON.stringify(ret)
          })
        })
      }).catch((error) => {
        console.log("error", error)
        return callback(null, {
          statusCode: 400,
          body: JSON.stringify(error)
        })
      })
    }
  3. Update todo by ID

    Then create a new function file in /functions called todos-update.js

    /* code from functions/todos-update.js */
    import faunadb from 'faunadb'
    import getId from './utils/getId'
    
    const q = faunadb.query
    const client = new faunadb.Client({
      secret: process.env.FAUNADB_SECRET
    })
    
    exports.handler = (event, context, callback) => {
      const data = JSON.parse(event.body)
      const id = getId(event.path)
      console.log(`Function 'todo-update' invoked. update id: ${id}`)
      return client.query(q.Update(q.Ref(`classes/todos/${id}`), {data}))
      .then((response) => {
        console.log("success", response)
        return callback(null, {
          statusCode: 200,
          body: JSON.stringify(response)
        })
      }).catch((error) => {
        console.log("error", error)
        return callback(null, {
          statusCode: 400,
          body: JSON.stringify(error)
        })
      })
    }
  4. Delete by ID

    Then create a new function file in /functions called todos-delete.js

    /* code from functions/todos-delete.js */
    import faunadb from 'faunadb'
    import getId from './utils/getId'
    
    const q = faunadb.query
    const client = new faunadb.Client({
      secret: process.env.FAUNADB_SECRET
    })
    
    exports.handler = (event, context, callback) => {
      const id = getId(event.path)
      console.log(`Function 'todo-delete' invoked. delete id: ${id}`)
      return client.query(q.Delete(q.Ref(`classes/todos/${id}`)))
      .then((response) => {
        console.log("success", response)
        return callback(null, {
          statusCode: 200,
          body: JSON.stringify(response)
        })
      }).catch((error) => {
        console.log("error", error)
        return callback(null, {
          statusCode: 400,
          body: JSON.stringify(error)
        })
      })
    }
  5. Delete batch todos

    Then create a new function file in /functions called todos-delete-batch.js

    /* code from functions/todos-delete-batch.js */
    import faunadb from 'faunadb'
    import getId from './utils/getId'
    
    const q = faunadb.query
    const client = new faunadb.Client({
      secret: process.env.FAUNADB_SECRET
    })
    
    exports.handler = (event, context, callback) => {
      const data = JSON.parse(event.body)
      console.log('data', data)
      console.log("Function `todo-delete-batch` invoked", data.ids)
      // construct batch query from IDs
      const deleteAllCompletedTodoQuery = data.ids.map((id) => {
        return q.Delete(q.Ref(`classes/todos/${id}`))
      })
      // Hit fauna with the query to delete the completed items
      return client.query(deleteAllCompletedTodoQuery)
      .then((response) => {
        console.log("success", response)
        return callback(null, {
          statusCode: 200,
          body: JSON.stringify(response)
        })
      }).catch((error) => {
        console.log("error", error)
        return callback(null, {
          statusCode: 400,
          body: JSON.stringify(error)
        })
      })
    }

After we deploy all these functions, we will be able to call them from our frontend code with these fetch calls:

/* Frontend code from src/utils/api.js */
/* Api methods to call /functions */

const create = (data) => {
  return fetch('/.netlify/functions/todos-create', {
    body: JSON.stringify(data),
    method: 'POST'
  }).then(response => {
    return response.json()
  })
}

const readAll = () => {
  return fetch('/.netlify/functions/todos-read-all').then((response) => {
    return response.json()
  })
}

const update = (todoId, data) => {
  return fetch(`/.netlify/functions/todos-update/${todoId}`, {
    body: JSON.stringify(data),
    method: 'POST'
  }).then(response => {
    return response.json()
  })
}

const deleteTodo = (todoId) => {
  return fetch(`/.netlify/functions/todos-delete/${todoId}`, {
    method: 'POST',
  }).then(response => {
    return response.json()
  })
}

const batchDeleteTodo = (todoIds) => {
  return fetch(`/.netlify/functions/todos-delete-batch`, {
    body: JSON.stringify({
      ids: todoIds
    }),
    method: 'POST'
  }).then(response => {
    return response.json()
  })
}

export default {
  create: create,
  readAll: readAll,
  update: update,
  delete: deleteTodo,
  batchDelete: batchDeleteTodo
}

Wrapping Up

That's it. You now have your own CRUD API using Netlify Functions and FaunaDB.

As you can see, functions can be extremely powerful when combined with a cloud database!

The sky is the limit on what you can build with the JAMstack and we'd love to hear about what you make. Give us a shout about it on Twitter

Next Steps

This example can be improved with users/authentication. Next steps to build out the app would be:

  • Add in the concept of users for everyone to have their own todo list
  • Wire up authentication using the JSON web token-based Netlify Identity
  • Add in due dates to todos and wire up Functions to notify users via email/SMS
  • File for IPO?

netlify-faunadb-example's People

Contributors

davidwells avatar lambrospetrou avatar laurajodz avatar ryannielson avatar swyxio avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

netlify-faunadb-example's Issues

Works without setting faunadb key?

This seems like one of those obvious bits of information that's just not coming to me. I used the 1-click deploy button to deploy to netlify, but actually didn't need to follow any of the steps in the readme to get the app working.

I don't have a faunadb account, there's not environment variable file, and no environment variables in the Netlify UI.

Is it suppsoed to work just right out of the box? And also, how is that happening? because that's very cool.

I needed to set FAUNADB_SERVER_SECRET as well as FAUNADB_SECRET for the app to work

The FAUNADB_SECRET was needed to create the table in faunadb, but I only got unauthorized errors when running the app. Looking in the code I found it is using the FAUNADB_SERVER_SECRET environment variable to actually make the calls, once I set that as well then the application ran and I could create todo entries. The functions/todos-real-all.js contains the following code for example.

const client = new faunadb.Client({
secret: process.env.FAUNADB_SERVER_SECRET
})

Easy fix is to set both env variables (e.g. in windows):
set FAUNADB_SECRET= (admin key)
set FAUNADB_SERVER_SECRET= (server key)

The keys were set at the in the fauna cloud dashboard: https://dashboard.fauna.com/keys/@db/

So all that is needed is for the tutorial to be updated to instruct both environmental variables to be set. First time using netlify and first time using faunadb so good if it works out of the box as a good demo.

◈ Empty args assigned, this is an internal Netlify Dev bug, please report your settings and scripts so we can improve

New Post:

Problem:
image

Steps to recreate:

  1. Deployed by clicking on the button
  2. Create a new database on FaunaDB
  3. Clone the repo created from deploying
  4. npm install
  5. npm audit fix
  6. Ran $ export FAUNADB_SERVER_SECRET=[KEY]
  7. npm run bootstrap

Running npm run bootstrap caused this error:
image

So I ran netlify link.

That went well, but running npm start next caused the same error:
image

> [email protected] start /Users/lpnotes/Desktop/projects/bc
> netlify dev

◈ Netlify Dev ◈
◈ Injected addon env var:  FAUNADB_ADMIN_SECRET
◈ Injected addon env var:  FAUNADB_CLIENT_SECRET
◈ Empty args assigned, this is an internal Netlify Dev bug, please report your settings and scripts so we can improve
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! [email protected] start: `netlify dev`
npm ERR! Exit status 1
npm ERR! 
npm ERR! Failed at the [email protected] start script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

npm ERR! A complete log of this run can be found in:
npm ERR!     /Users/lpnotes/.npm/_logs/2020-08-25T02_53_25_800Z-debug.log

The full debug log:

0 info it worked if it ends with ok
1 verbose cli [
1 verbose cli   '/usr/local/Cellar/node/12.9.1/bin/node',
1 verbose cli   '/usr/local/bin/npm',
1 verbose cli   'start'
1 verbose cli ]
2 info using [email protected]
3 info using [email protected]
4 verbose run-script [ 'prestart', 'start', 'poststart' ]
5 info lifecycle [email protected]~prestart: [email protected]
6 info lifecycle [email protected]~start: [email protected]
7 verbose lifecycle [email protected]~start: unsafe-perm in lifecycle true
8 verbose lifecycle [email protected]~start: PATH: /usr/local/lib/node_modules/npm/node_modules/npm-lifecycle/node-gyp-bin:/Users/lpnotes/Desktop/projects/bc/node_modules/.bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/go/bin
9 verbose lifecycle [email protected]~start: CWD: /Users/lpnotes/Desktop/projects/bc
10 silly lifecycle [email protected]~start: Args: [ '-c', 'netlify dev' ]
11 silly lifecycle [email protected]~start: Returned: code: 1  signal: null
12 info lifecycle [email protected]~start: Failed to exec start script
13 verbose stack Error: [email protected] start: `netlify dev`
13 verbose stack Exit status 1
13 verbose stack     at EventEmitter.<anonymous> (/usr/local/lib/node_modules/npm/node_modules/npm-lifecycle/index.js:326:16)
13 verbose stack     at EventEmitter.emit (events.js:209:13)
13 verbose stack     at ChildProcess.<anonymous> (/usr/local/lib/node_modules/npm/node_modules/npm-lifecycle/lib/spawn.js:55:14)
13 verbose stack     at ChildProcess.emit (events.js:209:13)
13 verbose stack     at maybeClose (internal/child_process.js:1021:16)
13 verbose stack     at Process.ChildProcess._handle.onexit (internal/child_process.js:283:5)
14 verbose pkgid [email protected]
15 verbose cwd /Users/lpnotes/Desktop/projects/bc
16 verbose Darwin 18.7.0
17 verbose argv "/usr/local/Cellar/node/12.9.1/bin/node" "/usr/local/bin/npm" "start"
18 verbose node v12.9.1
19 verbose npm  v6.10.3
20 error code ELIFECYCLE
21 error errno 1
22 error [email protected] start: `netlify dev`
22 error Exit status 1
23 error Failed at the [email protected] start script.
23 error This is probably not a problem with npm. There is likely additional logging output above.
24 verbose exit [ 1, true ]

Old post:

After clicking on the button to deploy this to Netlify and creating the FaunaDB key, we were getting the following error:

image

Can I add to the README.md the instruction to install the netlify CLI? https://docs.netlify.com/cli/get-started/

Issue with formidable package inside of faunadb npm module

I found an issue when trying to run this where I receive the error:

WARNING in ../node_modules/formidable/lib/incoming_form.js 1:43-50
Critical dependency: require function is used in a way in which dependencies cannot be statically extracted

The fix for me was to add a webpack.functions.js file to the root with the following:

const webpack = require('webpack');

module.exports = {
  plugins: [ new webpack.DefinePlugin({ "global.GENTLY": false }) ]
};

In package.json the serve and build commands needed to add this per the documentation.

"dev:server": "netlify-lambda serve functions --config ./webpack.functions.js",
"netlify:build:lambda": "netlify-lambda build functions --config ./webpack.functions.js"

This allowed this to compile properly without the error. Not sure if something changed in the formidable package or if anyone else has come across this.

Confused re tutorial

The tutorial https://www.netlify.com/blog/2018/07/09/building-serverless-crud-apps-with-netlify-functions--faunadb/#1-create-react-app looked excellent, but in the end I spent a long time not going far. Help requested please.

  1. I cloned the repo and followed the the 1st section, "Setup & Run Locally". As this already had a React app, all the functions etc, it seemed to include all the steps in the tutorial below. But after step5, npm start, the browser showed 3 errors and the fauna dashboard indicated no db creation.

  2. So I then decided to start from the tutorial, only to have the same error as reported in "Error: Cannot find module 'faunadb' #3". When I then used "npm install faunadb -save", this went fine, but after "npm run bootstrap" only index 'all-todos' and class 'todos' appeared in the faunadb dashboard, no database. So this seemed wrong. But the answer given in error #3 above did not make sense, as said above, because the tutorial included steps already incorporated in the copied repo above.

Where am I missing the boat here?

UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'statusCode' of undefined

Hi, thanks for this great little example, it helped me get started quickly and get better understanding of how to use Netlify's implementation of Lambda.

Something I wanted to share as well is I've set up the secret in .env and added export $(cat .env | xargs) && to the start script which is handy for local dev.

As to the error - I find that if you unwrap your lambda functions return responses from the callback objects the error is fixed:
console.log('error', error) return { statusCode: 200, body: JSON.stringify(ret) }

I thought sharing this might help someone bootstrap this project. Thanks!

Follow AWS Lambda best practices

I recently tried using faunadb inside Netlify Functions, and I noticed about 25% of the time, the functions were returning a 502 with this error:

12:36:29 PM: 2020-02-13T11:36:29.083Z	00e2d3c8-39f5-48e4-b5c2-4341629d4ef9	ERROR	FetchError: request to https://db.fauna.com/ failed, reason: socket hang up
    at ClientRequest.<anonymous> (/var/task/node_modules/node-fetch/lib/index.js:1455:11)
    at ClientRequest.emit (events.js:223:5)
    at TLSSocket.socketOnEnd (_http_client.js:440:9)
    at TLSSocket.emit (events.js:228:7)
    at endReadableNT (_stream_readable.js:1185:12)
    at processTicksAndRejections (internal/process/task_queues.js:81:21) {
  message: 'request to https://db.fauna.com/ failed, reason: socket hang up',
  type: 'system',
  errno: 'ECONNRESET',
  code: 'ECONNRESET'
}

I found this relevant issue, which links to this article around how to use FaunaDB in AWS Lambda functions. The short version is: the calls to instantiate the connection should be done inside the handler, instead of outside, to prevent the environment from reusing a connection that has closed.

As an example, here's how the first function should change, to avoid the issue I was running into:

/* Import faunaDB sdk */
const faunadb = require('faunadb')

-/* configure faunaDB Client with our secret */
-const q = faunadb.query
-const client = new faunadb.Client({
-  secret: process.env.FAUNADB_SERVER_SECRET
-})

/* export our lambda function as named "handler" export */
exports.handler = async (event, context) => {
+  /* configure faunaDB Client with our secret */
+  const q = faunadb.query
+  const client = new faunadb.Client({
+    secret: process.env.FAUNADB_SERVER_SECRET
+  })
+
  /* parse the string body into a useable JS object */
  const data = JSON.parse(event.body)
  console.log('Function `todo-create` invoked', data)
  const todoItem = {
    data: data
  }
  /* construct the fauna query */
  return client.query(q.Create(q.Ref('classes/todos'), todoItem))
    .then((response) => {
      console.log('success', response)
      /* Success! return the response with statusCode 200 */
      return {
        statusCode: 200,
        body: JSON.stringify(response)
      }
    }).catch((error) => {
      console.log('error', error)
      /* Error! return the error with statusCode 400 */
      return {
        statusCode: 400,
        body: JSON.stringify(error)
      }
    })
}

I expect that this will be an issue for just about anyone that tries following this example, and I was pretty close to just giving up and rolling a Node server when I found the issue 😅so it'd be awesome if you could update the functions in the example!

Error: Cannot find module 'faunadb'

Thank you for the tutorial.

I got stuck when I ran npm run bootstrap. This error showed up in the terminal:

> node ./scripts/bootstrap-fauna-database.js

internal/modules/cjs/loader.js:583
    throw err;
    ^

Error: Cannot find module 'faunadb'
    at Function.Module._resolveFilename (internal/modules/cjs/loader.js:581:15)
    at Function.Module._load (internal/modules/cjs/loader.js:507:25)
    at Module.require (internal/modules/cjs/loader.js:637:17)
    at require (internal/modules/cjs/helpers.js:22:18)
    at Object.<anonymous> (C:\Users\Andrew\Documents\webDev\netlify-db-example\scripts\bootstrap-fauna-database.js:3:17)
    at Module._compile (internal/modules/cjs/loader.js:689:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:700:10)
    at Module.load (internal/modules/cjs/loader.js:599:32)
    at tryModuleLoad (internal/modules/cjs/loader.js:538:12)
    at Function.Module._load (internal/modules/cjs/loader.js:530:3)
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! [email protected] bootstrap: `node ./scripts/bootstrap-fauna-database.js`
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the [email protected] bootstrap script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

Is there something I overlooked in the tutorial?

Stuck waiting for localhost:34567...

When I delete the package-lock.json and then run npm install (to get the latest version of netlify-cli), the npm run start script no longer works. It gets stuck on Waiting for localhost:34567:

image

Steps:

  • Clone the repository
  • Remove package-lock.json
  • Run npm install
  • Run npm start

Is there some breaking change with newer versions of the Netlify CLI that causes this not to work? Any thoughts on what to do? Here is a fork with a deleted & reinstalled package-lock.json: https://github.com/FinnWoelm/netlify-faunadb-example

Environment variables are potentially vulnerable to a malicious deploy preview

I stumbled upon this tutorial while attempting to design a similar app. I'm concerned about the potential security implications of including Netlify Functions in an open source project.

If deploy previews are enabled for PRs, can a contributor submit a malicious PR to expose process.env?

We seem to have come across this in our similar project:

screen shot 2019-01-09 at 12 05 14 pm

I'm excited about using Netlify Functions to proxy API requests, and I'm curious about any thoughts and recommendations on this. Does Netlify recommend disabling deploy previews or otherwise configuring them in an open source project that utilizes Netlify Functions?

Puzzling out UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'statusCode' of undefined

@abtx says he has a solution for this error #9 , but I something of a js newbie and don't get it.

If my code is this:

exports.handler = (event, context, callback) => {
  const data = JSON.parse(event.body)
  const id = getId(event.path)
  console.log(`Function 'todo-update' invoked. update id: ${id}`)
  return client.query(q.Update(q.Ref(`classes/todos/${id}`), {data}))
    .then((response) => {
      console.log('success', response)
      return callback(null, {
        statusCode: 200,
        body: JSON.stringify(response)
      })
    }).catch((error) => {
      console.log('error', error)
      return callback(null, {
        statusCode: 400,
        body: JSON.stringify(error)
      })
    })
}

How do I "unwrap your lambda functions return responses from the callback objects the error is fixed:
console.log('error', error) return { statusCode: 200, body: JSON.stringify(ret) }"?

Solution for missing 'https' module / 500 response error

I spent quite a bit of time trying to get this working today, and kept getting a weird error when posting to the create-todo netlify function. I managed to trace down the solution, it appears to be a bug with the faunadb package (versions newer than 2.7.0).

fauna/faunadb-js#182

Reverting to 2.7.0 resolved the problem for me.

Error After Following README Instructions

I followed the instructions in the README and was able to sucsesfully get the application and FaunaDB talking to one another. i.e. I was able to run

npm run bootstrap 

and the collections/tables were created in my FaunaDB. However, if I run npm start and navigate to http://localhost:3000/, I receive a javascript error in the console

Uncaught (in promise) SyntaxError: JSON.parse: unexpected character at line 1 column 1 of the JSON data

If I attempt to add a todo I get an XHR error in my console

POSThttp://localhost:3000/.netlify/functions/todos-create [HTTP/1.1 404 Not Found 4ms]
An API error occurred SyntaxError: JSON.parse: unexpected character at line 1 column 1 of the JSON data

I'm unsure if this is bitrot, or if there's some subtle step I'm missing. If someone can confirm this project works as is (or tell me the additional steps needed to get it running) that would go a long way towards getting things up and running myself.

Screen Shot 2020-09-24 at 2 14 11 PM

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.