플레이 리스트 : https://www.youtube.com/playlist?list=PLl-K7zZEsYLmnJ_FpMOZgyg6XcIGBu2OX


주요 동영상 : https://youtu.be/LOeioOKUKI8

위) firebase-tools 글로벌로 설치

image
image
image
image

위) firebase.json 수정을 통해 header를 넣을수도 있고 reroute도 할수있다.

image

위) timestamp로 접속하는 경우 firebase functions app으로 reroute하는 경우

image

위) firebase functions https 모든 요청을 express app이 처리하게 만든 경우

image

위) localhost로 확인

image

위) cache를 이용 사용속도를 올리는 방법

image

위) 모든 http 접근을 firebase functions app이 처리하게 하는 경우

image

위) cache를 설정한경우

image

위) firebase cloud functions에 deploy하는 경우

image

위) html template 화일은 functions folder내의 views안에 한다.

image
image

위) template hbs를 사용하는 경우

image

위) statics화일의 경우 public에 넣어놓으면 html에서는 화일명 만으로도 접근 가능하게 된다.

image

.

.

.

.

참고사항)

예제코드 : https://github.com/firebase/functions-samples

original source : https://medium.com/@GaryHarrower/working-with-stripe-webhooks-firebase-cloud-functions-5366c206c6c

firebase functions 와 stripe webhook연결

Now lets head over to our terminal and create a new directory for our project.

$ mkdir stripe-webhooks
$ cd stripe-webhooks

We then need to install the firebase-tools package globally using NPM.

(아래는 firebase-tool설치)

$ npm install -g firebase-tools

Now we have firebase-tools installed, we should login to our firebase account and initiate a new project in our project directory. You will get a choice of which services you would like to use — you only need to select ‘Functions’ here for now.

(아래는 firebase 사용전 초기 작업)

$ firebase login
$ firebase init

Let’s move into the functions folder (created with firebase init) and make sure we have the latest version of firebase-functions and firebase-admin installed. firebase-functions is used for running the actual cloud functions and firebase-admin is used to access the Realtime Database.

$ cd functions/
$ npm install firebase-functions@latest firebase-admin@latest --save

Let’s create a new function called events to handle our endpoint. We’ll start off simple with a basic function that returns a string to let us generate the URL we need to supply our Stripe account with.

const functions = require('firebase-functions');exports.events = functions.https.onRequest((request, response) => {
 response.send("Endpoint for Stripe Webhooks!");
});

We can then deploy our function and get our endpoint (Function URL in output in screenshot).

firebase deploy --only functions

(아래는 stripe에 webhook 만드는 과정)

Now we have our Cloud Function URL, we can head over to the webhooks section of the Stripe dashboard. We then want to + Add Endpoint, and enter our URL into the URL field. You can select the types of events to be sent, but for now we will just stick to all event types.

Once you create the endpoint, take note of your ‘Signing secret’ — we’ll need that to verify the request send to our function.

While we’re in our Stripe Dashboard, let’s head over to the API Keys section to generate and take not of the API key we’re going to use.

You should create a restricted API key and only assign permissions you’re going to need in your firebase project. For example, if you’re only going to read customer objects, you can specify only Customers when creating the key.

Now we have our signing secret and our API key, let’s add them to our Firebase project as environment variables so we don’t need to check them in to any source control.

$ firebase functions:config:set 
   keys.webhooks="your_restricted_key"
   keys.signing="your_signing_key"

That’s our setup complete — We’re now ready to write some code! I’m going to be using examples from Firebase and Stripe, so if there’s anything you would like to dive deeper into, you can use the following links:

To start with, we’re going to need the Stripe NPM package, so let’s go ahead and install that:

(stripe 라이브러리 설치)

$ npm install --save stripe

We added our API keys to our Firebase config, so we can access them using functions.config() (For example: functions.config().keys.webhooks will return our keys.webhooks string we added).

We will then require the Stripe package in our functions index.js. We will also bring in our Signing key to our application (endpointSecret).

const functions = require(‘firebase-functions’);
const stripe = require(‘stripe’)(functions.config().keys.webhooks);
const endpointSecret = functions.config().keys.signing;exports.events = functions.https.onRequest((request, response) => {
 response.send(“Endpoint for Stripe Webhooks!”);
});

Note: Stripe marks a webhook as successful only when your function returns a success (2xx) response. If it receives anything else, such as a 400 or 500, then it marks it as failed, and will try again.

We can use our signing key to verify that a request has actually come from Stripe, and not an unauthorized attacker. The stripe package has a method (stripe.webhooks.constructEvent) which we can use to verify the request. We can also use a Try Catch to return an error if the request fails verification.

// Get the signature from the request header
let sig = request.headers["stripe-signature"];// Verify the request against our endpointSecret
let event = stripe.webhooks.constructEvent(request.rawBody, sig, endpointSecret);

Note: We need to use the original request body otherwise the verification will fail, so we must use Firebase Function’s request.rawBody, instead of the usual request.body.

As mentioned, we can wrap this in a Try Catch to catch any failed requests.

let sig = request.headers["stripe-signature"];try {
 let event = stripe.webhooks.constructEvent(request.rawBody, sig, endpointSecret);
} catch (err) {
 return response.status(400).end();
}

Now we have our valid events, let’s save them to our Firebase Realtime Database.

We can do this by using the firebase-admin database methods. We’re going to be using the .push() method to create a new entry in our database.

const admin = require('firebase-admin');
admin.initializeApp();...return admin.database().ref('/events').push(event)
 .then((snapshot) => {
   return response.json({ received: true, ref: snapshot.ref.toString() });
 })
 .catch((err) => {
   console.error(err);
   return response.status(500).end();
 });

Let’s break this code down a bit.

  • Ref is the path in the database we would like to save our new entry to. This can be whatever you like — i’ve chosen so save my events in the /events ref.
  • Push(event)- event is the variable we’re saving the response from the constructEvent method we called. This is an object with all of our event info
  • Response.json — We respond with a valid json object — this tells Stripe that the webhook event was received and we’re happy we’ve processed it, so mark it as complete.
  • Catch — In case something goes wrong while we’re saving the event to the database, we return an error 500 to tell Stripe that something went wrong. Stripe will then retry sending the event. There are ways you could incorporate this into the Try Catch we have, although I like having the differentiation of errors.

Now we should deploy our function again, then we can test it out.

$ firebase deploy --only functions

Let’s head back over to the Stripe Dashboard Webhooks area, select our endpoint where we can now ‘Send test webhook’.

Select an event type and hit ‘Send test webhook’ — all going well, we get a successful response, and our event is now saved in our database!

That’s it in terms of saving. Now you have endless possibilities of cool things to do with your data. For further reading, you could explore the different triggers Cloud Functions can use. You can run another function whenever anything is added to your database. The example below would run any time a new event is saved to our database. We could now check the event type, and if it’s a successful charge, update our Realtime database to increase our daily revenue on our live dashboard…

You can read more about database events here: https://firebase.google.com/docs/functions/database-events

I hope this was useful. Please leave any feedback or questions – I’m always learning and really appreciate any comments you may have.

You can find the completed code over on Github — https://github.com/GaryH21/Stripe-Webhooks-Tutorial

Happy building!

firebase functions official examples

https://github.com/firebase/functions-samples

onCreate 을 사용하는 경우 새로 생성된 doc과 context가 되돌려 진다.

doc( DocumentSnapshot ) https://cloud.google.com/nodejs/docs/reference/firestore/0.11.x/DocumentSnapshot

promise error catch 하는 방법

admin.storage().bucket().file('path/to/file').download({
    destination: 'temporary/file/path'
}).then(() => {
    // Change the file and upload it.
}).catch(err => {
    // Handle error(create file) if the file does not exist
})

firestore경로에 있는 문자열을 parameter로 사용하는 방법

exports.observeCreate = functions.firestore.document('/pathOne/{id}/pathTwo/{anotherId}').onCreate((snapshot, context) => {
  console.log(context.params);
  console.log(context.params.id);
});

notification and nested 작업

exports.observeCreate = functions.firestore.document('/pathOne/{id}/pathTwo/{anotherId}').onCreate(event => {
  console.log(event.params);

  //event prints out data but params undefined...
  const data = event.data()

  var id = event.params.id;

  return admin.firestore().collection('path').doc(id).get().then(doc => {
    const data = doc.data();
    var fcmToken = data.fcmToken;

    var message = {
      notification: {
        title: "x",
        body: "x"
      },
      token: fcmToken
    };

    admin.messaging().send(message)
      .then((response) => {
        console.log('Successfully sent message:', response);
        return;
      })
      .catch((error) => {
        console.log('Error sending message:', error);
        return;
      });

      return;
  })
})

device에 notification 보내기

exports.sendNotification = 
functions.firestore.document('Users/{userId}/Notifications/{notificationId}')
.onWrite((c hange, context) =>{

const userId = context.params.userId;
const notificationId = context.params.notificationId;

console.log('The User id is : ', userId);
console.log('The Notification id is : ', notificationId);

// ref to the parent document

return admin.firestore().collection("Users").doc(userId).collection("Token").doc(userId).get().then(queryResult => {
    const tokenId = queryResult.data().deviceToken;

    //const toUser = admin.firestore().collection("Users").doc(userId).collection("Notifications").doc(notificationId).get();

        const notificationContent = {
                notification:{
                    title: "/*App name */",
                    body: "You have a new Comment!",
                    icon: "default",
                    click_action: "/*Package */_TARGET_NOTIFICATION"
            }
        };

        return admin.messaging().sendToDevice(tokenId, notificationContent).then(result => {
            console.log("Notification sent!");
            //admin.firestore().collection("notifications").doc(userEmail).collection("userNotifications").doc(notificationId).delete();
        });

   });

});

onwrite에 반응해서 특정topic으로 구분된 그룹에게 notification 보내기

exports.sendNotification = functions.firestore
.document('chats/{chatID}')
.onWrite((change, context) => {
  // Get an object representing the document
   console.log('chat triggered');
  // perform desired operations ...

    // See documentation on defining a message payload.
    var message = {
      notification: {
        title: 'Hello World!',
        body: 'Hello World!'
      },
      topic: context.params.chatID.   //<- If you are using a CF version under v1.0 don't change here
    };

    // Send a message to devices subscribed to the provided topic.
    return admin.messaging().send(message).  //<- return the resulting Promise
      .then((response) => {
        // Response is a message ID string.
        console.log('Successfully sent message:', response);
        return true;    //<- return a value
      })
      .catch((error) => {
        console.log('Error sending message:', error);
        //return.  <- No need to return here
      });

});

firestore에서 data fetch해서 가져오기 

firestore.collection('products').doc(payment.product).get().then(product => {
    if (!product.exists) {
        console.log('No such product!');
    } else {
        console.log('Document data:', product.data());
    }
})

function을 이용해서 firestore에 document만들기

exports.createProfile = functions.auth.user().onCreate((user) => {

  var userObject = {
     displayName : user.displayName,
     email : user.email,
  };

  return admin.firestore().doc('users/'+user.uid).set(userObject);

});

firebase auth에 새로운 유저가 생성되는 경우에 따른 작업을 만들때

export const accountCreate = functions.auth.user().onCreate(user => {
    console.log(user.data);
    userDoc = {'email' = user.data.email, 
               'displayName' = user.data.displayName}
    admin.firestore().collection('users').doc(user.data.uid)
    .set(userDoc).then(writeResult => {
        console.log('User Created result:', writeResult);
        return;
    }).catch(err => {
       console.log(err);
       return;
    });
});

firebase functions official examples

https://github.com/firebase/functions-samples

onCreate 을 사용하는 경우 새로 생성된 doc과 context가 되돌려 진다.

doc( DocumentSnapshot ) https://cloud.google.com/nodejs/docs/reference/firestore/0.11.x/DocumentSnapshot

promise error catch 하는 방법

admin.storage().bucket().file('path/to/file').download({
    destination: 'temporary/file/path'
}).then(() => {
    // Change the file and upload it.
}).catch(err => {
    // Handle error(create file) if the file does not exist
})

firestore경로에 있는 문자열을 parameter로 사용하는 방법

exports.observeCreate = functions.firestore.document('/pathOne/{id}/pathTwo/{anotherId}').onCreate((snapshot, context) => {
  console.log(context.params);
  console.log(context.params.id);
});

notification and nested 작업

exports.observeCreate = functions.firestore.document('/pathOne/{id}/pathTwo/{anotherId}').onCreate(event => {
  console.log(event.params);

  //event prints out data but params undefined...
  const data = event.data()

  var id = event.params.id;

  return admin.firestore().collection('path').doc(id).get().then(doc => {
    const data = doc.data();
    var fcmToken = data.fcmToken;

    var message = {
      notification: {
        title: "x",
        body: "x"
      },
      token: fcmToken
    };

    admin.messaging().send(message)
      .then((response) => {
        console.log('Successfully sent message:', response);
        return;
      })
      .catch((error) => {
        console.log('Error sending message:', error);
        return;
      });

      return;
  })
})

device에 notification 보내기

exports.sendNotification = 
functions.firestore.document('Users/{userId}/Notifications/{notificationId}')
.onWrite((c hange, context) =>{

const userId = context.params.userId;
const notificationId = context.params.notificationId;

console.log('The User id is : ', userId);
console.log('The Notification id is : ', notificationId);

// ref to the parent document

return admin.firestore().collection("Users").doc(userId).collection("Token").doc(userId).get().then(queryResult => {
    const tokenId = queryResult.data().deviceToken;

    //const toUser = admin.firestore().collection("Users").doc(userId).collection("Notifications").doc(notificationId).get();

        const notificationContent = {
                notification:{
                    title: "/*App name */",
                    body: "You have a new Comment!",
                    icon: "default",
                    click_action: "/*Package */_TARGET_NOTIFICATION"
            }
        };

        return admin.messaging().sendToDevice(tokenId, notificationContent).then(result => {
            console.log("Notification sent!");
            //admin.firestore().collection("notifications").doc(userEmail).collection("userNotifications").doc(notificationId).delete();
        });

   });

});

onwrite에 반응해서 특정topic으로 구분된 그룹에게 notification 보내기

exports.sendNotification = functions.firestore
.document('chats/{chatID}')
.onWrite((change, context) => {
  // Get an object representing the document
   console.log('chat triggered');
  // perform desired operations ...

    // See documentation on defining a message payload.
    var message = {
      notification: {
        title: 'Hello World!',
        body: 'Hello World!'
      },
      topic: context.params.chatID.   //<- If you are using a CF version under v1.0 don't change here
    };

    // Send a message to devices subscribed to the provided topic.
    return admin.messaging().send(message).  //<- return the resulting Promise
      .then((response) => {
        // Response is a message ID string.
        console.log('Successfully sent message:', response);
        return true;    //<- return a value
      })
      .catch((error) => {
        console.log('Error sending message:', error);
        //return.  <- No need to return here
      });

});

firestore에서 data fetch해서 가져오기 

firestore.collection('products').doc(payment.product).get().then(product => {
    if (!product.exists) {
        console.log('No such product!');
    } else {
        console.log('Document data:', product.data());
    }
})

function을 이용해서 firestore에 document만들기

exports.createProfile = functions.auth.user().onCreate((user) => {

  var userObject = {
     displayName : user.displayName,
     email : user.email,
  };

  return admin.firestore().doc('users/'+user.uid).set(userObject);

});

firebase auth에 새로운 유저가 생성되는 경우에 따른 작업을 만들때

export const accountCreate = functions.auth.user().onCreate(user => {
    console.log(user.data);
    userDoc = {'email' = user.data.email, 
               'displayName' = user.data.displayName}
    admin.firestore().collection('users').doc(user.data.uid)
    .set(userDoc).then(writeResult => {
        console.log('User Created result:', writeResult);
        return;
    }).catch(err => {
       console.log(err);
       return;
    });
});

firebase cloud functions은 node js를 이용한 server없이 server기능을 이용할수 있게 해준다. 


Firebase functions ( javascript node.js를 기반으로 하고 있다)

관련자료)

Firebase functions official tutorials

https://www.youtube.com/playlist?list=PLl-K7zZEsYLkPZHe41m4jfAxUi0JjLgSM

1.화일 다운 로드 받아서 컴퓨터에 Node js v11 설치 (설치시 grpc 설치과정에서 문제 발생 이부분만 따로 또 설치)


2.컴퓨터에 sudo npm install -g firebase-tools 를 통해 firebase cli firebase-tools@6.0.1 설치


3.Visual studio code ( text editor ) 설치


4. firebase를 설치할 폴더를 만들어 그 폴더 안으로 이동


5. 터미널에 firebase login 을 실행

6. 터미널에 firebase init을 실행

npm을 통해 dependencies를 설치중 문제가 발생했었다. grpc설치에 문제 발생 이부분만 따로 다시 install했다.

visual studio에서 firebase를 위해 만들었던 폴더를 연다.

visual studio작업후에는 firebase 폴더안에 들어가서 firebase deploy를 실행한다.

firebase cloud functions은 node js를 이용한 server없이 server기능을 이용할수 있게 해준다. 


Firebase functions ( javascript node.js를 기반으로 하고 있다)

관련자료)

Firebase functions official tutorials

https://www.youtube.com/playlist?list=PLl-K7zZEsYLkPZHe41m4jfAxUi0JjLgSM

1.화일 다운 로드 받아서 컴퓨터에 Node js v11 설치 (설치시 grpc 설치과정에서 문제 발생 이부분만 따로 또 설치)


2.컴퓨터에 sudo npm install -g firebase-tools 를 통해 firebase cli firebase-tools@6.0.1 설치


3.Visual studio code ( text editor ) 설치


4. firebase를 설치할 폴더를 만들어 그 폴더 안으로 이동


5. 터미널에 firebase login 을 실행

6. 터미널에 firebase init을 실행

npm을 통해 dependencies를 설치중 문제가 발생했었다. grpc설치에 문제 발생 이부분만 따로 다시 install했다.

visual studio에서 firebase를 위해 만들었던 폴더를 연다.

visual studio작업후에는 firebase 폴더안에 들어가서 firebase deploy를 실행한다.

junecnol:

firebase cloud function basic “hello world”

my review point is 9 

firebase init

firebase deploy

getting a function endpoint link

다음 비디오 :  https://youtu.be/nezhsGvrhaI

여기에서는 console log에 출력, 확인하는 방법, query string을 request에 포함하는 방법