gwilcox019 / grace-serverless-3

1 stars 0 forks source link

What is your deepest secret? The API #19

Closed ghost closed 3 years ago

ghost commented 3 years ago

Week 3 Step 6 ⬤⬤⬤⬤⬤⬤◯◯◯ | 🕐 Estimated completion: 10-20 minutes

Can you keep a secret?

This week, you will be going through steps to set up a Twilio account and create an Azure function that texts your Twilio number.

✅ Task:

🚧 Test Your Work

To test your work, try texting a message to your Twilio number - you should receive a text message back that repeats your own message.

:question: How do I find my Twilio number? See your [phone numbers](https://www.twilio.com/console/phone-numbers/incoming).
❗ Example output? ![194569969_1687986154736022_4227041675617722938_n](https://user-images.githubusercontent.com/49426183/120210870-1e99ce80-c1e5-11eb-9619-3a812f6206a7.jpg) > Note: You might not get a text back on your phone because Twilio sometimes won't allow you to return a single variable as the entire body, but as long as the code passes the test, you will be okay!

💡 Yay! This means you've successfully configured your Twilio webhook.

Set Up a Twilio Account

Since you should already have a trial Twilio Account from Week 2, you will only need to reconfigure the webhook URL. You will use the same phone number as before.

1. Create an Azure Function

Next, we'll want to create an Azure Function that will eventually output the content of texts that your Twilio number receives. This will just be a simple HTTP trigger function.

Finally, we need to install the npm package querystring to use in our function code later.

2. Configure Your Webhook URL

When someone sends a text message to your Twilio number, Twillio can call a webhook: your Azure Function. You can send a reply back simply by returning your message in the request body.

:question: Webhook? Twilio? I'm lost!
Fear not! [Webhooks](https://www.twilio.com/docs/usage/webhooks) are essentially just HTTP callbacks that are triggered by an event - in our case, this event is receiving an SMS message. When that event occurs, Twilio makes an HTTP request to the URL configured for the webhook.

We'll configure the Webhook URL by filling in the Azure Function URL as a webhook.

:question: How do I find my Azure Function URL?
Navigate to your Function page (Overview), and click `Get Function URL`. ![image](https://user-images.githubusercontent.com/49426183/120208560-784cc980-c1e2-11eb-8ad2-fd18597932ea.png)
:question: How do I configure my Twilio webhook URL?
1. Go to the [Twilio Console's Numbers page](https://www.twilio.com/console/phone-numbers/incoming) ![image](https://user-images.githubusercontent.com/49426183/120208171-06748000-c1e2-11eb-91a7-06c427967d46.png) 2. Click on the phone number you'd like to modify 3. Scroll down to the Messaging section and the "A MESSAGE COMES IN" option. 4. Paste in your Azure Function URL. Make sure to click `Save` afterwards!! ![image](https://user-images.githubusercontent.com/49426183/120208692-a0d4c380-c1e2-11eb-85fa-ed8463d1da43.png)

3. Write your Azure Function

Now, we'll want to write our Azure Function. Go to the code for the function you created previously in this step.

First, we'll need to instantiate our querystring npm package in order to use it.

:question: How do I use the `querystring` package? ```js const querystring = require('querystring'); ```

Next, we'll use the querystring object to parse our request's body.

:question: How do I parse the request body? ```js const queryObject = querystring.parse(req.body); ```

From this output, we'll find its Body attribute and return it.

:question: How do I return the output? ```js context.res = { body: queryObject.Body }; ``` > Since we are returning `queryObject.Body` as the entire body, you might not receive a text back on your phone. This is Twilio's issue, but the counselor bot's test should pass fine if your code is correct still!
ghost commented 3 years ago

Week 3 Step 7 ⬤⬤⬤⬤⬤⬤⬤◯◯ | 🕐 Estimated completion: 20-30 minutes

Leaky secrets

Store a message from Twilio in CosmosDB and return the most recent message

✅ Task:

❗ Make sure to return your message in this format:

Thanks 😊! Stored your secret "insert_user's_message". 😯 Someone confessed that: "the_most_recent_message"

🚧 Test Your Work

To test your work, send your Twilio number a text message. Once you do so, if you navigate to your Cosmos database account, go to Data Explorer, and the dropdowns underneath your new SecretStorer database, you should see an item that contains a message with your text message!

image

Important Note: If you are triggering the function for the first time, you may see an error message like the one below:

image

Don't worry! Try sending another text message, and everything should work fine the second time around. This error occurs because you don't have anything stored in CosmosDB yet.

💡 Yay! This means you've successfully connected Twilio with your Azure Cosmos database and Function.


1. Create your Cosmos Databases

Before we do anything else, we'll want to create our Cosmos DB account.

:question: How do I create my Cosmos DB account? 1. Navigate to your Azure Portal and click on `Azure Cosmos DB` under Azure Services. ![image](https://user-images.githubusercontent.com/49426183/120911257-90857400-c63a-11eb-9046-d9a7401e24af.png) 2. Click `Create Azure Cosmos DB Account`. ![image](https://user-images.githubusercontent.com/49426183/120911303-405ae180-c63b-11eb-98eb-6a1fedcad05c.png) 3. Under `Select API Option`, choose `Core (SQL) - Recommended`. ![image](https://user-images.githubusercontent.com/49426183/120911316-5d8fb000-c63b-11eb-8466-f7bfc938d1f8.png) 4. Fill in your account name, leave default options as they are, and click `Review + create`. ![image](https://user-images.githubusercontent.com/49426183/120911344-b52e1b80-c63b-11eb-82ff-e6b5f2e9075a.png) 5. Click `Create` a final time. ![image](https://user-images.githubusercontent.com/49426183/120911368-e7d81400-c63b-11eb-9855-686d444eb1ec.png) 6. Once deployment is complete, click `Go to resource`. ![image](https://user-images.githubusercontent.com/49426183/120911461-83698480-c63c-11eb-8260-b622013485a3.png)

1. Install @azure/cosmos

Now that your Azure Cosmos DB account is created, we should install the npm package @azure/cosmos.

🔧 1. Configuration

First, we need to instantiate a variable CosmosClient from the @azure/cosmos package we just downloaded.

const CosmosClient = require("@azure/cosmos").CosmosClient;

Create a config object that contains all of the sensitive information that we need to manipulate our data.

Call it config, and place keys for endpoint, key, databaseId, containerId, and partitionKey.

:question: What should my config object look like? Here is an example of the config object. Make sure your databaseId, containerId, and partitionKey are correct. ```js const config = { endpoint: process.env.ENDPOINT, key: process.env.KEY, databaseId: "SecretStorer", containerId: "secrets", partitionKey: {kind: "Hash", paths: ["/secrets"]} }; ```

2. The create Function

Now, we want to write an asynchronous create function that takes in the parameter of client (this will be our CosmosClient).

This function will:

⭐️ Use the client to create a database with an id of config.databaseId if it does not exist. ```js const { database } = await client.databases.createIfNotExists({ id: config.databaseId }); ```
⭐️ Use the client to create a container inside the database of ID config.databaseId. This container will have an ID of config.containerId and a key of config.partitionKey. ```js const { container } = await client .database(config.databaseId) .containers.createIfNotExists( { id: config.containerId, key: config.partitionKey }, { offerThroughput: 400 } ); ```

:bulb: Hint: The config.[value] variables are accessed from the config object you created earlier.

📜 2. The createDocument Function

Next, we need to create another asynchronous function called createDocument that will take in a parameter of newItem.

This function will create a new document within the database container that contains the newItem data.

In its entirety, the function will:

⭐️ Use the global config object to create the database and container if they do not exist. (Hint: this uses the create function we just implemented!) ```js var { endpoint, key, databaseId, containerId } = config; const client = new CosmosClient({endpoint, key}); const database = client.database(databaseId); const container = database.container(containerId); await create(client, databaseId, containerId); ```
⭐️ Create and execute a query that uses SQL language to fetch the most recent data document. This SQL query requests for the "top 1" document when it is orderd by `c._ts`, or the timestamp, in descending order. ```js const querySpec = { query: "SELECT top 1 * FROM c order by c._ts desc" }; ``` Using the query `querySpec`, it will use the `container` we created to fetch the most recent document! ```js const { resources: items } = await container.items.query(querySpec).fetchAll(); ```
⭐️ Create an document for your database that contains the information passed through the parameter `newItem`. ```js const {resource: createdItem} = await container.items.create(newItem); ```

Finally, it should return your items object from the function which contains the most recent message.

3. The Main Function

Instead of directly passing queryObject.Body (the SMS message) to context.res:

:question: How do I create a new document with queryObject.Body? ```js const queryObject = querystring.parse(req.body); let message = queryObject.Body; let document = {"message" : message} let items = await createDocument(document) ```

Your response message can then look something like:

const responseMessage = `Thanks 😊! Stored your secret "${message}". 😯 Someone confessed that: ${JSON.stringify(items[0].message)}`
ghost commented 3 years ago

That's it for Week 3, move on to Week 4 in your new issue!