{"id":2512,"date":"2020-11-13T12:33:22","date_gmt":"2020-11-13T17:33:22","guid":{"rendered":"https:\/\/blogs.mathworks.com\/developer\/?p=2512"},"modified":"2020-11-13T12:34:17","modified_gmt":"2020-11-13T17:34:17","slug":"all-your-database-are-belong-to-us","status":"publish","type":"post","link":"https:\/\/blogs.mathworks.com\/developer\/2020\/11\/13\/all-your-database-are-belong-to-us\/","title":{"rendered":"All your (data)base are belong to us"},"content":{"rendered":"<div class=\"content\"><!--introduction--><p><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/developer\/files\/y2020_DTF.png\" alt=\"\"> <\/p><p><i>Today I'd like to introduce first time blog contributor Tim Johns. Tim is a consultant in our UK office who has a wealth of experience utilizing the power of MATLAB for production applications. He is here to highlight a powerful workflow he has developed and is sharing for testing with databases. Take it away Tim!<\/i><\/p><p><b>You need automated testing!<\/b><\/p><p>For the past year or so, a couple of my colleagues from the consulting team and I have been working with one of our customers on a large software development project in MATLAB&reg; &#8211; 60 000 lines of code, 10+ developers in 3 countries. The resulting application is being used by the customer worldwide. I can easily say that if it wasn&#8217;t for automated testing, we would have been completely lost!<\/p><p>The application performs a lot of data analysis. To do this it must connect to an enterprise database. This presents a conundrum:<\/p><p><b>How do we automatically test against a database?<\/b><\/p><p>When writing such data processing applications, at some point you end up needing to test against a database. <a href=\"https:\/\/www.mathworks.com\/help\/matlab\/mocking-framework.html\">Mocking<\/a> can and should be used at the unit level, but as you progress into the integration testing, a representative system is required. The question is then what to test against?<\/p><p>Using the production database is an absolute no-no: much like performing electrical work on your house without turning off the main electrical supply, you&#8217;ll get a nasty shock sooner or later.<\/p><p>A better option is to run a test database either on a separate server or locally on each development machine. This creates a clear separation between production and development work, however there are some disadvantages.<\/p><p><b>Disadvantages of a &#8220;fat&#8221; test server<\/b><\/p><p>A central test server:<\/p><!--\/introduction--><div><ul><li>May be administered by your IT department who (rightly!) won&#8217;t give you free reign. During early development in particular, the database design may need to iterate rapidly.<\/li><li>Will need to handle multiple users running tests against it at the same time without contention.<\/li><\/ul><\/div><p>Running locally on each development machine is a heavyweight installation, even if IT permits it, and in either case, can you be confident that you haven&#8217;t inadvertently changed something on the server that affects subsequent test runs?<\/p><p><b>Solution: use a transient database<\/b><\/p><p>The solution that we came up with was to spin up and populate an instance of the database server in a <a href=\"https:\/\/www.docker.com\/use-cases\">Docker&reg; container<\/a> at the moment it was needed. That way you can guarantee you have got a clean database ready for testing, and no matter how wrong the test may go, it all gets cleaned up at the end!<\/p><p>Docker is fast becoming a standard DevOps tool. The Docker install is lightweight compared to a complete local install of a database server.<\/p><p><b>Introducing our database testing framework<\/b><\/p><p>The database testing framework that we developed to solve this is <a href=\"https:\/\/www.mathworks.com\/matlabcentral\/fileexchange\/77101-database-testing-framework\">now available on the File Exchange<\/a> for you to use to. It helps you to do a few things:<\/p><div><ol><li>We&#8217;ve worked out the Docker commands to launch the right containers in the right state for you. Currently we ship implementations for Microsoft SQL Server&reg; 2017 and 2019, and PostgreSQL&reg;. We also have the same functionality for SQLite, although this doesn&#8217;t actually need Docker.<\/li><li>We&#8217;ve provided the code as a <a href=\"https:\/\/www.mathworks.com\/help\/matlab\/matlab_prog\/write-test-using-shared-fixtures.html\">shared test fixture<\/a> with corresponding test classes that your own tests can inherit from. Being a shared fixture minimises the number of times that the database gets setup &amp; torn down (provided you&#8217;ve <a href=\"https:\/\/www.mathworks.com\/help\/matlab\/ref\/matlab.unittest.testsuite.sortbyfixtures.html\">sorted your test suite<\/a>), maximising efficiency &#8211; but the onus is on you not to write leaky tests!<\/li><li>Additional functionality includes checkpointing (restoring the database to a set state) and loading a backup file. You might use this if you want to debug an issue from production for example.<\/li><li>The port used by each database server instance is changed from the default to another free port. This allows multiple test suites to run independently at the same time. For example, you may want to run your tests in parallel, or your CI system may execute multiple jobs at the same time.<\/li><\/ol><\/div><p><b>Getting started<\/b><\/p><p>You will need the <a href=\"https:\/\/www.mathworks.com\/products\/database.html\">Database Toolbox&#8482;<\/a> to run this code. Install the <a href=\"https:\/\/www.mathworks.com\/matlabcentral\/fileexchange\/77101-database-testing-framework\">Database Testing Framework<\/a> from the File Exchange. This toolbox is currently supported only on Windows so be sure to do this from a Windows machine. Next, make sure you have the relevant driver installed for the database you want to use (<a href=\"https:\/\/www.microsoft.com\/en-us\/download\/details.aspx?id=53339\">Microsoft SQL Server<\/a> or <a href=\"https:\/\/www.postgresql.org\/ftp\/odbc\/versions\/\">PostgreSQL<\/a>). Finally, if you don&#8217;t have it already, download and install <a href=\"https:\/\/www.docker.com\/products\/docker-desktop\">Docker Desktop<\/a> for Windows along with the Windows Subsystem for Linux.<\/p><p>A full set of instructions is included with the toolbox, but here are some basic commands to get you started. We&#8217;ll use an interactive test session here, but normally you&#8217;ll want to use a class-based approach.<\/p><p><i>Establish a database and connection<\/i><\/p><p>First, we&#8217;ll run the command to setup the database in Docker and establish a connection to it:<\/p><pre class=\"codeinput\">tc = dbtest.WithMsSqlServer2019.forInteractiveUseWithAutoSetup()\r\n<\/pre><pre class=\"codeoutput\">EULA: &lt;a href=\"https:\/\/hub.docker.com\/_\/microsoft-mssql-server\"&gt;https:\/\/hub.docker.com\/_\/microsoft-mssql-server&lt;\/a&gt;\r\n[13-Nov-2020 11:49:45] Attempting to create container: Source=lh:55430_13-11_11:49:45.568, Port=55430\r\n[13-Nov-2020 11:49:48] Attempt [01] Waiting for container to be initialized \r\n[13-Nov-2020 11:49:53] Attempt [02] Waiting for container to be initialized \r\n[13-Nov-2020 11:49:58] Attempt [03] Waiting for container to be initialized \r\n[13-Nov-2020 11:50:03] Attempt [04] Connected: took 16.5sec \r\nRunning Setup Fcn ...\r\nFinished setting up database\r\n\r\ntc = \r\n\r\n  WithMsSqlServer2019 with properties:\r\n\r\n    DatabaseConnection: [1&times;1 database.odbc.connection]\r\n       CheckpointNames: [1&times;0 string]\r\n            TableNames: [0&times;1 string]\r\n\r\n<\/pre><p><i>Write some data to the database<\/i><\/p><p>Next, we&#8217;ll create a simple table and write it to the database:<\/p><pre class=\"codeinput\">tbl = table(<span class=\"string\">\"Batman\"<\/span>, 35,<span class=\"string\">\"Male\"<\/span>, 200,<span class=\"string\">\"Gotham\"<\/span>,<span class=\"string\">'VariableNames'<\/span>,<span class=\"keyword\">...<\/span>\r\n    {<span class=\"string\">'LastName'<\/span>, <span class=\"string\">'Age'<\/span>, <span class=\"string\">'Gender'<\/span>, <span class=\"string\">'Height'<\/span>, <span class=\"string\">'Location'<\/span>})\r\n<\/pre><pre class=\"codeoutput\">\r\ntbl =\r\n\r\n  1&times;5 table\r\n\r\n    LastName    Age    Gender    Height    Location\r\n    ________    ___    ______    ______    ________\r\n\r\n    \"Batman\"    35     \"Male\"     200      \"Gotham\"\r\n\r\n<\/pre><pre class=\"codeinput\">tc.DatabaseConnection.sqlwrite(<span class=\"string\">\"Characters\"<\/span>,tbl);\r\n<\/pre><p><i>Retrieve the data again<\/i><\/p><p>Now we&#8217;ll fetch the data back from the database and check it&#8217;s the same as what we sent:<\/p><pre class=\"codeinput\">tc.DatabaseConnection.sqlread(<span class=\"string\">\"Characters\"<\/span>)\r\n<\/pre><pre class=\"codeoutput\">\r\nans =\r\n\r\n  1&times;5 table\r\n\r\n     LastName     Age     Gender     Height     Location \r\n    __________    ___    ________    ______    __________\r\n\r\n    {'Batman'}    35     {'Male'}     200      {'Gotham'}\r\n\r\n<\/pre><p><i>Make use of checkpoints<\/i><\/p><p>One of the features built into the framework is the ability to create a checkpoint in the database that you can restore to at a later point in time. This is really useful when you want to set up the database once for a test suite but start each test point with the database in the same state.<\/p><p>Let&#8217;s create a checkpoint called &#8220;BatmanOnly&#8221;:<\/p><pre class=\"codeinput\">tc.createCheckpoint(<span class=\"string\">\"BatmanOnly\"<\/span>);\r\n<\/pre><p>Now we&#8217;ll add some more data to the table in the database:<\/p><pre class=\"codeinput\">tbl.LastName = <span class=\"string\">\"Robin\"<\/span>;\r\ntc.DatabaseConnection.sqlwrite(<span class=\"string\">\"Characters\"<\/span>,tbl);\r\ntc.DatabaseConnection.sqlread(<span class=\"string\">\"Characters\"<\/span>)\r\n<\/pre><pre class=\"codeoutput\">\r\nans =\r\n\r\n  2&times;5 table\r\n\r\n     LastName     Age     Gender     Height     Location \r\n    __________    ___    ________    ______    __________\r\n\r\n    {'Batman'}    35     {'Male'}     200      {'Gotham'}\r\n    {'Robin' }    35     {'Male'}     200      {'Gotham'}\r\n\r\n<\/pre><p>And now we&#8217;ll restore the database to the &#8220;BatmanOnly&#8221; checkpoint:<\/p><pre class=\"codeinput\">tc.restoreCheckpoint(<span class=\"string\">\"BatmanOnly\"<\/span>)\r\ntc.DatabaseConnection.sqlread(<span class=\"string\">\"Characters\"<\/span>)\r\n<\/pre><pre class=\"codeoutput\">\r\nans =\r\n\r\n  1&times;5 table\r\n\r\n     LastName     Age     Gender     Height     Location \r\n    __________    ___    ________    ______    __________\r\n\r\n    {'Batman'}    35     {'Male'}     200      {'Gotham'}\r\n\r\n<\/pre><p><i>Clean up!<\/i><\/p><p>Finally, we&#8217;ll clear the connection to the database from the workspace. Since it&#8217;s no-longer in use, it will automatically delete the connection, and stop and remove the container in Docker:<\/p><pre class=\"codeinput\">clear <span class=\"string\">tc<\/span>\r\n<\/pre><pre class=\"codeoutput\">[13-Nov-2020 11:50:16] Attempting to tear down container: Source=lh:55430_13-11_11:49:45.568, Port=55430\r\n<\/pre><p><b>Your turn!<\/b><\/p><p>Grab the Database Testing Framework toolbox from <a href=\"https:\/\/www.mathworks.com\/matlabcentral\/fileexchange\/77101-database-testing-framework\">File Exchange<\/a> or <a href=\"https:\/\/github.com\/mathworks-ref-arch\/matlab-database-testing-framework\">GitHub<\/a> and have a go yourself! Let me know how you get on in the comments below.<\/p><script language=\"JavaScript\"> <!-- \r\n    function grabCode_381f096588a7457c8ead5b96913e6011() {\r\n        \/\/ Remember the title so we can use it in the new page\r\n        title = document.title;\r\n\r\n        \/\/ Break up these strings so that their presence\r\n        \/\/ in the Javascript doesn't mess up the search for\r\n        \/\/ the MATLAB code.\r\n        t1='381f096588a7457c8ead5b96913e6011 ' + '##### ' + 'SOURCE BEGIN' + ' #####';\r\n        t2='##### ' + 'SOURCE END' + ' #####' + ' 381f096588a7457c8ead5b96913e6011';\r\n    \r\n        b=document.getElementsByTagName('body')[0];\r\n        i1=b.innerHTML.indexOf(t1)+t1.length;\r\n        i2=b.innerHTML.indexOf(t2);\r\n \r\n        code_string = b.innerHTML.substring(i1, i2);\r\n        code_string = code_string.replace(\/REPLACE_WITH_DASH_DASH\/g,'--');\r\n\r\n        \/\/ Use \/x3C\/g instead of the less-than character to avoid errors \r\n        \/\/ in the XML parser.\r\n        \/\/ Use '\\x26#60;' instead of '<' so that the XML parser\r\n        \/\/ doesn't go ahead and substitute the less-than character. \r\n        code_string = code_string.replace(\/\\x3C\/g, '\\x26#60;');\r\n\r\n        copyright = 'Copyright 2020 The MathWorks, Inc.';\r\n\r\n        w = window.open();\r\n        d = w.document;\r\n        d.write('<pre>\\n');\r\n        d.write(code_string);\r\n\r\n        \/\/ Add copyright line at the bottom if specified.\r\n        if (copyright.length > 0) {\r\n            d.writeln('');\r\n            d.writeln('%%');\r\n            if (copyright.length > 0) {\r\n                d.writeln('% _' + copyright + '_');\r\n            }\r\n        }\r\n\r\n        d.write('<\/pre>\\n');\r\n\r\n        d.title = title + ' (MATLAB code)';\r\n        d.close();\r\n    }   \r\n     --> <\/script><p style=\"text-align: right; font-size: xx-small; font-weight:lighter;   font-style: italic; color: gray\"><br><a href=\"javascript:grabCode_381f096588a7457c8ead5b96913e6011()\"><span style=\"font-size: x-small;        font-style: italic;\">Get \r\n      the MATLAB code <noscript>(requires JavaScript)<\/noscript><\/span><\/a><br><br>\r\n      Published with MATLAB&reg; R2020b<br><\/p><\/div><!--\r\n381f096588a7457c8ead5b96913e6011 ##### SOURCE BEGIN #####\r\n%% \r\n%\r\n% <<y2020_DTF.png>> \r\n%\r\n% _Today I'd like to introduce first time blog contributor Tim Johns. Tim\r\n% is a consultant in our UK office who has a wealth of experience utilizing\r\n% the power of MATLAB for production applications. He is here to highlight\r\n% a powerful workflow he has developed and is sharing for testing with\r\n% databases. Take it away Tim!_\r\n%\r\n% *You need automated testing!*\r\n% \r\n% For the past year or so, a couple of my colleagues from the consulting team \r\n% and I have been working with one of our customers on a large software development \r\n% project in MATLAB\u00ae \u2013 60 000 lines of code, 10+ developers in 3 countries. The \r\n% resulting application is being used by the customer worldwide. I can easily \r\n% say that if it wasn\u2019t for automated testing, we would have been completely lost! \r\n% \r\n% The application performs a lot of data analysis. To do this it must connect \r\n% to an enterprise database. This presents a conundrum: \r\n% \r\n% *How do we automatically test against a database?* \r\n% \r\n% When writing such data processing applications, at some point you end up needing \r\n% to test against a database. <https:\/\/www.mathworks.com\/help\/matlab\/mocking-framework.html \r\n% Mocking> can and should be used at the unit level, but as you progress into \r\n% the integration testing, a representative system is required. The question is \r\n% then what to test against?  \r\n% \r\n% Using the production database is an absolute no-no: much like performing electrical \r\n% work on your house without turning off the main electrical supply, you\u2019ll get \r\n% a nasty shock sooner or later. \r\n% \r\n% A better option is to run a test database either on a separate server or locally \r\n% on each development machine. This creates a clear separation between production \r\n% and development work, however there are some disadvantages. \r\n% \r\n% *Disadvantages of a \u201cfat\u201d test server* \r\n% \r\n% A central test server:\r\n%% \r\n% * May be administered by your IT department who (rightly!) won\u2019t give you \r\n% free reign. During early development in particular, the database design may \r\n% need to iterate rapidly. \r\n% * Will need to handle multiple users running tests against it at the same \r\n% time without contention. \r\n%% \r\n% Running locally on each development machine is a heavyweight installation, \r\n% even if IT permits it, and in either case, can you be confident that you haven\u2019t \r\n% inadvertently changed something on the server that affects subsequent test runs? \r\n% \r\n% *Solution: use a transient database* \r\n% \r\n% The solution that we came up with was to spin up and populate an instance \r\n% of the database server in a <https:\/\/www.docker.com\/use-cases Docker\u00ae container> \r\n% at the moment it was needed. That way you can guarantee you have got a clean \r\n% database ready for testing, and no matter how wrong the test may go, it all \r\n% gets cleaned up at the end!   \r\n% \r\n% Docker is fast becoming a standard DevOps tool. The Docker install is lightweight \r\n% compared to a complete local install of a database server. \r\n% \r\n% *Introducing our database testing framework* \r\n% \r\n% The database testing framework that we developed to solve this is <https:\/\/www.mathworks.com\/matlabcentral\/fileexchange\/77101-database-testing-framework \r\n% now available on the File Exchange> for you to use to. It helps you to do a \r\n% few things: \r\n%% \r\n% # We\u2019ve worked out the Docker commands to launch the right containers in the \r\n% right state for you. Currently we ship implementations for Microsoft SQL Server\u00ae \r\n% 2017 and 2019, and PostgreSQL\u00ae. We also have the same functionality for SQLite, \r\n% although this doesn\u2019t actually need Docker. \r\n% # We\u2019ve provided the code as a <https:\/\/www.mathworks.com\/help\/matlab\/matlab_prog\/write-test-using-shared-fixtures.html \r\n% shared test fixture> with corresponding test classes that your own tests can \r\n% inherit from. Being a shared fixture minimises the number of times that the \r\n% database gets setup & torn down (provided you\u2019ve <https:\/\/www.mathworks.com\/help\/matlab\/ref\/matlab.unittest.testsuite.sortbyfixtures.html \r\n% sorted your test suite>), maximising efficiency \u2013 but the onus is on you not \r\n% to write leaky tests! \r\n% # Additional functionality includes checkpointing (restoring the database \r\n% to a set state) and loading a backup file. You might use this if you want to \r\n% debug an issue from production for example. \r\n% # The port used by each database server instance is changed from the default \r\n% to another free port. This allows multiple test suites to run independently \r\n% at the same time. For example, you may want to run your tests in parallel, or \r\n% your CI system may execute multiple jobs at the same time. \r\n\r\n%% \r\n% *Getting started* \r\n% \r\n% You will need the <https:\/\/www.mathworks.com\/products\/database.html\r\n% Database Toolbox&#x2122;> to run this code. Install the\r\n% <https:\/\/www.mathworks.com\/matlabcentral\/fileexchange\/77101-database-testing-framework\r\n% Database Testing Framework> from the File Exchange. This toolbox is\r\n% currently supported only on Windows so be sure to do this from a Windows\r\n% machine. Next, make sure you have the relevant driver installed for the\r\n% database you want to use\r\n% (<https:\/\/www.microsoft.com\/en-us\/download\/details.aspx?id=53339\r\n% Microsoft SQL Server> or <https:\/\/www.postgresql.org\/ftp\/odbc\/versions\/\r\n% PostgreSQL>). Finally, if you don\u2019t have it already, download and install\r\n% <https:\/\/www.docker.com\/products\/docker-desktop Docker Desktop> for\r\n% Windows along with the Windows Subsystem for Linux.\r\n% \r\n% A full set of instructions is included with the toolbox, but here are some \r\n% basic commands to get you started. We\u2019ll use an interactive test session here, \r\n% but normally you\u2019ll want to use a class-based approach. \r\n% \r\n% _Establish a database and connection_ \r\n% \r\n% First, we\u2019ll run the command to setup the database in Docker and establish \r\n% a connection to it: \r\n% \r\ntc = dbtest.WithMsSqlServer2019.forInteractiveUseWithAutoSetup() \r\n\r\n%% \r\n% _Write some data to the database_ \r\n% \r\n% Next, we\u2019ll create a simple table and write it to the database: \r\n% \r\ntbl = table(\"Batman\", 35,\"Male\", 200,\"Gotham\",'VariableNames',...\r\n    {'LastName', 'Age', 'Gender', 'Height', 'Location'}) \r\n%%\r\ntc.DatabaseConnection.sqlwrite(\"Characters\",tbl); \r\n\r\n%%\r\n% _Retrieve the data again_ \r\n% \r\n% Now we\u2019ll fetch the data back from the database and check it\u2019s the same as \r\n% what we sent: \r\n% \r\ntc.DatabaseConnection.sqlread(\"Characters\") \r\n\r\n%%\r\n% _Make use of checkpoints_ \r\n% \r\n% One of the features built into the framework is the ability to create a checkpoint \r\n% in the database that you can restore to at a later point in time. This is really \r\n% useful when you want to set up the database once for a test suite but start \r\n% each test point with the database in the same state. \r\n% \r\n% Let\u2019s create a checkpoint called \u201cBatmanOnly\u201d: \r\n% \r\ntc.createCheckpoint(\"BatmanOnly\"); \r\n\r\n%% \r\n% Now we\u2019ll add some more data to the table in the database: \r\n% \r\ntbl.LastName = \"Robin\"; \r\ntc.DatabaseConnection.sqlwrite(\"Characters\",tbl); \r\ntc.DatabaseConnection.sqlread(\"Characters\") \r\n\r\n%% \r\n% And now we\u2019ll restore the database to the \u201cBatmanOnly\u201d checkpoint: \r\ntc.restoreCheckpoint(\"BatmanOnly\") \r\ntc.DatabaseConnection.sqlread(\"Characters\") \r\n\r\n%%\r\n% _Clean up!_ \r\n% \r\n% Finally, we\u2019ll clear the connection to the database from the workspace. Since \r\n% it\u2019s no-longer in use, it will automatically delete the connection, and stop \r\n% and remove the container in Docker: \r\nclear tc \r\n\r\n%%\r\n% *Your turn!* \r\n% \r\n% Grab the Database Testing Framework toolbox from <https:\/\/www.mathworks.com\/matlabcentral\/fileexchange\/77101-database-testing-framework \r\n% File Exchange> or <https:\/\/github.com\/mathworks-ref-arch\/matlab-database-testing-framework \r\n% GitHub> and have a go yourself! Let me know how you get on in the comments below.\r\n##### SOURCE END ##### 381f096588a7457c8ead5b96913e6011\r\n-->","protected":false},"excerpt":{"rendered":"<div class=\"overview-image\"><img src=\"https:\/\/blogs.mathworks.com\/developer\/files\/y2020_DTF.png\" class=\"img-responsive attachment-post-thumbnail size-post-thumbnail wp-post-image\" alt=\"\" decoding=\"async\" loading=\"lazy\" \/><\/div><p><i>Today I'd like to introduce first time blog contributor Tim Johns. Tim is a consultant in our UK office who has a wealth of experience utilizing the power of MATLAB for production applications. He is here to highlight a powerful workflow he has developed and is sharing for testing with databases. Take it away Tim!<\/i>... <a class=\"read-more\" href=\"https:\/\/blogs.mathworks.com\/developer\/2020\/11\/13\/all-your-database-are-belong-to-us\/\">read more >><\/a><\/p>","protected":false},"author":90,"featured_media":2516,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[34,7],"tags":[],"_links":{"self":[{"href":"https:\/\/blogs.mathworks.com\/developer\/wp-json\/wp\/v2\/posts\/2512"}],"collection":[{"href":"https:\/\/blogs.mathworks.com\/developer\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blogs.mathworks.com\/developer\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blogs.mathworks.com\/developer\/wp-json\/wp\/v2\/users\/90"}],"replies":[{"embeddable":true,"href":"https:\/\/blogs.mathworks.com\/developer\/wp-json\/wp\/v2\/comments?post=2512"}],"version-history":[{"count":1,"href":"https:\/\/blogs.mathworks.com\/developer\/wp-json\/wp\/v2\/posts\/2512\/revisions"}],"predecessor-version":[{"id":2514,"href":"https:\/\/blogs.mathworks.com\/developer\/wp-json\/wp\/v2\/posts\/2512\/revisions\/2514"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/blogs.mathworks.com\/developer\/wp-json\/wp\/v2\/media\/2516"}],"wp:attachment":[{"href":"https:\/\/blogs.mathworks.com\/developer\/wp-json\/wp\/v2\/media?parent=2512"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blogs.mathworks.com\/developer\/wp-json\/wp\/v2\/categories?post=2512"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blogs.mathworks.com\/developer\/wp-json\/wp\/v2\/tags?post=2512"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}