<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: ZahidRahman47</title>
    <description>The latest articles on DEV Community by ZahidRahman47 (@zahidrahman47).</description>
    <link>https://dev.to/zahidrahman47</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1378212%2F14aa6878-0618-4970-9580-d098939b06a1.jpg</url>
      <title>DEV Community: ZahidRahman47</title>
      <link>https://dev.to/zahidrahman47</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/zahidrahman47"/>
    <language>en</language>
    <item>
      <title>I turned a public-domain government CSV into a searchable index of every port and airport on Earth</title>
      <dc:creator>ZahidRahman47</dc:creator>
      <pubDate>Wed, 15 Jul 2026 19:54:30 +0000</pubDate>
      <link>https://dev.to/zahidrahman47/i-turned-a-public-domain-government-csv-into-a-searchable-index-of-every-port-and-airport-on-earth-495j</link>
      <guid>https://dev.to/zahidrahman47/i-turned-a-public-domain-government-csv-into-a-searchable-index-of-every-port-and-airport-on-earth-495j</guid>
      <description>&lt;p&gt;For a side project I needed something that turned out to be weirdly hard to find: a free, clean list of the world's seaports — real depths, coordinates, and the codes ships actually use. Everything out there was paywalled, login-walled, or a table that looked untouched since 2005.&lt;/p&gt;

&lt;p&gt;So I built the thing I wanted. Then it grew: &lt;strong&gt;&lt;a href="https://www.theportindex.online" rel="noopener noreferrer"&gt;The Port Index&lt;/a&gt;&lt;/strong&gt; — 3,804 seaports and 9,640 airports, free, no signup, and the whole dataset &lt;a href="https://www.theportindex.online/data" rel="noopener noreferrer"&gt;downloadable as CSV/JSON&lt;/a&gt;. Here's what I learned building it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The data is all public domain — you just have to find it
&lt;/h2&gt;

&lt;p&gt;No scraping, no licensing fees. Three public-domain sources do the heavy lifting:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;NGA World Port Index (Pub 150)&lt;/strong&gt; — a U.S. government dataset of ~4,000 ports, each with 100+ coded attributes (depths, max vessel size, pilotage, facilities…).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;UN/LOCODE&lt;/strong&gt; — the UNECE location codes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;OurAirports&lt;/strong&gt; — a public-domain database behind the 9,640 airports (IATA/ICAO codes, runways, elevation).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Public data is everywhere; the value is in making it &lt;em&gt;usable&lt;/em&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The data-cleaning was the actual project
&lt;/h2&gt;

&lt;p&gt;The "just parse a CSV" part is where all the interesting bugs live:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Quoted fields with embedded newlines.&lt;/strong&gt; The WPI CSV has multi-line values inside quotes. Naive &lt;code&gt;split('\n')&lt;/code&gt; shreds it into garbage. You need a real CSV parser that respects quoting.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Offshore oil terminals listed with 900+ meter "depths."&lt;/strong&gt; That's the &lt;em&gt;ocean floor at the mooring buoy&lt;/em&gt;, not a harbor depth. Left in, they made my "deepest ports" ranking pure nonsense — a cluster of open-ocean SPM buoys beating every real deep-water port. I had to detect and filter them.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Zeros that mean "unknown."&lt;/strong&gt; The source uses &lt;code&gt;0&lt;/code&gt; for "not reported." Trust it blindly and you'll confidently render "0 m channel depth" for half the world.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Display data, or derive intelligence?
&lt;/h2&gt;

&lt;p&gt;A depth of &lt;code&gt;14.5 m&lt;/code&gt; is boring. A depth that tells you &lt;em&gt;"this berth can take a Panamax but not a Capesize"&lt;/em&gt; is useful. So I built a small inference layer: &lt;strong&gt;depth → vessel class&lt;/strong&gt; for ports, and its aviation twin, &lt;strong&gt;runway length → aircraft class&lt;/strong&gt; for airports.&lt;/p&gt;

&lt;p&gt;The part I'm most into is the &lt;strong&gt;cross-modal graph&lt;/strong&gt;: every port page lists its nearest airports, and every airport page lists its nearest seaports — computed at build time with a simple spatial grid. That linked structure is where a directory stops being a lookup table and starts being something you can explore.&lt;/p&gt;

&lt;h2&gt;
  
  
  14,000 pages, zero backend
&lt;/h2&gt;

&lt;p&gt;The whole thing is &lt;strong&gt;Next.js, fully static&lt;/strong&gt;. &lt;code&gt;generateStaticParams&lt;/code&gt; runs over the entire dataset and pre-renders ~14,000 pages at build time. No database, no server, no runtime cost — it deploys to a CDN and is basically free to run and very fast.&lt;/p&gt;

&lt;h2&gt;
  
  
  The SEO lesson I didn't expect (the useful bit for other devs)
&lt;/h2&gt;

&lt;p&gt;If you're building a &lt;em&gt;programmatic&lt;/em&gt; site, here's a trap I hit face-first: dump 14,000 templated pages into Google's index and it flags you for &lt;strong&gt;"scaled / thin content."&lt;/strong&gt; I learned this the hard way with an AdSense rejection.&lt;/p&gt;

&lt;p&gt;The fix that worked: a &lt;strong&gt;lean core&lt;/strong&gt;. Only the ~400 highest-quality pages per vertical are indexable and in the sitemap; the long tail stays fully live for users but is marked &lt;code&gt;noindex, follow&lt;/code&gt;. You earn Google's trust with a small, genuinely-good set first, then expand the indexable core as the domain gains authority. If you're doing programmatic SEO, bake this in from day one instead of discovering it later.&lt;/p&gt;

&lt;h2&gt;
  
  
  It's free, and the data is yours
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Browse it:&lt;/strong&gt; &lt;a href="https://www.theportindex.online" rel="noopener noreferrer"&gt;theportindex.online&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Download the full datasets&lt;/strong&gt; (CSV + JSON, with documented columns): &lt;a href="https://www.theportindex.online/data" rel="noopener noreferrer"&gt;theportindex.online/data&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Also mirrored on &lt;a href="https://www.kaggle.com/datasets/zahidrahman47/world-seaports-and-airports-depths-codes" rel="noopener noreferrer"&gt;Kaggle&lt;/a&gt; and &lt;a href="https://huggingface.co/datasets/programmer47/world-seaports-and-airports" rel="noopener noreferrer"&gt;Hugging Face&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All of it is built on public-domain data — use it for whatever you like.&lt;/p&gt;

&lt;p&gt;I'd love feedback, especially from anyone in shipping, logistics, or aviation: &lt;strong&gt;what data or features would actually be useful to you?&lt;/strong&gt; And for the builders — what would you make with a clean, global port + airport dataset?&lt;/p&gt;

</description>
      <category>showdev</category>
      <category>webdev</category>
      <category>nextjs</category>
      <category>datascience</category>
    </item>
    <item>
      <title>uploading file into pinata</title>
      <dc:creator>ZahidRahman47</dc:creator>
      <pubDate>Sat, 23 Mar 2024 21:34:33 +0000</pubDate>
      <link>https://dev.to/zahidrahman47/uploading-file-into-pinata-22ce</link>
      <guid>https://dev.to/zahidrahman47/uploading-file-into-pinata-22ce</guid>
      <description>&lt;p&gt;hello family. in this function i want to send multiple png,s to pinata using their file upload system and then i want to fetch the images and map it inside my react app here is my code please some one let me know if they already face this issue .&lt;/p&gt;

&lt;p&gt;`const handleImageChange = async () =&amp;gt; {&lt;br&gt;
    setLoaderThree(true);&lt;br&gt;
    try {&lt;br&gt;
      const formData = new FormData();&lt;br&gt;
      const files = Array.from(selectedFile);&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  files.forEach((file) =&amp;gt; {
    console.log(file.name);
    formData.append("file", file);
    formData.append(
      "pinataMetadata",
      JSON.stringify({
        name: file.name,
      })
    );
  });

  formData.append(
    "pinataOptions",
    JSON.stringify({
      cidVersion: 0,
    })
  );

  const res = await fetch(
    "https://api.pinata.cloud/pinning/pinFileToIPFS",
    {
      method: "POST",
      headers: {
        pinata_api_key: `${apikey}`,
        pinata_secret_api_key: `${secretapikey}`,
      },
      body: formData,
    }
  );

  if (res.ok) {
    const resData = await res.json();
    console.log("Parent Hash:", resData.IpfsHash);
    const filesResponse = await fetch(
      `https://gateway.pinata.cloud/ipfs/${resData.IpfsHash}`
    );
    if (filesResponse.ok) {
      const filesText = await filesResponse.text();
      console.log("Response Body:", filesText);
      // Push each image with its corresponding metadata
      files.forEach((file, index) =&amp;gt; {
        setImagesWithMetadata((prev) =&amp;gt; [
          ...prev,
          { imageUrl: filesText, metadata: { name: file.name } },
        ]);
      });
    } else {
      console.error(
        "Failed to retrieve files within the parent hash:",
        filesResponse.statusText
      );
    }
  } else {
    console.error("Failed to pin the file to IPFS");
  }

  setLoaderThree(false);
} catch (error) {
  console.error("Error while processing response:", error);
  setLoaderThree(false);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;};`&lt;/p&gt;

</description>
      <category>pinata</category>
      <category>ipfs</category>
      <category>webdev</category>
      <category>javascript</category>
    </item>
  </channel>
</rss>
