{"id":847,"date":"2022-03-24T00:32:26","date_gmt":"2022-03-24T00:32:26","guid":{"rendered":"https:\/\/adrianotanaka.com.br\/?p=847"},"modified":"2022-03-24T00:32:52","modified_gmt":"2022-03-24T00:32:52","slug":"oci-integracao-object-storage-com-functions","status":"publish","type":"post","link":"https:\/\/adrianotanaka.com.br\/index.php\/2022\/03\/24\/oci-integracao-object-storage-com-functions\/","title":{"rendered":"OCI &#8211; Integra\u00e7\u00e3o Object Storage com Functions"},"content":{"rendered":"\n<p>Um dos recursos que o Object Storage nos fornece \u00e9 disparar eventos quando ocorre uma intera\u00e7\u00e3o com ele,  nesse artigo mostro como usar essa funcionalidade com o OCI Functions para gerar uma PAR e enviar um e-mail quando um objeto \u00e9 enviado\/alterado, al\u00e9m disso tamb\u00e9m vamos usar o custom metadata.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Configura\u00e7\u00e3o do bucket<\/h2>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"937\" height=\"401\" src=\"https:\/\/adrianotanaka.com.br\/wp-content\/uploads\/2022\/03\/image-31.png\" alt=\"\" class=\"wp-image-850\" srcset=\"https:\/\/adrianotanaka.com.br\/wp-content\/uploads\/2022\/03\/image-31.png 937w, https:\/\/adrianotanaka.com.br\/wp-content\/uploads\/2022\/03\/image-31-300x128.png 300w, https:\/\/adrianotanaka.com.br\/wp-content\/uploads\/2022\/03\/image-31-768x329.png 768w\" sizes=\"auto, (max-width: 937px) 100vw, 937px\" \/><\/figure>\n\n\n\n<p>Ao criar o Bucket, marque a op\u00e7\u00e3o Emit Object Events.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Custom metadata<\/h2>\n\n\n\n<p>Antes de criar a FN, um dos pontos que levei em considera\u00e7\u00e3o foi como permitir ao usu\u00e1rio passar como par\u00e2metro para ela o endere\u00e7o de destino e o tempo que o PAR seria v\u00e1lido, a op\u00e7\u00e3o mais l\u00f3gica seria o uso de tags, mas elas n\u00e3o est\u00e3o dispon\u00edveis em n\u00edvel de Objeto (apenas a n\u00edvel de bucket), ent\u00e3o a sa\u00edda foi usar metada customizado:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"219\" src=\"https:\/\/adrianotanaka.com.br\/wp-content\/uploads\/2022\/03\/image-33-1024x219.png\" alt=\"\" class=\"wp-image-855\" srcset=\"https:\/\/adrianotanaka.com.br\/wp-content\/uploads\/2022\/03\/image-33-1024x219.png 1024w, https:\/\/adrianotanaka.com.br\/wp-content\/uploads\/2022\/03\/image-33-300x64.png 300w, https:\/\/adrianotanaka.com.br\/wp-content\/uploads\/2022\/03\/image-33-768x164.png 768w, https:\/\/adrianotanaka.com.br\/wp-content\/uploads\/2022\/03\/image-33.png 1236w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>Via oci cli voc\u00ea pode usar o par\u00e2metro &#8211;metadata<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Function<\/h2>\n\n\n\n<p>A function tem 3 partes:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>create_PAR, essa fun\u00e7\u00e3o recebe como par\u00e2metro o signer, nome do bucket, nome do PAR, o tempo de validade dele e o nome do objeto, ela retorna o PAR gerado.<\/li><li>getMetadata, essa \u00e9 a fun\u00e7\u00e3o que recupera os metadados do objeto e alimenta o envio de e-mail<\/li><li>handler, essa fun\u00e7\u00e3o \u00e9 chamada pelo Evento, chama as outras duas e envia o email<\/li><\/ul>\n\n\n\n<pre class=\"wp-block-code\"><code>import io\r\nimport json\r\nfrom pickle import OBJ\r\nfrom fdk import response\r\nimport os\r\nimport oci\r\nimport oci.object_storage\r\nfrom datetime import datetime, timedelta\r\nimport smtplib\r\nfrom email.mime.multipart import MIMEMultipart\r\nfrom email.mime.text import MIMEText\r\n\r\n\r\n\r\n\r\n\r\n\r\ndef create_PAR(signer, bucket_name, PAR_name, lifetime,OBJ_name):\r\n    client = oci.object_storage.ObjectStorageClient(config={}, signer=signer)\r\n    namespace = client.get_namespace().data\r\n    par_expiration = datetime.utcnow() + timedelta(minutes=lifetime)\r\n    object_storage_endpoint = \"https:\/\/objectstorage.\" + signer.region + \".oraclecloud.com\"\r\n    par_details = oci.object_storage.models.CreatePreauthenticatedRequestDetails(name=PAR_name, access_type='ObjectRead', time_expires=par_expiration,object_name=OBJ_name)\r\n    par = client.create_preauthenticated_request(namespace_name=namespace, bucket_name=bucket_name, create_preauthenticated_request_details=par_details)\r\n    par_url = object_storage_endpoint + par.data.access_uri\r\n    print (par_url)\r\n    return par_url\r\n\r\n\r\ndef getMetadata(signer, bucket_name,OBJ_name):\r\n \r\n        signer = oci.auth.signers.get_resource_principals_signer()\r\n        client = oci.object_storage.ObjectStorageClient(config={}, signer=signer)\r\n        namespace = client.get_namespace().data\r\n        meta = client.head_object(namespace_name=namespace, bucket_name=bucket_name, object_name=OBJ_name)\r\n        #print(meta.headers&#91;'opc-meta-email'])\r\n        return meta.headers\r\n\r\n\r\n\r\n\r\n\r\ndef handler(ctx, data: io.BytesIO = None):\r\n\r\n    resp = None\r\n    #f = open('\/home\/opc\/fn-obj\/teste.json')\r\n\r\n    try:\r\n        \r\n        #body = json.load(f)\r\n        body = json.loads(data.getvalue())\r\n       \r\n        bucket_name = body&#91;\"data\"]&#91;\"additionalDetails\"]&#91;\"bucketName\"]\r\n        PAR_name =  \"par_\" + body&#91;\"data\"]&#91;\"resourceName\"] \r\n        OBJ_name = body&#91;\"data\"]&#91;\"resourceName\"] \r\n        \r\n\r\n\r\n\r\n        print (bucket_name)\r\n        print (PAR_name)\r\n        \r\n        print (OBJ_name)\r\n\r\n\r\n\r\n        signer = oci.auth.signers.get_resource_principals_signer()\r\n        emailMetadata = getMetadata(signer, bucket_name,OBJ_name)\r\n        #print (emailMetadata)\r\n        #print (emailMetadata&#91;'opc-meta-tempopar'])\r\n        if 'opc-meta-tempopar' in emailMetadata:\r\n            lifetime = int(emailMetadata&#91;'opc-meta-tempopar'])\r\n        else:\r\n            lifetime=10\r\n        resp = create_PAR(signer, bucket_name, PAR_name, lifetime,OBJ_name)\r\n        \r\n        validade = datetime.utcnow() + timedelta(minutes=lifetime)\r\n       \r\n        mail_content = \"Ola, seu PAR para o arquivo \" + OBJ_name + \" no bucket \" +bucket_name+\" \u00e9 o seguinte: \\n\" + resp + \"\\nValido at\u00e9 \" + str(validade)\r\n        print (mail_content)\r\n\r\n \r\n        #The mail addresses and password\r\n        sender_address = 'EMAIL_ORIGEM'\r\n        sender_pass = 'SENHA'\r\n        receiver_address = emailMetadata&#91;'opc-meta-emailto']\r\n        #Setup the MIME\r\n        message = MIMEMultipart()\r\n        message&#91;'From'] = sender_address\r\n        message&#91;'To'] = receiver_address\r\n        message&#91;'Subject'] = 'PAR ' + OBJ_name   #The subject line\r\n        #The body and the attachments for the mail\r\n        message.attach(MIMEText(mail_content, 'plain'))\r\n        #Create SMTP session for sending the mail\r\n        session = smtplib.SMTP('smtp.gmail.com', 587) #use gmail with port\r\n        session.starttls() #enable security\r\n        session.login(sender_address, sender_pass) #login with mail_id and password\r\n        text = message.as_string()\r\n        session.sendmail(sender_address, receiver_address, text)\r\n        session.quit()\r\n        print('Mail Sent')\r\n\r\n\r\n\r\n        return response.Response(\r\n          ctx, response_data=json.dumps(resp),\r\n            headers={\"Content-Type\": \"application\/json\"}\r\n        )\r\n    except (Exception, ValueError) as e:\r\n        print(\"Error \" + str(e), flush=True)<\/code><\/pre>\n\n\n\n<p>Coment\u00e1rios:<br><\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>Se a pessoa n\u00e3o entrar o metadado tempopar o PAR vai ter 10 minutos por padr\u00e3o<\/li><li>Ajuste os valores sender_address e sender_pass, nesse exemplo estou usando um gmail como origem mas voc\u00ea pode alterar o servidor de e-mail no session<\/li><li>Caso tamb\u00e9m use gmail, voc\u00ea precisa criar uma senha do tipo APP nas configura\u00e7\u00f5es de seguran\u00e7a<\/li><\/ul>\n\n\n\n<p><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Deploy da function<\/h2>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"614\" height=\"455\" src=\"https:\/\/adrianotanaka.com.br\/wp-content\/uploads\/2022\/03\/image-34.png\" alt=\"\" class=\"wp-image-858\" srcset=\"https:\/\/adrianotanaka.com.br\/wp-content\/uploads\/2022\/03\/image-34.png 614w, https:\/\/adrianotanaka.com.br\/wp-content\/uploads\/2022\/03\/image-34-300x222.png 300w\" sizes=\"auto, (max-width: 614px) 100vw, 614px\" \/><\/figure><\/div>\n\n\n\n<p>Crie um app para receber sua fun\u00e7\u00e3o:<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"636\" height=\"288\" src=\"https:\/\/adrianotanaka.com.br\/wp-content\/uploads\/2022\/03\/image-35.png\" alt=\"\" class=\"wp-image-859\" srcset=\"https:\/\/adrianotanaka.com.br\/wp-content\/uploads\/2022\/03\/image-35.png 636w, https:\/\/adrianotanaka.com.br\/wp-content\/uploads\/2022\/03\/image-35-300x136.png 300w\" sizes=\"auto, (max-width: 636px) 100vw, 636px\" \/><\/figure><\/div>\n\n\n\n<p>Siga o Getting Started que ele vai te guiar na cria\u00e7\u00e3o dos recursos b\u00e1sicos para a fn funcionar, aqui usei a modalidade Cloud Shell<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"326\" src=\"https:\/\/adrianotanaka.com.br\/wp-content\/uploads\/2022\/03\/image-36-1024x326.png\" alt=\"\" class=\"wp-image-860\" srcset=\"https:\/\/adrianotanaka.com.br\/wp-content\/uploads\/2022\/03\/image-36-1024x326.png 1024w, https:\/\/adrianotanaka.com.br\/wp-content\/uploads\/2022\/03\/image-36-300x96.png 300w, https:\/\/adrianotanaka.com.br\/wp-content\/uploads\/2022\/03\/image-36-768x245.png 768w, https:\/\/adrianotanaka.com.br\/wp-content\/uploads\/2022\/03\/image-36.png 1497w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure><\/div>\n\n\n\n<p>Ap\u00f3s isso, coloque o c\u00f3digo da fun\u00e7\u00e3o junto com o arquivo yaml de informa\u00e7\u00f5es e o requirements.txt dentro de um diret\u00f3rio do seu Cloud Shell e fa\u00e7a o deploy:<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"589\" height=\"286\" src=\"https:\/\/adrianotanaka.com.br\/wp-content\/uploads\/2022\/03\/image-37.png\" alt=\"\" class=\"wp-image-861\" srcset=\"https:\/\/adrianotanaka.com.br\/wp-content\/uploads\/2022\/03\/image-37.png 589w, https:\/\/adrianotanaka.com.br\/wp-content\/uploads\/2022\/03\/image-37-300x146.png 300w\" sizes=\"auto, (max-width: 589px) 100vw, 589px\" \/><\/figure><\/div>\n\n\n\n<p>Dica, nesse momento voc\u00ea pode ativar a op\u00e7\u00e3o de log da fun\u00e7\u00e3o para acompanhar o que est\u00e1 acontecendo nela.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Events<\/h2>\n\n\n\n<p>Vamos criar uma Rule que vai monitorar os eventos que ocorrem no Bucket, v\u00e1 em Observability &amp; Management -&gt; Events Service -&gt; Rules <\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"894\" height=\"562\" src=\"https:\/\/adrianotanaka.com.br\/wp-content\/uploads\/2022\/03\/image-32.png\" alt=\"\" class=\"wp-image-851\" srcset=\"https:\/\/adrianotanaka.com.br\/wp-content\/uploads\/2022\/03\/image-32.png 894w, https:\/\/adrianotanaka.com.br\/wp-content\/uploads\/2022\/03\/image-32-300x189.png 300w, https:\/\/adrianotanaka.com.br\/wp-content\/uploads\/2022\/03\/image-32-768x483.png 768w\" sizes=\"auto, (max-width: 894px) 100vw, 894px\" \/><\/figure>\n\n\n\n<p>Aqui no meu ambiente, estou monitorando cria\u00e7\u00e3o (Object &#8211; Create) e atualiza\u00e7\u00e3o (Object Update), al\u00e9m disso tamb\u00e9m coloquei como condi\u00e7\u00e3o apenas eventos que ocorram no Bucket com nome bucket-fast:<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"192\" src=\"https:\/\/adrianotanaka.com.br\/wp-content\/uploads\/2022\/03\/image-38-1024x192.png\" alt=\"\" class=\"wp-image-862\" srcset=\"https:\/\/adrianotanaka.com.br\/wp-content\/uploads\/2022\/03\/image-38-1024x192.png 1024w, https:\/\/adrianotanaka.com.br\/wp-content\/uploads\/2022\/03\/image-38-300x56.png 300w, https:\/\/adrianotanaka.com.br\/wp-content\/uploads\/2022\/03\/image-38-768x144.png 768w, https:\/\/adrianotanaka.com.br\/wp-content\/uploads\/2022\/03\/image-38-1536x287.png 1536w, https:\/\/adrianotanaka.com.br\/wp-content\/uploads\/2022\/03\/image-38.png 1572w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure><\/div>\n\n\n\n<p>Como a\u00e7\u00e3o, coloquei um t\u00f3pico do tipo e-mail (Tnk-OGG) para validar se o evento est\u00e1 sendo disparado(voc\u00ea pode remover essa a\u00e7\u00e3o depois de validar a FN) e a FN que criamos:<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"145\" src=\"https:\/\/adrianotanaka.com.br\/wp-content\/uploads\/2022\/03\/image-39-1024x145.png\" alt=\"\" class=\"wp-image-863\" srcset=\"https:\/\/adrianotanaka.com.br\/wp-content\/uploads\/2022\/03\/image-39-1024x145.png 1024w, https:\/\/adrianotanaka.com.br\/wp-content\/uploads\/2022\/03\/image-39-300x43.png 300w, https:\/\/adrianotanaka.com.br\/wp-content\/uploads\/2022\/03\/image-39-768x109.png 768w, https:\/\/adrianotanaka.com.br\/wp-content\/uploads\/2022\/03\/image-39-1536x218.png 1536w, https:\/\/adrianotanaka.com.br\/wp-content\/uploads\/2022\/03\/image-39.png 1574w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure><\/div>\n\n\n\n<h2 class=\"wp-block-heading\">Testando<\/h2>\n\n\n\n<p>Agora que j\u00e1 temos todos os recursos provisionados, vamos enviar um objeto e colocar os metadados necess\u00e1rios:<\/p>\n\n\n\n<p>Via console, basta cliar em Advanced e entrar os metadados emailto(quem vai receber o e-mail com o PAR) e tempopar (quanto tempo o PAR vai ser v\u00e1lido)<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/adrianotanaka.com.br\/wp-content\/uploads\/2022\/03\/image-40-1024x547.png\" alt=\"\" class=\"wp-image-865\" width=\"840\" height=\"448\" srcset=\"https:\/\/adrianotanaka.com.br\/wp-content\/uploads\/2022\/03\/image-40-1024x547.png 1024w, https:\/\/adrianotanaka.com.br\/wp-content\/uploads\/2022\/03\/image-40-300x160.png 300w, https:\/\/adrianotanaka.com.br\/wp-content\/uploads\/2022\/03\/image-40-768x411.png 768w, https:\/\/adrianotanaka.com.br\/wp-content\/uploads\/2022\/03\/image-40.png 1214w\" sizes=\"auto, (max-width: 840px) 100vw, 840px\" \/><\/figure><\/div>\n\n\n\n<p>Via oci cli<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>oci os object put -ns xxxxxx -bn bucket-fast --file history.log --metadata \n'{\"emailto\":\"adriano.tanaka@oracle.com\",\"tempopar\":\"25\"}'\n\n<\/code><\/pre>\n\n\n\n<p>Rule<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"1000\" height=\"190\" src=\"https:\/\/adrianotanaka.com.br\/wp-content\/uploads\/2022\/03\/image-42.png\" alt=\"\" class=\"wp-image-868\" srcset=\"https:\/\/adrianotanaka.com.br\/wp-content\/uploads\/2022\/03\/image-42.png 1000w, https:\/\/adrianotanaka.com.br\/wp-content\/uploads\/2022\/03\/image-42-300x57.png 300w, https:\/\/adrianotanaka.com.br\/wp-content\/uploads\/2022\/03\/image-42-768x146.png 768w\" sizes=\"auto, (max-width: 1000px) 100vw, 1000px\" \/><\/figure><\/div>\n\n\n\n<p>Aqui podemos ver que a rule foi disparada (Rule has matched event) e que ela executou nossas duas a\u00e7\u00f5es.<\/p>\n\n\n\n<p>PAR<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"667\" height=\"330\" src=\"https:\/\/adrianotanaka.com.br\/wp-content\/uploads\/2022\/03\/image-43.png\" alt=\"\" class=\"wp-image-869\" srcset=\"https:\/\/adrianotanaka.com.br\/wp-content\/uploads\/2022\/03\/image-43.png 667w, https:\/\/adrianotanaka.com.br\/wp-content\/uploads\/2022\/03\/image-43-300x148.png 300w\" sizes=\"auto, (max-width: 667px) 100vw, 667px\" \/><\/figure><\/div>\n\n\n\n<p>E-mail recebido<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"262\" src=\"https:\/\/adrianotanaka.com.br\/wp-content\/uploads\/2022\/03\/image-41-1024x262.png\" alt=\"\" class=\"wp-image-866\" srcset=\"https:\/\/adrianotanaka.com.br\/wp-content\/uploads\/2022\/03\/image-41-1024x262.png 1024w, https:\/\/adrianotanaka.com.br\/wp-content\/uploads\/2022\/03\/image-41-300x77.png 300w, https:\/\/adrianotanaka.com.br\/wp-content\/uploads\/2022\/03\/image-41-768x197.png 768w, https:\/\/adrianotanaka.com.br\/wp-content\/uploads\/2022\/03\/image-41.png 1121w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure><\/div>\n","protected":false},"excerpt":{"rendered":"<p>Um dos recursos que o Object Storage nos fornece \u00e9 disparar eventos quando ocorre uma intera\u00e7\u00e3o com ele, nesse artigo mostro como usar essa funcionalidade com o OCI Functions para gerar uma PAR e enviar um e-mail quando um objeto \u00e9 enviado\/alterado, al\u00e9m disso tamb\u00e9m vamos usar o custom metadata. Configura\u00e7\u00e3o do bucket Ao criar [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":850,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"material-hide-sections":[],"footnotes":""},"categories":[1],"tags":[],"class_list":["post-847","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/adrianotanaka.com.br\/index.php\/wp-json\/wp\/v2\/posts\/847","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/adrianotanaka.com.br\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/adrianotanaka.com.br\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/adrianotanaka.com.br\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/adrianotanaka.com.br\/index.php\/wp-json\/wp\/v2\/comments?post=847"}],"version-history":[{"count":11,"href":"https:\/\/adrianotanaka.com.br\/index.php\/wp-json\/wp\/v2\/posts\/847\/revisions"}],"predecessor-version":[{"id":871,"href":"https:\/\/adrianotanaka.com.br\/index.php\/wp-json\/wp\/v2\/posts\/847\/revisions\/871"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/adrianotanaka.com.br\/index.php\/wp-json\/wp\/v2\/media\/850"}],"wp:attachment":[{"href":"https:\/\/adrianotanaka.com.br\/index.php\/wp-json\/wp\/v2\/media?parent=847"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/adrianotanaka.com.br\/index.php\/wp-json\/wp\/v2\/categories?post=847"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/adrianotanaka.com.br\/index.php\/wp-json\/wp\/v2\/tags?post=847"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}