{"id":78874,"date":"2018-05-26T12:15:55","date_gmt":"2018-05-26T12:15:55","guid":{"rendered":"https:\/\/www.red-gate.com\/simple-talk\/?p=78874"},"modified":"2022-01-05T21:01:40","modified_gmt":"2022-01-05T21:01:40","slug":"combining-amazon-aurora-lambda-and-sqs-to-go-beyond-the-native-capabilities-of-mysql","status":"publish","type":"post","link":"https:\/\/www.red-gate.com\/simple-talk\/cloud\/aws\/combining-amazon-aurora-lambda-and-sqs-to-go-beyond-the-native-capabilities-of-mysql\/","title":{"rendered":"Combining Amazon Aurora, Lambda, and SQS to go Beyond the Native Capabilities of MySQL"},"content":{"rendered":"<p>Adoption of open-source database engines, such as MySQL and PostgreSQL, has become a major driver shaping the future of modern cloud-native data architectures. By combining open-source database technologies, alongside existing commercial database solutions, companies can essentially eat their cake and have it too &#8211; use the more expensive, commercial database solutions only for the specific applications that absolutely require it, all while enabling expansion and flexibility of the \u2018database fleet\u2019 using lower-cost open source database alternatives. This is the 80\/20 rule of modern data architectures. Yet the transition isn\u2019t always simple.<\/p>\n<p>Most commercial database systems are \u2018monolithic\u2019 and integrate a great deal of advanced functionality and capabilities directly into the database itself. As one example, both Microsoft and Oracle provide an asynchronous messaging\/queuing mechanism that is part of the database engine. Oracle calls it Advanced Queueing and Microsoft calls it Service Broker. Both are great implementations of queueing directly within the database, and many applications have been closely developed around specific database features.<\/p>\n<p>The problem is that PostgreSQL and MySQL lack some of the built-in capabilities you can find in a commercial relational database system forcing customers to either deploy 3rd party solutions (such as a dedicated queue system, external to the database) or develop custom functionality within the applications themselves.<\/p>\n<p>But luckily for us, when it comes to running MySQL and PostgreSQL in the cloud, there are simpler alternatives for mitigating missing functionality in the database itself. For example, when your run your MySQL databases as an Aurora MySQL cluster in Amazon Web Services, you also have access to the full set of powerful AWS ecosystem services and solutions which you can leverage where native database functionality is missing.<\/p>\n<p>While Aurora MySQL itself can provide increased performance and high-availability capabilities that go beyond what native MySQL can offer, there are also application-facing advantages. In this article I will provide one such example: using a combination of AWS Simple Queue Services (SQS) &#8212; which are fully managed message queues for microservices and distributed systems plus AWS Lambda &#8212; which allows you to run code without thinking about servers to provide seamless queueing capabilities in the MySQL database itself.<\/p>\n<p>Essentially, you will be performing a three-step process so that you can enqueue and dequeue messages directly from within an Amazon Aurora MySQL cluster:<\/p>\n<ol>\n<li>\n<p>You will create an Amazon <em>SQS Queue<\/em> that will be used to store messages as JSON payloads.<\/p>\n<\/li>\n<li>\n<p>You will create a <em>Lambda Function<\/em> which will use the SQS API to send and receive messages from Amazon SQS.<\/p>\n<\/li>\n<li>\n<p>You will invoke the Amazon Lambda Function from within an Aurora MySQL Cluster using <em>mysql.lambda_async<\/em><strong>. <\/strong><\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"1858\" height=\"910\" class=\"wp-image-78875\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/05\/word-image-89.png\" \/><\/p>\n<\/li>\n<\/ol>\n<p>Time to get started!<\/p>\n<h2>Create an SQS Queue<\/h2>\n<p>The first step is to create the Amazon SQS queue which will store the messages or events. From within the AWS web console &#8211;<\/p>\n<ol>\n<li>\n<p>Navigate to <em>Services<\/em> and type <em>SQS. <\/em>Select <em>Simple Queue Service<\/em>.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"wp-image-78876\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/05\/word-image-90.png\" width=\"875\" height=\"578\" \/><\/p>\n<\/li>\n<li>\n<p>From the next page, click on <em>Create New Queue<\/em>. If this is your first Amazon SQS queue, you may need to click on the <em>Get Started Now<\/em> button instead.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone  wp-image-78973\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/05\/imgaws.png\" alt=\"\" width=\"541\" height=\"202\" \/><\/p>\n<\/li>\n<li>\n<p>Next, you will have to name your queue. In this example, I\u2019ll aptly name my queue <em>best_queue_ever<\/em>. You will also need to choose the type of queue you wish to create.<\/p>\n<p>You have two options for queue type: <em>Standard Queue<\/em> and <em>FIFO Queue<\/em>. If you prioritize queue performance over atomicity of queue payload operations, choose a <em>Standard Queue<\/em> type. If you need strict atomicity of operations on your queue with reduced total throughout, choose a <em>FIFO Queue<\/em> type. For this example, select a <em>Standard Queue<\/em> type.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"2500\" height=\"1222\" class=\"wp-image-78878\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/05\/word-image-92.png\" \/><\/p>\n<\/li>\n<li>\n<p>Next, click on <em>Quick Create Queue<\/em> to create your SQS Queue. For this simple example, you don\u2019t have to specify any additional advanced configuration options.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"wp-image-78879\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/05\/word-image-93.png\" width=\"790\" height=\"306\" \/><\/p>\n<\/li>\n<li>\n<p>At this point, your SQS Queue has been created and should appear in the SQS Service main page. You will need to remember the <em>Queue URL<\/em> so that you can use it inside your Amazon Lambda function. Select the queue and copy &amp; paste the queue URL to a text editor.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"2500\" height=\"1235\" class=\"wp-image-78880\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/05\/word-image-94.png\" \/><\/p>\n<p>The queue URL will be in the following format:<\/p>\n<pre>https:\/\/xxxxxxxx\/xxxxxxxx\/best_queue_ever<\/pre>\n<\/li>\n<li>\n<p>You will also need to assign permissions on who can read or write to the new SQS queue. With the queue still selected, navigate to the Permissions tab and click on the <em>Add a Permission<\/em> button.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"1620\" height=\"1052\" class=\"wp-image-78881\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/05\/word-image-95.png\" \/><\/p>\n<p>On the next page, you can add permissions for the newly created queue. Select the <em>Everybody<\/em> checkbox under <em>Principal <\/em>and <em>All SQS Actions<\/em> under <em>Actions<\/em>. Note that this gives everybody permissions to do anything with this queue which is great for keeping the demo simple and straightforward, but in a real production environment, you should probably be more granular with permissions on your SQS queues.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"624\" height=\"460\" class=\"wp-image-78882\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/05\/word-image-96.png\" \/><\/p>\n<\/li>\n<li>\n<p>As a final step for queue creation, click on the <em>Add Permission<\/em> button to apply the new permissions on your SQS queue.<\/p>\n<\/li>\n<\/ol>\n<h2>Create the Lambda Function<\/h2>\n<p>With the SQS Queue configured, now it\u2019s time to create two Amazon Lambda Functions which will be used to enqueue and dequeue messages from the SQS queue. You will later see how to get your Aurora MySQL cluster to invoke the Lambda functions and interact with the queue.<\/p>\n<ol>\n<li>\n<p>To create the Lambda functions, navigate to <em>Services<\/em> and type <em>lambda. <\/em>Then select <em>Lambda<\/em>.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"1142\" height=\"670\" class=\"wp-image-78883\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/05\/word-image-97.png\" \/><\/p>\n<\/li>\n<li>\n<p>In the <em>Lambda Functions<\/em> screen, click <em>Create Function<\/em> to create the first Lambda function. This one will be used to enqueue messages, i.e., send messages, to the SQS Queue.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"2500\" height=\"884\" class=\"wp-image-78884\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/05\/word-image-98.png\" \/><\/p>\n<\/li>\n<li>\n<p>Choose <em>Author from scratch<\/em>, as you do not need to use a blueprint for this particular Lambda function.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"1223\" height=\"278\" class=\"wp-image-78885\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/05\/word-image-99.png\" \/><\/p>\n<\/li>\n<li>\n<p>Enter the Lambda function name, I used <em>sqs_enqueue<\/em> but feel free to be as creative as you\u2019d like as long as you stick with letters, numbers, hyphens, or underscores.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"1204\" height=\"484\" class=\"wp-image-78886\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/05\/word-image-100.png\" \/><\/p>\n<\/li>\n<li>\n<p>Select <em>Create a custom role<\/em> under the <em>Role<\/em> dropdown list. This will open the IAM Management Console in a new tab in your browser. When you create a Lambda function, you must assign permissions on which resources inside your AWS Account the Lambda function can access. Lambda Functions use an IAM role that grants your code permissions to access the AWS resources it needs.<\/p>\n<\/li>\n<li>\n<p>In the new IAM Management Console page, select <em>Create a new IAM Role<\/em> and specify the role name, such as <em>lambda_role1<\/em>.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"1390\" height=\"850\" class=\"wp-image-78887\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/05\/word-image-101.png\" \/><\/p>\n<\/li>\n<li>\n<p>Click on <em>Allow<\/em> at the bottom right of the screen once finished to create your new IAM Role.<\/p>\n<\/li>\n<li>\n<p>Back to the Lambda Function <em>Author from Scratch<\/em> page, click the <em>Create Function<\/em> button so that you can write the Lambda Function code which will send messages to the SQS Queue.<\/p>\n<\/li>\n<li>\n<p>You will modify the <a href=\"https:\/\/gist.github.com\/johntdyer\/7f9b3fc422e7b370c29ba83e70ec1c81\">following<\/a> reference code to fit the requirements. In the snippet below, replace <strong>https:\/\/QUEUE_URL <\/strong>with the queue URL of your SQS queue. Then use it to replace the code in the code window.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"1590\" height=\"809\" class=\"wp-image-78888\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/05\/desktop-screen20shot202018-05-1620at204-42-.png\" alt=\"..\/Desktop\/Screen%20Shot%202018-05-16%20at%204.42.00%20PM.png\" \/><\/p>\n<pre class=\"lang:c# theme:vs2012\">var QUEUE_URL = '<strong>https:\/\/QUEUE_URL<\/strong>';\r\nvar AWS = require('aws-sdk');\r\nvar sqs = new AWS.SQS({region : 'us-east-1'});\r\nexports.handler = function(event, context) {\r\n  var params = {\r\n    MessageBody: JSON.stringify(event),\r\n    QueueUrl: QUEUE_URL\r\n  };\r\n  sqs.sendMessage(params, function(err,data){\r\n    if(err) {\r\n      console.log('error:',\"** Failed to write to queue **\" + err);\r\n      context.done('error', \"** ERROR writing to SQS **\");  \t\/\/ ERROR when trying to enqueue to SQS\r\n    }else{\r\n      console.log('data:',data.MessageId);\r\n      context.done(null,'');  \r\n\/\/ SUCCESS - message written to SQS\r\n    }\r\n  });\r\n}<\/pre>\n<p>The Lambda Function is pretty straightforward:<\/p>\n<ul>\n<li>\n<p>You configure the SQS queue URL, so that the Lambda Function can interact with the specific queue created earlier.<\/p>\n<\/li>\n<li>\n<p>It loads the AWS SDK so that it can use the SQS API.<\/p>\n<\/li>\n<li>\n<p>It constructs an SQS object in the region where the SQS queue resides (using <strong>new AWS.SQS<\/strong>). If your SQS queue has been created in a different region, modify the <a href=\"https:\/\/docs.aws.amazon.com\/general\/latest\/gr\/rande.html\">region<\/a> accordingly.<\/p>\n<\/li>\n<li>\n<p>It calls the SQS API with the <strong>sqs.sendMessage<\/strong> call and sends the JSON Payload to the SQS Queue.<\/p>\n<\/li>\n<\/ul>\n<p>&nbsp;<\/p>\n<\/li>\n<li>\n<p>Click on the Save button to save the <em>sqs_enqueue<\/em> Lambda function and then click <strong>Test<\/strong> to test its functionality by sending a mockup JSON Payload to the queue. This opens a window to create the test event. The specific contents of the JSON payload don\u2019t really matter for testing the Lambda function. You can use the default test event using the provided <em>Hello World<\/em> template.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"1610\" height=\"1780\" class=\"wp-image-78889\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/05\/word-image-102.png\" \/><\/p>\n<p>Give the event a name, such as <em>DummyPayload<\/em>, and click <em>Create<\/em>.<\/p>\n<\/li>\n<li>\n<p>Click on the <em>Test<\/em> button to send the JSON payload to the queue and verify that the <em>sqs_enqueue<\/em> Lambda function works correctly.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"602\" height=\"116\" class=\"wp-image-78890\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/05\/word-image-103.png\" \/><\/p>\n<p>You should expect to see an <em>Execution result: succeeded<\/em> message after clicking on the Test button which signifies that the message was written successfully to the queue.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"2500\" height=\"1252\" class=\"wp-image-78891\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/05\/word-image-104.png\" \/><\/p>\n<\/li>\n<li>\n<p>Copy the ARN (Amazon Resource Name) for the Lambda function you just created. An ARN is used when you need to specify a resource unambiguously across all of AWS. In this case, you will use this ARN in the Stored Procedure you will create in the Aurora MySQL database.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"1418\" height=\"335\" class=\"wp-image-78892\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/05\/desktop-screen20shot202018-05-1620at204-45-.png\" alt=\"..\/Desktop\/Screen%20Shot%202018-05-16%20at%204.45.37%20PM.png\" \/><\/p>\n<\/li>\n<li>\n<p>Repeat the same steps to create the second Lambda Function <em>sqs_dequeue<\/em>, used to dequeue (read) messages from the SQS queue.<\/p>\n<\/li>\n<li>\n<p>When creating the <em>sqs_dequeue<\/em> Lambda function, under role, select <em>Choose an existing role<\/em> and select the <em>lambda_role1<\/em> role you created when you created the <em>sqs_enqueue<\/em> Lambda function.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"1426\" height=\"544\" class=\"wp-image-78893\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/05\/desktop-screen20shot202018-05-1620at204-48-.png\" alt=\"..\/Desktop\/Screen%20Shot%202018-05-16%20at%204.48.03%20PM.png\" \/><\/p>\n<\/li>\n<li>\n<p>Use the code below for the <em>sqs_dequeue<\/em> Lambda function. Remember to replace the <strong>QUEUE_URL<\/strong> with the URL for your SQS Queue and your region. Note that this time you are using the <strong>sqs.receiveMessage<\/strong> API call.<\/p>\n<p><strong> <img loading=\"lazy\" decoding=\"async\" width=\"1428\" height=\"695\" class=\"wp-image-78894\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/05\/desktop-screen20shot202018-05-1620at204-52-.png\" alt=\"..\/Desktop\/Screen%20Shot%202018-05-16%20at%204.52.57%20PM.png\" \/><\/strong><\/p>\n<pre class=\"lang:c# theme:vs2012\">var QUEUE_URL = '<strong>https:\/\/QUEUE_URL<\/strong>';\r\nvar AWS = require('aws-sdk');\r\nvar sqs = new AWS.SQS({region : 'us-east-1'});\r\nexports.handler = function(event, context) {\r\n  var params = {\r\n    QueueUrl: QUEUE_URL,\r\n    MaxNumberOfMessages: 1\r\n  };\r\n  <strong>sqs.receiveMessage<\/strong>(params, function(err,data){\r\n    if(err) {\r\n      console.log('error:',\"** Failed to write to queue **\" + err);\r\n      context.done('error', \"** ERROR writing to SQS **\");  \r\n\/\/ ERROR when trying to dequeue from SQS\r\n    }else{\r\n      console.log('data:',data);\r\n      context.done(null,'');  \r\n\/\/ SUCCESS - message read from SQS \r\n    }\r\n  });\r\n}<\/pre>\n<\/li>\n<\/ol>\n<h2>Configure your AWS Aurora MySQL Instance<\/h2>\n<p>Now it\u2019s time to set up your Amazon Aurora w\/MySQL Compatibility Cluster and create the MySQL Stored Procedure which will be used to invoke the Lambda functions for dequeuing and enqueuing messages from and to SQS.<\/p>\n<p>Note that there are several steps required in order for an Aurora MySQL cluster to successfully invoke Lambda functions. Otherwise, you can run into permission issues. You will need to do the following:<\/p>\n<ul>\n<li>\n<p>Create a new IAM Role.<\/p>\n<\/li>\n<li>\n<p>Assign the <em>AWSLambdaFullAccess <\/em>policy to the role so that the IAM Role will be able to execute Lambda Function API calls.<\/p>\n<\/li>\n<li>\n<p>Create a new custom DB Cluster Parameter Group.<\/p>\n<\/li>\n<li>\n<p>Modify the <em>aws_default_lambda_role<\/em> parameter with the value of the IAM Role ARN so that the Aurora MySQL instance will have permissions to invoke AWS Lambda function.<\/p>\n<\/li>\n<li>\n<p>Create a new Aurora MySQL Cluster, using the custom Cluster Parameter Group.<\/p>\n<\/li>\n<li>\n<p>Create a stored procedure invoking the Lambda function using the Lambda function ARN.<\/p>\n<\/li>\n<\/ul>\n<p>It\u2019s actually much simpler than it looks. Let\u2019s get started!<\/p>\n<h3>Configure IAM Role and Create a Cluster Parameter Group<\/h3>\n<p>Start by creating an IAM Role to which you will associate permissions to execute Lambda functions. Later, you will attach this IAM Role to your AWS Aurora Cluster.<\/p>\n<ol>\n<li>\n<p>Navigate to the AWS IAM Service page by clicking on <em>Services <\/em>and typing <em>iam<\/em>. Select <em>IAM<\/em>.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"1212\" height=\"448\" class=\"wp-image-78895\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/05\/word-image-105.png\" \/><\/p>\n<\/li>\n<li>\n<p>Once on the IAM Service page, click on <em>Roles<\/em> and select <em>Create Role<\/em>.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"1634\" height=\"1158\" class=\"wp-image-78896\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/05\/word-image-106.png\" \/><\/p>\n<\/li>\n<li>\n<p>Select <em>AWS Service<\/em> as the role type, RDS as the <em>Service that will use this role <\/em>and <em>RDS \u2013 Cloud HSM and Directory Services<\/em> for the Use Case. Click on <em>Next: Permissions<\/em> once done.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"1612\" height=\"1418\" class=\"wp-image-78897\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/05\/desktop-screen20shot202018-05-1620at207-05-.png\" alt=\"..\/Desktop\/Screen%20Shot%202018-05-16%20at%207.05.57%20PM.png\" \/><\/p>\n<\/li>\n<li>\n<p>Leave the settings as-is on the next screen and click <em>Next: Review<\/em>. On the following screen, provide the role with a name, such as <em>rds_role,<\/em> and click <em>Create Role<\/em><\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"925\" height=\"485\" class=\"wp-image-78898\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/05\/word-image-107.png\" \/><\/p>\n<\/li>\n<li>\n<p>After the role has been created, you need to add a policy to this role which allows for execution of Lambda functions. To accomplish that, in your IAM Service page, click on Roles and the name of the IAM Role you have just created &#8211; <em>rds_role<\/em>.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"943\" height=\"961\" class=\"wp-image-78899\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/05\/desktop-screen20shot202018-05-1620at206-44-.png\" alt=\"..\/Desktop\/Screen%20Shot%202018-05-16%20at%206.44.56%20PM.png\" \/><\/p>\n<\/li>\n<li>\n<p>Click Attach Policy to select the policies you want granted to the IAM Role<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"1335\" height=\"583\" class=\"wp-image-78900\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/05\/desktop-screen20shot202018-05-1620at206-46-.png\" alt=\"..\/Desktop\/Screen%20Shot%202018-05-16%20at%206.46.54%20PM.png\" \/><\/p>\n<\/li>\n<li>\n<p>On the next screen, search for the <em>AWSLambdaFullAccess<\/em> policy name, select the checkbox next to it. The <em>AWSLambdaFullAccess<\/em> policy grants full access to Amazon Lambda. In a production environment, you will probably want to be more granular with the permissions you grant, but for this demo, granting the <em>AWSLambdaFullAccess<\/em> role is ok. Click <em>Attach Policy. <\/em><\/p>\n<p><em> <img loading=\"lazy\" decoding=\"async\" width=\"1428\" height=\"669\" class=\"wp-image-78901\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/05\/desktop-screen20shot202018-05-1620at206-50-.png\" alt=\"..\/Desktop\/Screen%20Shot%202018-05-16%20at%206.50.24%20PM.png\" \/><\/em><\/p>\n<p>&nbsp;<\/p>\n<p>Your new IAM Role now has the <em>AWSLambdaFullAccess <\/em>policy attached to it.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"1019\" height=\"285\" class=\"wp-image-78902\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/05\/word-image-108.png\" \/><\/p>\n<\/li>\n<li>\n<p>Copy the Role ARN and store it somewhere safe. You will need to use this value for a parameter in the AWS Aurora Cluster Parameter Group.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"1426\" height=\"617\" class=\"wp-image-78903\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/05\/desktop-screen20shot202018-05-1620at205-44-.png\" alt=\"..\/Desktop\/Screen%20Shot%202018-05-16%20at%205.44.56%20PM.png\" \/><\/p>\n<\/li>\n<\/ol>\n<h3>Create a new Cluster Parameter Group<\/h3>\n<p>After the IAM Role has been created, you will need to create a custom Aurora Cluster Parameter Group. This is required, as without doing so, your Aurora Cluster won\u2019t have the permissions to Invoke Lambda functions.<\/p>\n<ol>\n<li>\n<p>Click <em>Services<\/em> add type <em>rds. <\/em>Select <em>RDS<\/em> to open the RDS Service Dashboard.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"1104\" height=\"520\" class=\"wp-image-78904\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/05\/word-image-109.png\" \/><\/p>\n<\/li>\n<li>\n<p>Select <em>Parameter Groups<\/em> from the RDS Dashboard and click <em>Create Parameter Group<\/em>.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"1432\" height=\"771\" class=\"wp-image-78905\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/05\/desktop-screen20shot202018-05-1620at205-47-.png\" alt=\"..\/Desktop\/Screen%20Shot%202018-05-16%20at%205.47.47%20PM.png\" \/><\/p>\n<\/li>\n<li>\n<p>Choose <em>aurora-mysql5.7<\/em> as the <em>Parameter group family<\/em> (this is the Parameter Group Family for Aurora w\/MySQL compatibility version 5.7), select <em>DB Cluster Parameter Group<\/em> for the <em>Type<\/em> and enter a <em>Group name<\/em> and description. I\u2019m using <em>mysql-lambda<\/em> for my demo. You will also need to enter a description for the parameter group.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"1430\" height=\"778\" class=\"wp-image-78906\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/05\/desktop-screen20shot202018-05-1620at205-49-.png\" alt=\"..\/Desktop\/Screen%20Shot%202018-05-16%20at%205.49.51%20PM.png\" \/><\/p>\n<p>Once done, click <em>Create<\/em>.<\/p>\n<\/li>\n<li>\n<p>Back in the RDS Service page, navigate to <em>Parameter Groups<\/em>, select the custom <em>DB Cluster<\/em> <em>Parameter Group<\/em> you have created for your AWS Aurora MySQL Cluster, click on <em>Parameter group actions<\/em> and choose <em>Edit<\/em>.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"1432\" height=\"579\" class=\"wp-image-78907\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/05\/desktop-screen20shot202018-05-1620at205-52-.png\" alt=\"..\/Desktop\/Screen%20Shot%202018-05-16%20at%205.52.57%20PM.png\" \/><\/p>\n<\/li>\n<li>\n<p>Search for a parameter with the name: <em>aws_default_lambda_role<\/em>, and for the value of this parameter, enter the <em>IAM Role ARN <\/em>from the earlier step when creating the role.<\/p>\n<p><img decoding=\"async\" class=\"wp-image-78908\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/05\/desktop-screen20shot202018-05-1620at205-52-.png\" alt=\"..\/Desktop\/Screen%20Shot%202018-05-16%20at%205.56.26%20PM.png\" \/><\/p>\n<p>Click on Save Changes.<\/p>\n<\/li>\n<\/ol>\n<h3>Create your AWS Aurora MySQL Instance<\/h3>\n<p>After your IAM Role and custom Cluster Parameter Group have been created, you can provision your Aurora MySQL cluster.<\/p>\n<ol>\n<li>\n<p>Click <em>Services<\/em> and type <em>rds<\/em>. Select <em>RDS<\/em> to open the RDS Service Dashboard.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"1104\" height=\"520\" class=\"wp-image-78909\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/05\/word-image-110.png\" \/><\/p>\n<\/li>\n<li>\n<p>In the RDS Dashboard main screen click on <em>Launch an Aurora DB instance<\/em>. You may have to click <em>Get started now<\/em> if this is the first time you have been to this dashboard.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"820\" height=\"418\" class=\"wp-image-78910\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/05\/desktop-screen20shot202018-05-1620at205-59-.png\" alt=\"..\/Desktop\/Screen%20Shot%202018-05-16%20at%205.59.08%20PM.png\" \/><\/p>\n<\/li>\n<li>\n<p>Select <em>Amazon Aurora<\/em> and choose the <em>MySQL-5.7 compatible edition<\/em>. Click <em>Next<\/em>.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"1222\" height=\"1166\" class=\"wp-image-78911\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/05\/desktop-screen20shot202018-05-1620at206-00-.png\" alt=\"..\/Desktop\/Screen%20Shot%202018-05-16%20at%206.00.20%20PM.png\" \/><\/p>\n<\/li>\n<li>\n<p>Specify the <em>DB Instance Class<\/em> for your database (which determines the number of CPUs and RAM allocated to the Aurora instances), specify the <em>Multi-AZ Deployment<\/em> option which will create automatic replicas of your MySQL instance in multiple AZs for increased high availability and read scalability and a name for the database (such as <em>mysql01<\/em>). Also create a <em>Master username <\/em>and <em>Master password<\/em>.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"1429\" height=\"705\" class=\"wp-image-78912\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/05\/desktop-screen20shot202018-05-1620at206-01-.png\" alt=\"..\/Desktop\/Screen%20Shot%202018-05-16%20at%206.01.46%20PM.png\" \/><\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"1427\" height=\"402\" class=\"wp-image-78913\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/05\/desktop-screen20shot202018-05-1620at206-01-1-1.png\" alt=\"..\/Desktop\/Screen%20Shot%202018-05-16%20at%206.01.52%20PM.png\" \/><\/p>\n<p>Click <em>Next<\/em> once done.<\/p>\n<\/li>\n<li>\n<p>Specify the desired network, security and database options for your AWS Aurora MySQL Cluster. For example, selecting <em>Yes<\/em> for <em>Public accessibility<\/em> will make your Aurora MySQL cluster accessible from the internet. You can also choose the VPC security group which determines the rules for allowing or disabling connections to your cluster. The default options are fine for our demo but are usually not suited for production databases.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"938\" height=\"799\" class=\"wp-image-78914\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/05\/desktop-screen20shot202018-05-1620at206-05-.png\" alt=\"..\/Desktop\/Screen%20Shot%202018-05-16%20at%206.05.54%20PM.png\" \/><\/p>\n<\/li>\n<li>\n<p>Further down the screen, provide a name for your Aurora MySQL cluster and for the database &#8211; <em>mysql-cluster01<\/em> and <em>mydb<\/em> in my environment. Also make sure you select the custom <em>Cluster Parameter Group<\/em> you have created earlier under the <em>DB Cluster Parameter Group<\/em> option. Without doing so, you will not be able to invoke Lambda functions from within your Aurora MySQL database.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"907\" height=\"826\" class=\"wp-image-78915\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/05\/desktop-screen20shot202018-05-1620at206-14-.png\" alt=\"..\/Desktop\/Screen%20Shot%202018-05-16%20at%206.14.39%20PM.png\" \/><\/p>\n<\/li>\n<li>\n<p>Accept the defaults for the remaining options and click <em>Launch DB instance<\/em> at the bottom of the screen to create the cluster.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"770\" height=\"286\" class=\"wp-image-78916\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/05\/desktop-screen20shot202018-05-1620at206-17-.png\" alt=\"..\/Desktop\/Screen%20Shot%202018-05-16%20at%206.17.16%20PM.png\" \/><\/p>\n<p>You will be presented with a notification indicating that your Aurora MySQL Cluster is being created.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"1524\" height=\"1050\" class=\"wp-image-78917\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/05\/desktop-screen20shot202018-05-1620at206-18-.png\" alt=\"..\/Desktop\/Screen%20Shot%202018-05-16%20at%206.18.27%20PM.png\" \/><\/p>\n<\/li>\n<li>\n<p>After your AWS Aurora MySQL Database Cluster is ready, you will need to assign the IAM Role you created earlier. In the RDS Dashboard screen, click on Clusters, select the Aurora MySQL cluster you have just created and click on <em>Actions<\/em> followed by <em>Manage IAM Roles<\/em>.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"1429\" height=\"536\" class=\"wp-image-78918\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/05\/desktop-screen20shot202018-05-1620at206-21-.png\" alt=\"..\/Desktop\/Screen%20Shot%202018-05-16%20at%206.21.40%20PM.png\" \/><\/p>\n<\/li>\n<li>\n<p>Choose the IAM Role you have created earlier (<em>rds_role<\/em>) and click <em>Add role<\/em>.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"1223\" height=\"769\" class=\"wp-image-78919\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/05\/desktop-screen20shot202018-05-1620at207-14-.png\" alt=\"..\/Desktop\/Screen%20Shot%202018-05-16%20at%207.14.21%20PM.png\" \/><\/p>\n<\/li>\n<li>\n<p>Wait until the changes have been applied to your AWS Aurora MySQL Cluster and make sure no restart is required. After Status changes to Active click on Done.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"1098\" height=\"687\" class=\"wp-image-78920\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/05\/desktop-screen20shot202018-05-1620at207-15-.png\" alt=\"..\/Desktop\/Screen%20Shot%202018-05-16%20at%207.15.43%20PM.png\" \/><\/p>\n<\/li>\n<\/ol>\n<h2>Create the Stored Procedure That Will Execute the Lambda Function<\/h2>\n<p>If you reached this far, it means that you have completed all of the prerequisites steps required to allow Aurora MySQL access to invoke your Lambda function and as such, enqueue and dequeue messages to SQS.<\/p>\n<ol>\n<li style=\"list-style-type: none\">\n<ol>\n<li>\n<p>In the Amazon RDS console, click on Clusters and click on the name of the Aurora MySQL Cluster you have created earlier.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"1426\" height=\"641\" class=\"wp-image-78921\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/05\/screen20shot202018-05-1620at207-17-3320pm-png.png\" alt=\"Screen%20Shot%202018-05-16%20at%207.17.33%20PM.png\" \/><\/p>\n<\/li>\n<li>\n<p>Copy the DNS address that appears under <em>Cluster endpoint<\/em>. This is the DNS address of your Cluster and the one you will use when configuring your connection. Be sure to choose the Cluster endpoint address and not the Reader endpoint address.<\/p>\n<p>Since Amazon Aurora clusters are comprised of a writer node and multiple reader nodes, the Cluster endpoint will always point to the writer node in the cluster (even if one of the reader nodes has been prompted to a new writer, such as after a failover) and the Reader endpoint will load balance across all of the reader nodes in your cluster. Connecting to the reader endpoint will not allow you to write changes to your Aurora MySQL cluster.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"1430\" height=\"811\" class=\"wp-image-78922\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/05\/screen20shot202018-05-1620at207-18-1720pm-png.png\" alt=\"Screen%20Shot%202018-05-16%20at%207.18.17%20PM.png\" \/><\/p>\n<\/li>\n<li>\n<p>You will now need to connect to your Aurora MySQL cluster and invoke the Lambda functions you have created earlier. There are multiple tools available, but I usually prefer to use <a href=\"https:\/\/dbeaver.io\/\">DBeaver<\/a>, which is a free universal SQL client with good MySQL support.<\/p>\n<\/li>\n<li>\n<p>After you have downloaded and installed DBeaver, you will need to create a new connection to your Aurora MySQL cluster. You can accomplish that by clicking on the <em>Create New Connection<\/em> button. Note that the location of this may differ depending on your DBeaver screen layout.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"921\" height=\"422\" class=\"wp-image-78923\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/05\/screen20shot202018-05-1620at207-33-2620pm-png.png\" alt=\"Screen%20Shot%202018-05-16%20at%207.33.26%20PM.png\" \/><\/p>\n<\/li>\n<li>\n<p>In the first screen of the <em>Create new connection<\/em> wizard, choose <em>MySQL<\/em> as the driver and click <em>Next<\/em>.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"452\" height=\"304\" class=\"wp-image-78924\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/05\/word-image-111.png\" \/><\/p>\n<\/li>\n<li>\n<p>Next, you will need to provide the connection properties of your new Aurora MySQL cluster. This includes the Cluster endpoint you copied earlier for the Server Host, as well as the database name, username and password which you have configured during the creation of your Aurora cluster. Once done click <em>Test Connection<\/em> and if the test was successful click <em>Next<\/em>.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"1112\" height=\"1101\" class=\"wp-image-78925\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/05\/screen20shot202018-05-1620at207-27-4520pm-png.png\" alt=\"Screen%20Shot%202018-05-16%20at%207.27.45%20PM.png\" \/><\/p>\n<\/li>\n<li>\n<p>You can skip the next two screens by clicking on <em>Next<\/em> twice.<\/p>\n<\/li>\n<li>\n<p>Complete the creation of your new MySQL connection by providing a connection name and clicking on <em>Finish<\/em>.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"1017\" class=\"wp-image-78926\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/05\/screen20shot202018-05-1620at207-31-1020pm-png.png\" alt=\"Screen%20Shot%202018-05-16%20at%207.31.10%20PM.png\" \/><\/p>\n<\/li>\n<li>\n<p>Right click on the new connection in the left-hand pane and open a new <em>SQL Editor<\/em> window.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"783\" height=\"880\" class=\"wp-image-78927\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/05\/screen20shot202018-05-1620at207-36-4020pm-png.png\" alt=\"Screen%20Shot%202018-05-16%20at%207.36.40%20PM.png\" \/><\/p>\n<\/li>\n<li>\n<p>You can invoke a Lambda function from within MySQL by using the <strong>mysql.lambda_asyc<\/strong> procedure. Specify the <strong>ARN for the Lambda function<\/strong> you have created earlier and provide the JSON Payload for the message which will be sent to the queue:<\/p>\n<pre class=\"lang:tsql theme:ssms2012-simple-talk\">CALL mysql.lambda_async('LAMBDA_FUNCTION_ARN', '{\"subject\" : \"Aurora Lambda test!\", \"message\" : \"If this works, I can write to SQS!\"}');<\/pre>\n<p>You can execute the Lambda function call by clicking the <em>Execute<\/em> button.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"1430\" height=\"311\" class=\"wp-image-78928\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/05\/screen20shot202018-05-1620at207-39-4620pm-png.png\" alt=\"Screen%20Shot%202018-05-16%20at%207.39.46%20PM.png\" \/><\/p>\n<\/li>\n<\/ol>\n<\/li>\n<\/ol>\n<div class=\"note\">\n<p><em>Note that if you receive a \u201cmissing credential\u201d error at this point, you have probably missed one of the steps in configuring your IAM Role or Cluster parameter group settings.<\/em><\/p>\n<\/div>\n<ol>\n<li>\n<p>An easy way to verify that your messages have been sent successfully to the SQS queue through the usage of the Lambda function is to poll the SQS queue itself. Simply navigate to the AWS SQS console.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"564\" height=\"269\" class=\"wp-image-78929\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/05\/screen20shot202018-05-1620at207-42-1220pm-png.png\" alt=\"Screen%20Shot%202018-05-16%20at%207.42.12%20PM.png\" \/><\/p>\n<\/li>\n<li>\n<p>Select the queue which you have created earlier (<em>best_queue_ever<\/em>, in my environment), click on <em>Queue Actions<\/em> and choose <em>View\/Delete messages<\/em>.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"618\" height=\"368\" class=\"wp-image-78930\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/05\/screen20shot202018-05-1620at207-42-2520pm-png.png\" alt=\"Screen%20Shot%202018-05-16%20at%207.42.25%20PM.png\" \/><\/p>\n<\/li>\n<li>\n<p>In the pop-up screen click on the <em>Start Polling for Messages<\/em> button in the center of the screen:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"1113\" height=\"614\" class=\"wp-image-78931\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/05\/screen20shot202018-05-1620at207-42-3120pm-png.png\" alt=\"Screen%20Shot%202018-05-16%20at%207.42.31%20PM.png\" \/><\/p>\n<\/li>\n<li>\n<p>And if everything was successful up to this point, you should be able to see your messages appear. This indicates that you have invoked a <strong><em>Lambda function<\/em><\/strong> which sent JSON payloads to an <strong><em>SQS queue<\/em><\/strong> from within an <strong><em>Aurora MySQL cluster<\/em><\/strong>.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"1223\" height=\"677\" class=\"wp-image-78932\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/05\/screen20shot202018-05-1620at207-45-2420pm-png.png\" alt=\"Screen%20Shot%202018-05-16%20at%207.45.24%20PM.png\" \/><\/p>\n<\/li>\n<li>\n<p>Additionally, you can also wrap <strong>mysql.lambda_asyc<\/strong> with your own custom procedure that can further enhance the business logic you want to execute as well as perform error handling. Plus, you won\u2019t have to specify the Lambda function ARN on each execution. You can find one such very simple example of embedding <strong>mysql.lambda_asyc<\/strong> inside a stored procedure below:<\/p>\n<pre class=\"lang:tsql theme:ssms2012-simple-talk\">DROP PROCEDURE IF EXISTS sqs_enqueue;\r\nCREATE PROCEDURE <strong>sqs_enqueue<\/strong>(IN payload TEXT) LANGUAGE SQL \r\nBEGIN\r\nCALL mysql.lambda_async('LAMBDA_FUNCTION_ARN', payload);\r\n\tEND\r\n\t;;\r\n\t\r\ncall <strong>sqs_enqueue<\/strong>('{\"subject\" : \"Aurora Lambda test!\", \"message\" : \"If this works, I can write to SQS!\"}');<\/pre>\n<\/li>\n<\/ol>\n<p>So there you have it! Using a Lambda function from within an Amazon Aurora MySQL cluster to read and write messages to an AWS SQS queue. This is just one example of how you can extend the core functionality of MySQL by leveraging additional cloud-native components provided by AWS. To finish up, you will probably want to delete the instances.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Tapping the power of serverless computing via Lambda functions and cloud-native technologies allows us to extend the native capabilities that exist in open-source databases. David Yahalom demonstrates how to create a queue using Lambda that can be used to add queuing capabilities to MySQL.&hellip;<\/p>\n","protected":false},"author":319655,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[137092,145792],"tags":[],"coauthors":[58911],"class_list":["post-78874","post","type-post","status-publish","format-standard","hentry","category-aws","category-mysql"],"acf":[],"_links":{"self":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/78874","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/users\/319655"}],"replies":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/comments?post=78874"}],"version-history":[{"count":20,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/78874\/revisions"}],"predecessor-version":[{"id":93109,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/78874\/revisions\/93109"}],"wp:attachment":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/media?parent=78874"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/categories?post=78874"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/tags?post=78874"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/coauthors?post=78874"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}