{"id":220,"date":"2021-03-11T22:00:13","date_gmt":"2021-03-11T22:00:13","guid":{"rendered":"https:\/\/andrejacobs.org\/?p=220"},"modified":"2022-04-11T20:24:24","modified_gmt":"2022-04-11T20:24:24","slug":"100-days-of-learning-day-3-calling-another-api-from-our-openfaas-function","status":"publish","type":"post","link":"https:\/\/andrejacobs.org\/100-days-challenge\/100-days-of-learning-day-3-calling-another-api-from-our-openfaas-function\/","title":{"rendered":"100 Days of Learning: Day 3 \u2013 Calling another API from our OpenFaaS function"},"content":{"rendered":"\n

Photo by NASA<\/a> on Unsplash<\/a><\/p>\n\n\n\n

Here is my Log book<\/a><\/p>\n

Invoking the function directly<\/h2>\n

Building on from the previous days. What might not have been obvious at first is that you can invoke the function by talking directly to the API end point and not needing to use faas-cli invoke<\/code><\/p>\n

$ curl --data-binary '{"key":"value"}' --header "Content-Type: application\/json" http:\/\/192.168.64.4:8080\/function\/helloworld\n{"key":"value"}\n<\/code><\/pre>\n

Warm up for tonight – JSON prettifier<\/h2>\n

I am going to see if I can modify the helloworld function to take JSON as input and prettify it.<\/p>\n

But first I will test out the code in the Python REPL<\/p>\n

$ python\n>>> import json\n>>> req = '{"z": 1, "a": 2, "c": 3, "b": 4}'\n>>> data = json.loads(req)\n>>> response = json.dumps(data, indent=4, sort_keys=True)\n>>> response\n'{\\n    "a": 2, \\n    "b": 4, \\n    "c": 3, \\n    "z": 1\\n}'\n<\/code><\/pre>\n

Ok that worked so next I need to modify the [handler.py](http:\/\/handler.py)<\/code> file. Disclaimer: I am not worried about error handling or any of the production coding here.<\/p>\n

import json\n\ndef handle(req):\n    data = json.loads(req)\n    response = json.dumps(data, indent=4, sort_keys=True)\n    return response\n<\/code><\/pre>\n

Rebuild and redeploy with faas-cli<\/code><\/p>\n

$ faas-cli up -f helloworld.yml\n...\nDeployed. 200 OK.\nURL: http:\/\/192.168.64.4:8080\/function\/helloworld.openfaas-fn\n<\/code><\/pre>\n

Verify by throwing some JSON at it<\/p>\n

$ curl --data-binary '{"z": 1, "a": 2, "c": 3, "b": 4}' --header "Content-Type: application\/json" http:\/\/192.168.64.4:8080\/function\/helloworld\n{\n    "a": 2,\n    "b": 4,\n    "c": 3,\n    "z": 1\n}\n<\/code><\/pre>\n

Nice one! I also checked Docker Hub and indeed there is only 1 image that has been updated.<\/p>\n

Lets write a function that calls a 3rd party API<\/h2>\n

For this I am going to be following the example from Serverless for Everyone Else<\/a> that uses Node.js.<\/p>\n

Which API to call? In the book Alex uses http:\/\/open-notify.org<\/a> to get the number of Astronauts currently in space. I will be using their API that gives the geolocation of where the International Space Station is.<\/p>\n

See "International Space Station Current Location"<\/a> for more information on the API as well as a Python example.<\/p>\n

International Space Station Location<\/h3>\n

\"\"<\/p>\n

Create a new function from the node12 template<\/p>\n

\u256d ~\/Learning\/faasd                                                            [20:23:45]\n\u2570 $ faas-cli new --lang node12 iss-location\n<\/code><\/pre>\n

Whoops! I forgot to first create a directory in which to create the files, so now the files are mixed with my other function.<\/p>\n

$ mkdir temp\n$ mv iss* temp\n$ mv template temp\n$ mv temp iss-location\n$ ls\nhelloworld\/   iss-location\/ password.txt\n$ cd iss-location\n<\/code><\/pre>\n

Time to write some code $ mate iss-location\/handler.js<\/code> (I love TextMate<\/a>, been my text editor on mac for probably 10 years). Note: I am not proficient in JS or node.<\/p>\n

'use strict'\n\nconst axios = require("axios")\n\nmodule.exports = async (event, context) => {\n\tlet issResponse = await axios.get("http:\/\/api.open-notify.org\/iss-now.json")\n\tlet body = {"lat": issResponse.data.iss_position.latitude,\n\t\t"long": issResponse.data.iss_position.longitude\n\t}\n\treturn context\n\t\t.status(200)\n\t\t.headers({"Content-type": "application\/json"})\n\t\t.succeed(body)\n}\n<\/code><\/pre>\n

Need to install axios package first.<\/p>\n

$ npm install --save axios\n<\/code><\/pre>\n

Build and deploy the function.<\/p>\n

$ faas-cli up -f iss-location.yml\n...\nDeployed. 200 OK.\nURL: http:\/\/192.168.64.4:8080\/function\/iss-location.openfaas-fn\n<\/code><\/pre>\n

I tried to curl the end point and nothing. I checked the UI and it says "not ready". Ok so something is wrong (and I bet my code is wrong).<\/p>\n

$ faas-cli describe iss-location\nName:                iss-location\nStatus:              Not Ready\nReplicas:            0\nAvailable replicas:  0\nInvocations:         1\nImage:\nFunction process:    node index.js\n<\/code><\/pre>\n

It says that the status = Not Ready and also the Replicas = 0 (whereas my other functions = 1)<\/p>\n

$ curl -i http:\/\/192.168.64.4:8080\/function\/iss-location\nHTTP\/1.1 500 Internal Server Error\nContent-Length: 0\nContent-Type: text\/plain\nDate: Thu, 11 Mar 2021 20:58:45 GMT\nX-Call-Id: 50fb978e-160f-4f5e-824e-f5bcd4db5100\nX-Duration-Seconds: 0.000556\nX-Start-Time: 1615496325470597568\n<\/code><\/pre>\n

Learning action point:<\/strong> I do wonder how can you get to error logs or something when things go wrong on the webserver \/ multipass instance? At the moment the debugging is, poke something and see if it works.<\/p>\n

Ok I have narrowed it down to node not being happy about the line: const axios = require("axios") which means it can’t find the node package. Watching Alex’s workshop video I can see that I was suppose to install axios inside the directory where the handler.js file is.<\/p>\n

\u256d ~\/Learning\/faasd\/iss-location\/iss-location                                             [21:09:59]\n\u2570 $ ls\nhandler.js         node_modules\/      package-lock.json  package.json\n\n$ faas-cli describe iss-location\nName:                iss-location\nStatus:              Ready\nReplicas:            1\n<\/code><\/pre>\n

Bingo! Ok time to put all the code back like I wrote it earlier in this post and then faas-cli up<\/code> again.<\/p>\n

Moment of truth<\/h2>\n
$ faas-cli up -f iss-location.yml\n...\n$ curl http:\/\/192.168.64.4:8080\/function\/iss-location\n{"lat":"-50.3286","long":"-138.4613"}\n<\/code><\/pre>\n

Woo hoo!<\/strong><\/p>\n<\/div>\n","protected":false},"excerpt":{"rendered":"

Photo by NASA on Unsplash […]<\/p>\n

Read more →<\/a><\/p>\n","protected":false},"author":2,"featured_media":223,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_mi_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"footnotes":""},"categories":[37],"tags":[36],"yoast_head":"\n100 Days of Learning: Day 3 \u2013 Calling another API from our OpenFaaS function - Andr\u00e9 Jacobs<\/title>\n<meta name=\"description\" content=\"Day 3 of 100 complete! Today I learned how to use the node12 template and axios to make a call to another 3rd party API end point.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/andrejacobs.org\/100-days-challenge\/100-days-of-learning-day-3-calling-another-api-from-our-openfaas-function\/\" \/>\n<meta property=\"og:locale\" content=\"en_GB\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"100 Days of Learning: Day 3 \u2013 Calling another API from our OpenFaaS function - Andr\u00e9 Jacobs\" \/>\n<meta property=\"og:description\" content=\"Day 3 of 100 complete! Today I learned how to use the node12 template and axios to make a call to another 3rd party API end point.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/andrejacobs.org\/100-days-challenge\/100-days-of-learning-day-3-calling-another-api-from-our-openfaas-function\/\" \/>\n<meta property=\"og:site_name\" content=\"Andr\u00e9 Jacobs\" \/>\n<meta property=\"article:published_time\" content=\"2021-03-11T22:00:13+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2022-04-11T20:24:24+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/andrejacobs.org\/wp-content\/uploads\/2021\/03\/nasa-wAkLQnT2TC0-unsplash.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"1920\" \/>\n\t<meta property=\"og:image:height\" content=\"1440\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"Andr\u00e9 Jacobs\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@andrejacobs81\" \/>\n<meta name=\"twitter:site\" content=\"@andrejacobs81\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Andr\u00e9 Jacobs\" \/>\n\t<meta name=\"twitter:label2\" content=\"Estimated reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"4 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/andrejacobs.org\/100-days-challenge\/100-days-of-learning-day-3-calling-another-api-from-our-openfaas-function\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/andrejacobs.org\/100-days-challenge\/100-days-of-learning-day-3-calling-another-api-from-our-openfaas-function\/\"},\"author\":{\"name\":\"Andr\u00e9 Jacobs\",\"@id\":\"https:\/\/andrejacobs.org\/#\/schema\/person\/3d38360883015e883c80c2fb875c5a68\"},\"headline\":\"100 Days of Learning: Day 3 \u2013 Calling another API from our OpenFaaS function\",\"datePublished\":\"2021-03-11T22:00:13+00:00\",\"dateModified\":\"2022-04-11T20:24:24+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/andrejacobs.org\/100-days-challenge\/100-days-of-learning-day-3-calling-another-api-from-our-openfaas-function\/\"},\"wordCount\":474,\"publisher\":{\"@id\":\"https:\/\/andrejacobs.org\/#\/schema\/person\/3d38360883015e883c80c2fb875c5a68\"},\"keywords\":[\"OpenFaaS\"],\"articleSection\":[\"100 Days Challenge\"],\"inLanguage\":\"en-GB\"},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/andrejacobs.org\/100-days-challenge\/100-days-of-learning-day-3-calling-another-api-from-our-openfaas-function\/\",\"url\":\"https:\/\/andrejacobs.org\/100-days-challenge\/100-days-of-learning-day-3-calling-another-api-from-our-openfaas-function\/\",\"name\":\"100 Days of Learning: Day 3 \u2013 Calling another API from our OpenFaaS function - Andr\u00e9 Jacobs\",\"isPartOf\":{\"@id\":\"https:\/\/andrejacobs.org\/#website\"},\"datePublished\":\"2021-03-11T22:00:13+00:00\",\"dateModified\":\"2022-04-11T20:24:24+00:00\",\"description\":\"Day 3 of 100 complete! Today I learned how to use the node12 template and axios to make a call to another 3rd party API end point.\",\"breadcrumb\":{\"@id\":\"https:\/\/andrejacobs.org\/100-days-challenge\/100-days-of-learning-day-3-calling-another-api-from-our-openfaas-function\/#breadcrumb\"},\"inLanguage\":\"en-GB\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/andrejacobs.org\/100-days-challenge\/100-days-of-learning-day-3-calling-another-api-from-our-openfaas-function\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/andrejacobs.org\/100-days-challenge\/100-days-of-learning-day-3-calling-another-api-from-our-openfaas-function\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/andrejacobs.org\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"100 Days of Learning: Day 3 \u2013 Calling another API from our OpenFaaS function\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/andrejacobs.org\/#website\",\"url\":\"https:\/\/andrejacobs.org\/\",\"name\":\"Andr\u00e9 Jacobs\",\"description\":\"iOS Development, Electronics, Robotics, Artificial Intelligence, Business and Health\",\"publisher\":{\"@id\":\"https:\/\/andrejacobs.org\/#\/schema\/person\/3d38360883015e883c80c2fb875c5a68\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/andrejacobs.org\/?s={search_term_string}\"},\"query-input\":\"required name=search_term_string\"}],\"inLanguage\":\"en-GB\"},{\"@type\":[\"Person\",\"Organization\"],\"@id\":\"https:\/\/andrejacobs.org\/#\/schema\/person\/3d38360883015e883c80c2fb875c5a68\",\"name\":\"Andr\u00e9 Jacobs\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-GB\",\"@id\":\"https:\/\/andrejacobs.org\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/andrejacobs.org\/wp-content\/uploads\/2019\/03\/andre_jacobs.jpg\",\"contentUrl\":\"https:\/\/andrejacobs.org\/wp-content\/uploads\/2019\/03\/andre_jacobs.jpg\",\"width\":450,\"height\":450,\"caption\":\"Andr\u00e9 Jacobs\"},\"logo\":{\"@id\":\"https:\/\/andrejacobs.org\/#\/schema\/person\/image\/\"},\"sameAs\":[\"https:\/\/andrejacobs.org\",\"https:\/\/www.youtube.com\/channel\/UCzqXvnd_UJ3sAzQkQBD-IVw\"],\"url\":\"https:\/\/andrejacobs.org\/author\/andre\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"100 Days of Learning: Day 3 \u2013 Calling another API from our OpenFaaS function - Andr\u00e9 Jacobs","description":"Day 3 of 100 complete! Today I learned how to use the node12 template and axios to make a call to another 3rd party API end point.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/andrejacobs.org\/100-days-challenge\/100-days-of-learning-day-3-calling-another-api-from-our-openfaas-function\/","og_locale":"en_GB","og_type":"article","og_title":"100 Days of Learning: Day 3 \u2013 Calling another API from our OpenFaaS function - Andr\u00e9 Jacobs","og_description":"Day 3 of 100 complete! Today I learned how to use the node12 template and axios to make a call to another 3rd party API end point.","og_url":"https:\/\/andrejacobs.org\/100-days-challenge\/100-days-of-learning-day-3-calling-another-api-from-our-openfaas-function\/","og_site_name":"Andr\u00e9 Jacobs","article_published_time":"2021-03-11T22:00:13+00:00","article_modified_time":"2022-04-11T20:24:24+00:00","og_image":[{"width":1920,"height":1440,"url":"https:\/\/andrejacobs.org\/wp-content\/uploads\/2021\/03\/nasa-wAkLQnT2TC0-unsplash.jpg","type":"image\/jpeg"}],"author":"Andr\u00e9 Jacobs","twitter_card":"summary_large_image","twitter_creator":"@andrejacobs81","twitter_site":"@andrejacobs81","twitter_misc":{"Written by":"Andr\u00e9 Jacobs","Estimated reading time":"4 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/andrejacobs.org\/100-days-challenge\/100-days-of-learning-day-3-calling-another-api-from-our-openfaas-function\/#article","isPartOf":{"@id":"https:\/\/andrejacobs.org\/100-days-challenge\/100-days-of-learning-day-3-calling-another-api-from-our-openfaas-function\/"},"author":{"name":"Andr\u00e9 Jacobs","@id":"https:\/\/andrejacobs.org\/#\/schema\/person\/3d38360883015e883c80c2fb875c5a68"},"headline":"100 Days of Learning: Day 3 \u2013 Calling another API from our OpenFaaS function","datePublished":"2021-03-11T22:00:13+00:00","dateModified":"2022-04-11T20:24:24+00:00","mainEntityOfPage":{"@id":"https:\/\/andrejacobs.org\/100-days-challenge\/100-days-of-learning-day-3-calling-another-api-from-our-openfaas-function\/"},"wordCount":474,"publisher":{"@id":"https:\/\/andrejacobs.org\/#\/schema\/person\/3d38360883015e883c80c2fb875c5a68"},"keywords":["OpenFaaS"],"articleSection":["100 Days Challenge"],"inLanguage":"en-GB"},{"@type":"WebPage","@id":"https:\/\/andrejacobs.org\/100-days-challenge\/100-days-of-learning-day-3-calling-another-api-from-our-openfaas-function\/","url":"https:\/\/andrejacobs.org\/100-days-challenge\/100-days-of-learning-day-3-calling-another-api-from-our-openfaas-function\/","name":"100 Days of Learning: Day 3 \u2013 Calling another API from our OpenFaaS function - Andr\u00e9 Jacobs","isPartOf":{"@id":"https:\/\/andrejacobs.org\/#website"},"datePublished":"2021-03-11T22:00:13+00:00","dateModified":"2022-04-11T20:24:24+00:00","description":"Day 3 of 100 complete! Today I learned how to use the node12 template and axios to make a call to another 3rd party API end point.","breadcrumb":{"@id":"https:\/\/andrejacobs.org\/100-days-challenge\/100-days-of-learning-day-3-calling-another-api-from-our-openfaas-function\/#breadcrumb"},"inLanguage":"en-GB","potentialAction":[{"@type":"ReadAction","target":["https:\/\/andrejacobs.org\/100-days-challenge\/100-days-of-learning-day-3-calling-another-api-from-our-openfaas-function\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/andrejacobs.org\/100-days-challenge\/100-days-of-learning-day-3-calling-another-api-from-our-openfaas-function\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/andrejacobs.org\/"},{"@type":"ListItem","position":2,"name":"100 Days of Learning: Day 3 \u2013 Calling another API from our OpenFaaS function"}]},{"@type":"WebSite","@id":"https:\/\/andrejacobs.org\/#website","url":"https:\/\/andrejacobs.org\/","name":"Andr\u00e9 Jacobs","description":"iOS Development, Electronics, Robotics, Artificial Intelligence, Business and Health","publisher":{"@id":"https:\/\/andrejacobs.org\/#\/schema\/person\/3d38360883015e883c80c2fb875c5a68"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/andrejacobs.org\/?s={search_term_string}"},"query-input":"required name=search_term_string"}],"inLanguage":"en-GB"},{"@type":["Person","Organization"],"@id":"https:\/\/andrejacobs.org\/#\/schema\/person\/3d38360883015e883c80c2fb875c5a68","name":"Andr\u00e9 Jacobs","image":{"@type":"ImageObject","inLanguage":"en-GB","@id":"https:\/\/andrejacobs.org\/#\/schema\/person\/image\/","url":"https:\/\/andrejacobs.org\/wp-content\/uploads\/2019\/03\/andre_jacobs.jpg","contentUrl":"https:\/\/andrejacobs.org\/wp-content\/uploads\/2019\/03\/andre_jacobs.jpg","width":450,"height":450,"caption":"Andr\u00e9 Jacobs"},"logo":{"@id":"https:\/\/andrejacobs.org\/#\/schema\/person\/image\/"},"sameAs":["https:\/\/andrejacobs.org","https:\/\/www.youtube.com\/channel\/UCzqXvnd_UJ3sAzQkQBD-IVw"],"url":"https:\/\/andrejacobs.org\/author\/andre\/"}]}},"jetpack_sharing_enabled":true,"jetpack_featured_media_url":"https:\/\/andrejacobs.org\/wp-content\/uploads\/2021\/03\/nasa-wAkLQnT2TC0-unsplash.jpg","_links":{"self":[{"href":"https:\/\/andrejacobs.org\/wp-json\/wp\/v2\/posts\/220"}],"collection":[{"href":"https:\/\/andrejacobs.org\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/andrejacobs.org\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/andrejacobs.org\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/andrejacobs.org\/wp-json\/wp\/v2\/comments?post=220"}],"version-history":[{"count":3,"href":"https:\/\/andrejacobs.org\/wp-json\/wp\/v2\/posts\/220\/revisions"}],"predecessor-version":[{"id":225,"href":"https:\/\/andrejacobs.org\/wp-json\/wp\/v2\/posts\/220\/revisions\/225"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/andrejacobs.org\/wp-json\/wp\/v2\/media\/223"}],"wp:attachment":[{"href":"https:\/\/andrejacobs.org\/wp-json\/wp\/v2\/media?parent=220"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/andrejacobs.org\/wp-json\/wp\/v2\/categories?post=220"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/andrejacobs.org\/wp-json\/wp\/v2\/tags?post=220"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}