{"id":27840,"date":"2022-03-21T19:24:36","date_gmt":"2022-03-21T19:24:36","guid":{"rendered":"http:\/\/Creating-an-Asteroid-Map-with-the-NASA-API"},"modified":"2022-03-21T19:24:36","modified_gmt":"2022-03-21T19:24:36","slug":"creating-an-asteroid-map-with-the-nasa-api","status":"publish","type":"post","link":"https:\/\/cloudinary.com\/blog\/guest_post\/creating-an-asteroid-map-with-the-nasa-api\/","title":{"rendered":"Creating an Asteroid Map with a NASA API"},"content":{"rendered":"<div class=\"wp-block-cloudinary-markdown \"><p>There are a lot of cool APIs out there that let you work with interesting datasets. If you are interested in space at all, then the NASA APIs might be something you want to check out.<\/p>\n<p>In this post, we\u2019ll use one of the NASA APIs to create an asteroid map. This will give us a representation of how many asteroids came close to hitting the Earth and how big they were. We\u2019ll save these images to Cloudinary so we can review them later.<\/p>\n<h2>Initial setup<\/h2>\n<p>There are a few things we need to have in place before starting on the code. First, you\u2019ll need an API key for the NASA Asteroids &#8211; NeoWs API we\u2019ll be using. You can <a href=\"https:\/\/api.nasa.gov\/\">get a free one here<\/a>. It\u2019ll send the API key to the email you enter.<\/p>\n<p>Next, you\u2019ll need a Cloudinary account to store the asteroid map images that you can reference later. You can sign up for a <a href=\"https:\/\/cloudinary.com\/users\/register\/free\">free account here<\/a>.<\/p>\n<p>We\u2019ll be working with a local Postgres database, so if you don\u2019t have that installed, you can <a href=\"https:\/\/www.postgresql.org\/download\/\">download it here<\/a>.<\/p>\n<p>Now that we have all of these things set up, we can start working on the app.<\/p>\n<h2>Generate a new Redwood project<\/h2>\n<p>In a terminal, run the following command:<\/p>\n<pre class=\"js-syntax-highlighted\"><span><code class=\"hljs shcb-wrap-lines\">$ yarn create redwood-app asteroid-map\n<\/code><\/span><\/pre>\n<p>This will create a lot of new files and directories for you. Our focus will be in the <code>web<\/code> and <code>api<\/code> folders. The <code>web<\/code> folder is where we\u2019ll write all fo the front-end code in React. The <code>api<\/code> folder is where we\u2019ll handle the Postgres connection and the GraphQL back-end.<\/p>\n<h2>Create the database schema and connection<\/h2>\n<p>We\u2019ll start by connecting to the database and setting up our schema. First, open the <code>.env<\/code> file in the root of the project. You\u2019ll see a commented-out line that defines the <code>DATABASE_URL<\/code>. Uncomment that line and update it to match your local connection string. That might look similar to this:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-1\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\">DATABASE_URL=postgres:<span class=\"hljs-comment\">\/\/postgres:admin@localhost:5432\/asteroids<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-1\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>You won\u2019t need to create a new database manually. When we run the first migration, the <code>asteroids<\/code> database will be created for you.<\/p>\n<p>Now we can write the schema for the database. In the <code>api &gt; db<\/code> folder, open <code>schema.prisma<\/code>. Redwood uses <a href=\"https:\/\/prisma.io\/\">Prisma<\/a> to handle the database operations. This file is where we use the connection string and write the schema for all of our tables.<\/p>\n<p>Update the <code>provider<\/code> value from <code>sqlite<\/code> to <code>postgresql<\/code>. This tells Primsa we\u2019re working with a Postgres instance. You can see where the connection string is being read from the <code>DATABASE_URL<\/code> value we set earlier.<\/p>\n<p>Next, you can delete the example model and replace it with the following:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-2\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\">model <span class=\"hljs-built_in\">Map<\/span> {\n  id        Int    @id @<span class=\"hljs-keyword\">default<\/span>(autoincrement())\n  name      <span class=\"hljs-built_in\">String<\/span>\n  startDate DateTime\n  endDate   DateTime\n  mapUrl    <span class=\"hljs-built_in\">String<\/span>\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-2\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>This model represents the data we\u2019ll store in the database. The NASA API returns asteroid information based on the dates we submit, so we\u2019re storing those to know which dates correspond to the asteroid maps.<\/p>\n<h3>Running a database migration<\/h3>\n<p>Since we have the schema in place for the table we\u2019ll save the asteroid maps to, let\u2019s go ahead and run a database migration. In your terminal, run the following command:<\/p>\n<pre class=\"js-syntax-highlighted\"><span><code class=\"hljs shcb-wrap-lines\">$ yarn redwood prisma migrate dev\n<\/code><\/span><\/pre>\n<p>This will create the database (if needed) and then add the <code>Map<\/code> table to it.<\/p>\n<h2>Make the GraphQL types and resolvers<\/h2>\n<p>That\u2019s all we need to do on the database side of this app. Now we can turn to the GraphQL server. Redwood\u2019s CLI has a lot of commands that do some heavy lifting for us. We\u2019re going to generate the types and resolvers for our back-end with this command:<\/p>\n<pre class=\"js-syntax-highlighted\"><span><code class=\"hljs shcb-wrap-lines\">$ yarn redwood generate sdl --crud map\n<\/code><\/span><\/pre>\n<p>This will generate several files for us that handle all of the CRUD functionality for our maps. The only things we need to add are the types for the data we get from the NASA API and a resolver to fetch that data.<\/p>\n<h3>Adding the asteroid data types<\/h3>\n<p>In the <code>api &gt; src &gt; graphql<\/code> directory, open the newly generated <code>maps.sdl.ts<\/code> file. This already has the type definitions for the CRUD queries and mutations we might use to update the database.<\/p>\n<p>Now we\u2019ll add the type to define the data we\u2019ll get from the API, the input type to send to the API, and the query we can use to return the data. Right below the <code>Map<\/code> type, add this code:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-3\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\">type Asteroid {\n  <span class=\"hljs-attr\">missDistance<\/span>: <span class=\"hljs-built_in\">String<\/span>\n  <span class=\"hljs-attr\">estimatedDiameter<\/span>: <span class=\"hljs-built_in\">String<\/span>\n}\n\ninput AsteroidInput {\n  <span class=\"hljs-attr\">startDate<\/span>: <span class=\"hljs-built_in\">Date<\/span>!\n  endDate: <span class=\"hljs-built_in\">Date<\/span>!\n  viewDate: <span class=\"hljs-built_in\">Date<\/span>!\n}\n\ntype Query {\n  asteroids(input: AsteroidInput): &#91;Asteroid] @requireAuth\n  <span class=\"hljs-attr\">maps<\/span>: &#91;<span class=\"hljs-built_in\">Map<\/span>!]! @requireAuth\n  map(id: Int!): <span class=\"hljs-built_in\">Map<\/span> @requireAuth\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-3\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>That will give us access to the query and what it needs. Let\u2019s go define the resolver to fetch this data.<\/p>\n<h3>Calling the NASA API through a resolver<\/h3>\n<p>This is one of the cool things about GraphQL. You can call another API in a resolver and the data gets sent through the same endpoint as if it were hitting your own database.<\/p>\n<p>In <code>api &gt; src &gt; services &gt; maps<\/code>, open the <code>maps.js<\/code> file. This has the CRUD resolvers created from that CLI command we ran earlier. Below all of these, add the following resolver to fetch the asteroid data:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-4\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">const<\/span> asteroids = <span class=\"hljs-function\">(<span class=\"hljs-params\">{ input }<\/span>) =&gt;<\/span> {\n  <span class=\"hljs-keyword\">return<\/span> fetch(<span class=\"hljs-string\">`https:\/\/api.nasa.gov\/neo\/rest\/v1\/feed?start_date=<span class=\"hljs-subst\">${input.startDate.toISOString().split(<span class=\"hljs-string\">'T'<\/span>)&#91;<span class=\"hljs-number\">0<\/span>]}<\/span>&amp;end_date=<span class=\"hljs-subst\">${input.endDate.toISOString().split(<span class=\"hljs-string\">'T'<\/span>)&#91;<span class=\"hljs-number\">0<\/span>]}<\/span>&amp;api_key=<span class=\"hljs-subst\">${your_api_key_really_goes_here}<\/span>`<\/span>)\n  .then(<span class=\"hljs-function\"><span class=\"hljs-params\">response<\/span> =&gt;<\/span> {\n    <span class=\"hljs-keyword\">return<\/span> response.json()\n  })\n  .then(<span class=\"hljs-function\"><span class=\"hljs-params\">rawData<\/span> =&gt;<\/span> {\n    <span class=\"hljs-keyword\">const<\/span> data = rawData.near_earth_objects&#91;input.viewDate.toISOString().split(<span class=\"hljs-string\">'T'<\/span>)&#91;<span class=\"hljs-number\">0<\/span>]]\n\n    <span class=\"hljs-keyword\">const<\/span> asteroids = data.map(<span class=\"hljs-function\"><span class=\"hljs-params\">value<\/span> =&gt;<\/span> {\n      <span class=\"hljs-keyword\">return<\/span> {\n        <span class=\"hljs-attr\">missDistance<\/span>: value.close_approach_data&#91;<span class=\"hljs-number\">0<\/span>].miss_distance.kilometers,\n        <span class=\"hljs-attr\">estimatedDiameter<\/span>: value.estimated_diameter.kilometers.estimated_diameter_max\n      }\n    })\n    \n    <span class=\"hljs-keyword\">return<\/span> asteroids\n  })\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-4\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>This resolver takes the input we pass to it and makes this request to the API. Like with many API requests, we have to send the inputs in a particular format. That\u2019s why we\u2019re splitting the date string the way we are. GraphQL passes the date in a format the NASA API doesn\u2019t like.<\/p>\n<p>Then we get the data from the response and check out the asteroids that were close by on the <code>viewDate<\/code> we pass in. This date can be any time between the start and end dates. We take the data returned from the API and extract the values we need and that\u2019s what we pass in a successful response.<\/p>\n<p>That\u2019s everything for the back-end! We have all of the types and resolvers we need to get the asteroid data and save things to the database. We can turn our attention to the front-end where we\u2019ll wrap things up.<\/p>\n<h2>Building the user interface<\/h2>\n<p>Let\u2019s jump right in. There\u2019s one package that we need to install in order to save the asteroid maps we create. In your terminal, go to the <code>web<\/code> directory and run:<\/p>\n<pre class=\"js-syntax-highlighted\"><span><code class=\"hljs shcb-wrap-lines\">$ yarn add html-to-image\n<\/code><\/span><\/pre>\n<p>This will allow us to capture an image of the asteroid map really quickly.<\/p>\n<p>We can use the Redwood CLI to generate the asteroid map page for us. So in your terminal go back to the root of the project and run the following command:<\/p>\n<pre class=\"js-syntax-highlighted\"><span><code class=\"hljs shcb-wrap-lines\">$ yarn redwood generate page asteroid\n<\/code><\/span><\/pre>\n<p>This will update the <code>Routes.tsx<\/code> file to have this new path and it generates a few files for us in <code>web &gt; src &gt; pages &gt; AsteroidPage<\/code>. The file we will work in is <code>AsteroidPage.tsx<\/code>. Open this file and delete all of the existing import statements and replace them with these:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-5\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-keyword\">import<\/span> { useQuery, useMutation } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'@redwoodjs\/web'<\/span>\n<span class=\"hljs-keyword\">import<\/span> { useState, useRef } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'react'<\/span>\n<span class=\"hljs-keyword\">import<\/span> { toPng } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'html-to-image'<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-5\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>After these imports, we can add the GraphQL query to get our asteroid data and the mutation to save the map to the Cloudinary and the database.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-6\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php shcb-wrap-lines\"><span class=\"hljs-keyword\">const<\/span> CREATE_MAP_MUTATION = gql`\n  mutation CreateMapMutation($input: CreateMapInput!) {\n    createMap(input: $input) {\n      id\n    }\n  }\n`\n\n<span class=\"hljs-keyword\">const<\/span> GET_ASTEROIDS = gql`\n  query GetAsteroids($input: AsteroidInput!) {\n    asteroids(input: $input) {\n      missDistance\n      estimatedDiameter\n    }\n  }\n`\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-6\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<h3>Adding states and using hooks in the component<\/h3>\n<p>With all of the imports and GraphQL definitions in place, let\u2019s start working inside the <code>AsteroidPage<\/code> component. You can delete everything out of the component because we\u2019ll be writing a lot of different code.<\/p>\n<p>We\u2019ll start by adding the states and other hooks we need for the component.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-7\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-keyword\">const<\/span> &#91;createMap] = useMutation(CREATE_MAP_MUTATION)\n\n<span class=\"hljs-keyword\">const<\/span> canvasRef = useRef(<span class=\"hljs-literal\">null<\/span>)\n\n<span class=\"hljs-keyword\">const<\/span> &#91;startDate, setStartDate] = useState(<span class=\"hljs-string\">\"2021-08-12\"<\/span>)\n<span class=\"hljs-keyword\">const<\/span> &#91;endDate, setEndDate] = useState(<span class=\"hljs-string\">\"2021-08-15\"<\/span>)\n<span class=\"hljs-keyword\">const<\/span> &#91;viewDate, setViewDate] = useState(<span class=\"hljs-string\">\"2021-08-13\"<\/span>)\n\n<span class=\"hljs-keyword\">const<\/span> { loading, data } = useQuery(GET_ASTEROIDS, {\n  <span class=\"hljs-attr\">variables<\/span>: { <span class=\"hljs-attr\">input<\/span>: { <span class=\"hljs-attr\">startDate<\/span>: startDate, <span class=\"hljs-attr\">endDate<\/span>: endDate, <span class=\"hljs-attr\">viewDate<\/span>: viewDate }},\n})\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-7\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>First, we create the method that does the mutation to add new records to the database. Then we set the canvas ref that will hold the image of the asteroid map. Next, we set a few different date states. These will let us adjust what\u2019s in the map we save and what we see in the app.<\/p>\n<p>Then there\u2019s the data fetch query. This calls that resolver we made to get the asteroid data from the NASA API. We pass in the <code>input<\/code> in the shape we defined in the types on the back-end. These values come from the states, so whenever the state values change we can get a new asteroid map.<\/p>\n<h3>Having a loading state<\/h3>\n<p>You\u2019ll notice that we have a <code>loading<\/code> value from the <code>useQuery<\/code> call. This tells us if the data is still being fetched. It\u2019s important to have some kind of element that tells the user a page is loading. This also prevents the app from crashing when the data isn\u2019t available yet. So below the data query, add this code:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-8\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-keyword\">if<\/span> (loading) {\n  <span class=\"hljs-keyword\">return<\/span> <span class=\"xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span>&gt;<\/span>Loading...<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span><\/span>\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-8\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>This just renders a loading message on the page.<\/p>\n<h3>The elements that get rendered<\/h3>\n<p>Now that we have the data coming in, let\u2019s write the return statement for what should render on the page. Below the loading state check, add the following code and we\u2019ll go through it:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-9\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-keyword\">return<\/span> (\n  <span class=\"xml\"><span class=\"hljs-tag\">&lt;&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">h1<\/span>&gt;<\/span>AsteroidPage<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">h1<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">form<\/span> <span class=\"hljs-attr\">onSubmit<\/span>=<span class=\"hljs-string\">{submit}<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">label<\/span> <span class=\"hljs-attr\">htmlFor<\/span>=<span class=\"hljs-string\">\"mapName\"<\/span>&gt;<\/span>Map Name<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">label<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">input<\/span> <span class=\"hljs-attr\">type<\/span>=<span class=\"hljs-string\">\"text\"<\/span> <span class=\"hljs-attr\">name<\/span>=<span class=\"hljs-string\">\"mapName\"<\/span> \/&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">label<\/span> <span class=\"hljs-attr\">htmlFor<\/span>=<span class=\"hljs-string\">\"startDate\"<\/span>&gt;<\/span>Start Date<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">label<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">input<\/span> <span class=\"hljs-attr\">type<\/span>=<span class=\"hljs-string\">\"date\"<\/span> <span class=\"hljs-attr\">name<\/span>=<span class=\"hljs-string\">\"startDate\"<\/span> \/&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">label<\/span> <span class=\"hljs-attr\">htmlFor<\/span>=<span class=\"hljs-string\">\"endDate\"<\/span>&gt;<\/span>End Date<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">label<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">input<\/span> <span class=\"hljs-attr\">type<\/span>=<span class=\"hljs-string\">\"date\"<\/span> <span class=\"hljs-attr\">name<\/span>=<span class=\"hljs-string\">\"endDate\"<\/span> \/&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">label<\/span> <span class=\"hljs-attr\">htmlFor<\/span>=<span class=\"hljs-string\">\"viewDate\"<\/span>&gt;<\/span>View Date<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">label<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">input<\/span> <span class=\"hljs-attr\">type<\/span>=<span class=\"hljs-string\">\"date\"<\/span> <span class=\"hljs-attr\">name<\/span>=<span class=\"hljs-string\">\"viewDate\"<\/span> \/&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">button<\/span> <span class=\"hljs-attr\">type<\/span>=<span class=\"hljs-string\">\"submit\"<\/span>&gt;<\/span>Save Asteroid Map<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">button<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">form<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">button<\/span> <span class=\"hljs-attr\">type<\/span>=<span class=\"hljs-string\">\"button\"<\/span> <span class=\"hljs-attr\">onClick<\/span>=<span class=\"hljs-string\">{makeAsteroidMap}<\/span>&gt;<\/span>View Map<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">button<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">canvas<\/span> <span class=\"hljs-attr\">id<\/span>=<span class=\"hljs-string\">\"asteroidMap\"<\/span> <span class=\"hljs-attr\">ref<\/span>=<span class=\"hljs-string\">{canvasRef}<\/span> <span class=\"hljs-attr\">height<\/span>=<span class=\"hljs-string\">\"3000\"<\/span> <span class=\"hljs-attr\">width<\/span>=<span class=\"hljs-string\">\"3000\"<\/span>&gt;<\/span><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">canvas<\/span>&gt;<\/span>\n  <span class=\"hljs-tag\">&lt;\/&gt;<\/span><\/span>\n)\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-9\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>There\u2019s not as much going on as it might seem. We have a form that has a few input elements for the name we want to give an asteroid map and the dates we need to get the data and image. This form has a submit button that fetches new asteroid data based on our inputs and saves a new map.<\/p>\n<p>There\u2019s another button that lets us view the asteroid map in the canvas element below it. The canvas element is what we target in the <code>useRef<\/code> hook above. The form and view map buttons have functions that we need to write.<\/p>\n<p>If you want to look at the app so far, run <code>yarn redwood dev<\/code> in your terminal. You should see something like this.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/res.cloudinary.com\/jesse-thisdot\/image\/upload\/c_limit,w_2000\/f_auto\/q_auto\/v1639069205\/e-603fc55d218a650069f5228b\/ifpzozvsupyh1ovia8uz.png\" alt=\"basic user form for asteroid data input\" loading=\"lazy\" class=\"c-transformed-asset\"  width=\"1574\" height=\"936\"\/><\/p>\n<h3>The submit function<\/h3>\n<p>We\u2019ll add this function right below the loading state check. This will get the form data, update the date states, take a snapshot of the asteroid map in the canvas, upload it to Cloudinary, and then make a new database record.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-10\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-keyword\">async<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">submit<\/span>(<span class=\"hljs-params\">e<\/span>) <\/span>{\n  e.preventDefault()\n  <span class=\"hljs-keyword\">const<\/span> mapName = e.currentTarget.mapName.value\n  <span class=\"hljs-keyword\">const<\/span> startDate = e.currentTarget.startDate.value\n  <span class=\"hljs-keyword\">const<\/span> endDate = e.currentTarget.endDate.value\n  <span class=\"hljs-keyword\">const<\/span> viewDate = e.currentTarget.viewDate.value\n\n  setStartDate(startDate)\n  setEndDate(endDate)\n  setViewDate(viewDate)\n  \n  <span class=\"hljs-keyword\">if<\/span> (canvasRef.current === <span class=\"hljs-literal\">null<\/span>) {\n    <span class=\"hljs-keyword\">return<\/span>\n  }\n\n  <span class=\"hljs-keyword\">const<\/span> dataUrl = <span class=\"hljs-keyword\">await<\/span> toPng(canvasRef.current, { <span class=\"hljs-attr\">cacheBust<\/span>: <span class=\"hljs-literal\">true<\/span> })\n\n  <span class=\"hljs-keyword\">const<\/span> uploadApi = <span class=\"hljs-string\">`https:\/\/api.cloudinary.com\/v1_1\/<span class=\"hljs-subst\">${cloudName}<\/span>\/image\/upload`<\/span>\n\n  <span class=\"hljs-keyword\">const<\/span> formData = <span class=\"hljs-keyword\">new<\/span> FormData()\n  formData.append(<span class=\"hljs-string\">'file'<\/span>, dataUrl)\n  formData.append(<span class=\"hljs-string\">'upload_preset'<\/span>, upload_preset_value)\n\n  <span class=\"hljs-keyword\">const<\/span> cloudinaryRes = <span class=\"hljs-keyword\">await<\/span> fetch(uploadApi, {\n    <span class=\"hljs-attr\">method<\/span>: <span class=\"hljs-string\">'POST'<\/span>,\n    <span class=\"hljs-attr\">body<\/span>: formData,\n  })\n\n  <span class=\"hljs-keyword\">const<\/span> input = {\n    <span class=\"hljs-attr\">name<\/span>: mapName,\n    <span class=\"hljs-attr\">startDate<\/span>: <span class=\"hljs-keyword\">new<\/span> <span class=\"hljs-built_in\">Date<\/span>(startDate),\n    <span class=\"hljs-attr\">endDate<\/span>: <span class=\"hljs-keyword\">new<\/span> <span class=\"hljs-built_in\">Date<\/span>(endDate),\n    <span class=\"hljs-attr\">mapUrl<\/span>: cloudinaryRes.url\n  }\n\n  createMap({\n    <span class=\"hljs-attr\">variables<\/span>: { input },\n  })\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-10\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>You\u2019ll need to get your <code>cloudName<\/code> and upload preset value from your Cloudinary console. The only function left to write is the one to draw the asteroid map on the canvas.<\/p>\n<h3>Drawing the asteroid map<\/h3>\n<p>This will create a different sized circle at various distances from the left side of the page to show how close they were to Earth and how big they were.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-11\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">makeAsteroidMap<\/span>(<span class=\"hljs-params\"><\/span>) <\/span>{\n  <span class=\"hljs-keyword\">if<\/span> (canvasRef.current.getContext) {\n    <span class=\"hljs-keyword\">let<\/span> ctx = canvasRef.current.getContext(<span class=\"hljs-string\">'2d'<\/span>)\n\n    data.asteroids.forEach(<span class=\"hljs-function\">(<span class=\"hljs-params\">asteroid<\/span>) =&gt;<\/span> {\n      <span class=\"hljs-keyword\">const<\/span> scaledDistance = asteroid.missDistance \/ <span class=\"hljs-number\">75000<\/span>\n      <span class=\"hljs-keyword\">const<\/span> scaledSize = asteroid.estimatedDiameter * <span class=\"hljs-number\">100<\/span>\n      <span class=\"hljs-keyword\">let<\/span> circle = <span class=\"hljs-keyword\">new<\/span> Path2D()\n\n      circle.arc(scaledDistance * <span class=\"hljs-number\">2<\/span>, scaledDistance, scaledSize, <span class=\"hljs-number\">0<\/span>, <span class=\"hljs-number\">2<\/span> * <span class=\"hljs-built_in\">Math<\/span>.PI)\n  \n      ctx.fill(circle)\n    })\n  }\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-11\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>The scaling here isn\u2019t based on anything in particular, so feel free to play around with the math!<\/p>\n<p>Now if you run the app and click the View Map button, you\u2019ll see something like this.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/res.cloudinary.com\/jesse-thisdot\/image\/upload\/c_limit,w_2000\/f_auto\/q_auto\/v1639072537\/e-603fc55d218a650069f5228b\/uchtdfxvh86f6qw4i23r.png\" alt=\"the asteroid map\" loading=\"lazy\" class=\"c-transformed-asset\"  width=\"2000\" height=\"1046\"\/><\/p>\n<p>If you update the dates, you can view a different map and save it to the database. That\u2019s all of the code for this app!<\/p>\n<p>Now you can see how close we almost came to an asteroid event every day.<\/p>\n<h2>Finished code<\/h2>\n<p>You can take a look at the complete project in the <a href=\"https:\/\/github.com\/flippedcoder\/blog-examples\/tree\/main\/asteroid-map\"><code>asteroid-map<\/code> folder of this repo<\/a>. Or you can take a look at the front-end in <a href=\"https:\/\/codesandbox.io\/s\/reverent-lederberg-kbxsr\">this Code Sandbox<\/a>. You\u2019ll have to update some values to match yours in order for this to work.<\/p>\n<\/div>\n  \n  <div class=\"wp-block-cloudinary-code-sandbox \">\n    <iframe\n      src=\"https:\/\/codesandbox.io\/embed\/reverent-lederberg-kbxsr?theme=dark&amp;codemirror=1&amp;highlights=&amp;editorsize=50&amp;fontsize=14&amp;expanddevtools=0&amp;hidedevtools=0&amp;eslint=0&amp;forcerefresh=0&amp;hidenavigation=0&amp;initialpath=%2F&amp;module=&amp;moduleview=0&amp;previewwindow=&amp;view=&amp;runonclick=1\"\n      height=\"500\"\n      style=\"width: 100%;\"\n      title=\"reverent-lederberg-kbxsr\"\n      loading=\"lazy\"\n      allow=\"accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking\"\n      sandbox=\"allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts\"\n    ><\/iframe>\n  <\/div>\n\n  <div class=\"wp-block-cloudinary-markdown \"><h2>Conclusion<\/h2>\n<p>Working with external APIs is something we commonly do and GraphQL is one of the ways we can centralize all of the APIs we call. Using this as a tool to make visual representations of how close we came to being hit by asteroids every day is just a fun way to use that functionality.<\/p>\n<\/div>","protected":false},"excerpt":{"rendered":"","protected":false},"author":41,"featured_media":27841,"comment_status":"","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"_cloudinary_featured_overwrite":false,"footnotes":""},"categories":[1],"tags":[332,134,370,177,246,371],"class_list":["post-27840","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-uncategorized","tag-api","tag-guest-post","tag-image","tag-javascript","tag-react","tag-under-review"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v25.6 (Yoast SEO v26.9) - https:\/\/yoast.com\/product\/yoast-seo-premium-wordpress\/ -->\n<title>Creating an Asteroid Map with a NASA API<\/title>\n<meta name=\"description\" content=\"There are tons of cool APIs out there that give us access to all kinds of data. If you&#039;re into space things at all, you might be happy to know that NASA has APIs that let us work with some of their data. In this post, we&#039;ll see how you can make an asteroid map using one of these APIs.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/cloudinary.com\/blog\/guest_post\/creating-an-asteroid-map-with-the-nasa-api\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Creating an Asteroid Map with a NASA API\" \/>\n<meta property=\"og:description\" content=\"There are tons of cool APIs out there that give us access to all kinds of data. If you&#039;re into space things at all, you might be happy to know that NASA has APIs that let us work with some of their data. In this post, we&#039;ll see how you can make an asteroid map using one of these APIs.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/cloudinary.com\/blog\/guest_post\/creating-an-asteroid-map-with-the-nasa-api\/\" \/>\n<meta property=\"og:site_name\" content=\"Cloudinary Blog\" \/>\n<meta property=\"article:published_time\" content=\"2022-03-21T19:24:36+00:00\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:image\" content=\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681926136\/Web_Assets\/blog\/0a0ea18d19659910c20e9ecd19e52e691eadc92d-4852x3428-1_27841c4b2c\/0a0ea18d19659910c20e9ecd19e52e691eadc92d-4852x3428-1_27841c4b2c.jpg?_i=AA\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"NewsArticle\",\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/creating-an-asteroid-map-with-the-nasa-api\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/creating-an-asteroid-map-with-the-nasa-api\/\"},\"author\":{\"name\":\"\",\"@id\":\"\"},\"headline\":\"Creating an Asteroid Map with a NASA API\",\"datePublished\":\"2022-03-21T19:24:36+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/creating-an-asteroid-map-with-the-nasa-api\/\"},\"wordCount\":8,\"publisher\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#organization\"},\"image\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/creating-an-asteroid-map-with-the-nasa-api\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681926136\/Web_Assets\/blog\/0a0ea18d19659910c20e9ecd19e52e691eadc92d-4852x3428-1_27841c4b2c\/0a0ea18d19659910c20e9ecd19e52e691eadc92d-4852x3428-1_27841c4b2c.jpg?_i=AA\",\"keywords\":[\"API\",\"Guest Post\",\"Image\",\"Javascript\",\"React\",\"Under Review\"],\"inLanguage\":\"en-US\",\"copyrightYear\":\"2022\",\"copyrightHolder\":{\"@id\":\"https:\/\/cloudinary.com\/#organization\"}},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/creating-an-asteroid-map-with-the-nasa-api\/\",\"url\":\"https:\/\/cloudinary.com\/blog\/guest_post\/creating-an-asteroid-map-with-the-nasa-api\/\",\"name\":\"Creating an Asteroid Map with a NASA API\",\"isPartOf\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/creating-an-asteroid-map-with-the-nasa-api\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/creating-an-asteroid-map-with-the-nasa-api\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681926136\/Web_Assets\/blog\/0a0ea18d19659910c20e9ecd19e52e691eadc92d-4852x3428-1_27841c4b2c\/0a0ea18d19659910c20e9ecd19e52e691eadc92d-4852x3428-1_27841c4b2c.jpg?_i=AA\",\"datePublished\":\"2022-03-21T19:24:36+00:00\",\"description\":\"There are tons of cool APIs out there that give us access to all kinds of data. If you're into space things at all, you might be happy to know that NASA has APIs that let us work with some of their data. In this post, we'll see how you can make an asteroid map using one of these APIs.\",\"breadcrumb\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/creating-an-asteroid-map-with-the-nasa-api\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/cloudinary.com\/blog\/guest_post\/creating-an-asteroid-map-with-the-nasa-api\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/creating-an-asteroid-map-with-the-nasa-api\/#primaryimage\",\"url\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681926136\/Web_Assets\/blog\/0a0ea18d19659910c20e9ecd19e52e691eadc92d-4852x3428-1_27841c4b2c\/0a0ea18d19659910c20e9ecd19e52e691eadc92d-4852x3428-1_27841c4b2c.jpg?_i=AA\",\"contentUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681926136\/Web_Assets\/blog\/0a0ea18d19659910c20e9ecd19e52e691eadc92d-4852x3428-1_27841c4b2c\/0a0ea18d19659910c20e9ecd19e52e691eadc92d-4852x3428-1_27841c4b2c.jpg?_i=AA\",\"width\":4852,\"height\":3428},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/creating-an-asteroid-map-with-the-nasa-api\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/cloudinary.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Creating an Asteroid Map with a NASA API\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#website\",\"url\":\"https:\/\/cloudinary.com\/blog\/\",\"name\":\"Cloudinary Blog\",\"description\":\"\",\"publisher\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/cloudinary.com\/blog\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#organization\",\"name\":\"Cloudinary Blog\",\"url\":\"https:\/\/cloudinary.com\/blog\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718331\/Web_Assets\/blog\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA\",\"contentUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718331\/Web_Assets\/blog\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA\",\"width\":312,\"height\":60,\"caption\":\"Cloudinary Blog\"},\"image\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#\/schema\/logo\/image\/\"}},{\"@type\":\"Person\",\"@id\":\"\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Creating an Asteroid Map with a NASA API","description":"There are tons of cool APIs out there that give us access to all kinds of data. If you're into space things at all, you might be happy to know that NASA has APIs that let us work with some of their data. In this post, we'll see how you can make an asteroid map using one of these APIs.","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:\/\/cloudinary.com\/blog\/guest_post\/creating-an-asteroid-map-with-the-nasa-api\/","og_locale":"en_US","og_type":"article","og_title":"Creating an Asteroid Map with a NASA API","og_description":"There are tons of cool APIs out there that give us access to all kinds of data. If you're into space things at all, you might be happy to know that NASA has APIs that let us work with some of their data. In this post, we'll see how you can make an asteroid map using one of these APIs.","og_url":"https:\/\/cloudinary.com\/blog\/guest_post\/creating-an-asteroid-map-with-the-nasa-api\/","og_site_name":"Cloudinary Blog","article_published_time":"2022-03-21T19:24:36+00:00","twitter_card":"summary_large_image","twitter_image":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681926136\/Web_Assets\/blog\/0a0ea18d19659910c20e9ecd19e52e691eadc92d-4852x3428-1_27841c4b2c\/0a0ea18d19659910c20e9ecd19e52e691eadc92d-4852x3428-1_27841c4b2c.jpg?_i=AA","schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"NewsArticle","@id":"https:\/\/cloudinary.com\/blog\/guest_post\/creating-an-asteroid-map-with-the-nasa-api\/#article","isPartOf":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/creating-an-asteroid-map-with-the-nasa-api\/"},"author":{"name":"","@id":""},"headline":"Creating an Asteroid Map with a NASA API","datePublished":"2022-03-21T19:24:36+00:00","mainEntityOfPage":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/creating-an-asteroid-map-with-the-nasa-api\/"},"wordCount":8,"publisher":{"@id":"https:\/\/cloudinary.com\/blog\/#organization"},"image":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/creating-an-asteroid-map-with-the-nasa-api\/#primaryimage"},"thumbnailUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681926136\/Web_Assets\/blog\/0a0ea18d19659910c20e9ecd19e52e691eadc92d-4852x3428-1_27841c4b2c\/0a0ea18d19659910c20e9ecd19e52e691eadc92d-4852x3428-1_27841c4b2c.jpg?_i=AA","keywords":["API","Guest Post","Image","Javascript","React","Under Review"],"inLanguage":"en-US","copyrightYear":"2022","copyrightHolder":{"@id":"https:\/\/cloudinary.com\/#organization"}},{"@type":"WebPage","@id":"https:\/\/cloudinary.com\/blog\/guest_post\/creating-an-asteroid-map-with-the-nasa-api\/","url":"https:\/\/cloudinary.com\/blog\/guest_post\/creating-an-asteroid-map-with-the-nasa-api\/","name":"Creating an Asteroid Map with a NASA API","isPartOf":{"@id":"https:\/\/cloudinary.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/creating-an-asteroid-map-with-the-nasa-api\/#primaryimage"},"image":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/creating-an-asteroid-map-with-the-nasa-api\/#primaryimage"},"thumbnailUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681926136\/Web_Assets\/blog\/0a0ea18d19659910c20e9ecd19e52e691eadc92d-4852x3428-1_27841c4b2c\/0a0ea18d19659910c20e9ecd19e52e691eadc92d-4852x3428-1_27841c4b2c.jpg?_i=AA","datePublished":"2022-03-21T19:24:36+00:00","description":"There are tons of cool APIs out there that give us access to all kinds of data. If you're into space things at all, you might be happy to know that NASA has APIs that let us work with some of their data. In this post, we'll see how you can make an asteroid map using one of these APIs.","breadcrumb":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/creating-an-asteroid-map-with-the-nasa-api\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/cloudinary.com\/blog\/guest_post\/creating-an-asteroid-map-with-the-nasa-api\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/cloudinary.com\/blog\/guest_post\/creating-an-asteroid-map-with-the-nasa-api\/#primaryimage","url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681926136\/Web_Assets\/blog\/0a0ea18d19659910c20e9ecd19e52e691eadc92d-4852x3428-1_27841c4b2c\/0a0ea18d19659910c20e9ecd19e52e691eadc92d-4852x3428-1_27841c4b2c.jpg?_i=AA","contentUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681926136\/Web_Assets\/blog\/0a0ea18d19659910c20e9ecd19e52e691eadc92d-4852x3428-1_27841c4b2c\/0a0ea18d19659910c20e9ecd19e52e691eadc92d-4852x3428-1_27841c4b2c.jpg?_i=AA","width":4852,"height":3428},{"@type":"BreadcrumbList","@id":"https:\/\/cloudinary.com\/blog\/guest_post\/creating-an-asteroid-map-with-the-nasa-api\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/cloudinary.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Creating an Asteroid Map with a NASA API"}]},{"@type":"WebSite","@id":"https:\/\/cloudinary.com\/blog\/#website","url":"https:\/\/cloudinary.com\/blog\/","name":"Cloudinary Blog","description":"","publisher":{"@id":"https:\/\/cloudinary.com\/blog\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/cloudinary.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/cloudinary.com\/blog\/#organization","name":"Cloudinary Blog","url":"https:\/\/cloudinary.com\/blog\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/cloudinary.com\/blog\/#\/schema\/logo\/image\/","url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718331\/Web_Assets\/blog\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA","contentUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718331\/Web_Assets\/blog\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA","width":312,"height":60,"caption":"Cloudinary Blog"},"image":{"@id":"https:\/\/cloudinary.com\/blog\/#\/schema\/logo\/image\/"}},{"@type":"Person","@id":""}]}},"jetpack_featured_media_url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681926136\/Web_Assets\/blog\/0a0ea18d19659910c20e9ecd19e52e691eadc92d-4852x3428-1_27841c4b2c\/0a0ea18d19659910c20e9ecd19e52e691eadc92d-4852x3428-1_27841c4b2c.jpg?_i=AA","_links":{"self":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts\/27840","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/users\/41"}],"replies":[{"embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/comments?post=27840"}],"version-history":[{"count":0,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts\/27840\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/media\/27841"}],"wp:attachment":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/media?parent=27840"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/categories?post=27840"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/tags?post=27840"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}