🔥 layer5io / layer5 - Layer5, expect more from your infrastructure
GitHub热门项目 | Layer5, expect more from your infrastructure | Stars: 1,096 | 1 star today | 语言: JavaScript
找到 1190 篇相关文章
GitHub热门项目 | Layer5, expect more from your infrastructure | Stars: 1,096 | 1 star today | 语言: JavaScript
GitHub热门项目 | Source for remoteintech.company — a community-maintained directory of remote-friendly tech companies | Stars: 40,681 | 12 stars today | 语言: JavaScript
Libraries like Valtio and Pinia for Vue use a mutator pattern instead of the actions, dispatch, and...
In my last post I wrote about an error that cost me a full evening: my pom.xml had the MongoDB starter, but my code was still full of JPA annotations. The compiler kept saying cannot find symbol: class Entity . That post was about the error. This post is about the fix — every single line I had to change to move my Task Manager project from MySQL to MongoDB. If you are planning the same switch, this is the checklist I wish I had. 1. The dependency Before (MySQL + JPA): <dependency> <groupId> org.springframework.boot </groupId> <artifactId> spring-boot-starter-data-jpa </artifactId> </dependency> <dependency> <groupId> com.mysql </groupId> <artifactId> mysql-connector-j </artifactId> <scope> runtime </scope> </dependency> After (MongoDB): <dependency> <groupId> org.springframework.boot </groupId> <artifactId> spring-boot-starter-data-mongodb </artifactId> </dependency> One starter replaces two dependencies. And this is exactly where my problem started — I added the new one but never removed the old one, so half my code still compiled and half did not. Remove the JPA starter completely. If you leave it in, the jakarta.persistence annotations still resolve, and you will not notice you are mixing two worlds until something breaks at runtime. 2. application.properties Before: spring.datasource.url = jdbc:mysql://localhost:3306/taskmanager spring.datasource.username = root spring.datasource.password = yourpassword spring.jpa.hibernate.ddl-auto = update spring.jpa.show-sql = true After: spring.data.mongodb.uri = mongodb://localhost:27017/taskmanager Five lines became one. No ddl-auto because MongoDB has no schema to create. No dialect because there is no SQL being generated. The database and the collection are created automatically the first time you insert a document. 3. The model class This is where most of the work was. Here is my actual Task class after the migration: package com.taskmanager.task_manager ; import com.fasterxml.jackson.annotation.JsonIgnore ; import org.
Your modal is open, centered, perfect. Then someone flicks the overlay and the page behind it scrolls away underneath. Everyone's first fix is the same three lines: useEffect (() => { document . body . style . overflow = open ? " hidden " : "" ; }, [ open ]); It works on your laptop. Then the bug reports arrive: On iPhone the page still moves. iOS Safari rubber-band scrolls the document by touch even with overflow: hidden on <body> . Something else got wiped. "" isn't necessarily what was there before — you just erased whatever your design system or CSS-in-JS had set inline. Two overlays, one frozen page. A drawer and a lightbox both own body.style.overflow ; close them in the wrong order and the page never scrolls again. The layout jumps the instant the desktop scrollbar disappears. useScrollLock from @reactuses/core is those three lines with the hard parts handled: it restores the exact inline overflow it replaced, adds a touchmove guard on iOS that still lets your modal's own content scroll, exposes the lock as React state you can render off, and works on any element — not just <body> . This post covers what it actually does line by line, why overflow: hidden is not enough on iOS, how it compares to the position: fixed and body:has(dialog[open]) approaches, and the six gotchas that show up in real apps. Quick Start npm install @reactuses/core import { useScrollLock } from " @reactuses/core " ; import { useEffect } from " react " ; function Modal ({ open , onClose , children }: ModalProps ) { // a getter, not `document.body` — see the SSR gotcha below const [, setLocked ] = useScrollLock (() => document . body ); useEffect (() => { setLocked ( open ); return () => setLocked ( false ); // release even if we unmount while open }, [ open , setLocked ]); if ( ! open ) return null ; return ( < div className = "overlay" onClick = { onClose } > < div className = "sheet" onClick = { e => e . stopPropagation () } > { children } </ div > </ div > ); } The signature: const [
I kept running into a boring problem that was harder to debug than it should have been: text that looked normal, but behaved wrong the moment I pasted it into a CMS, a spreadsheet, or a code comment. Search would fail. Line breaks would get weird. A heading copied from ChatGPT would drag Markdown markers along with it. Sometimes the only visible clue was that the punctuation felt slightly "off." What finally made this manageable wasn't some big NLP trick. It was going back to the dumb, reliable layer: exact character matching. The tool I built for this is basically a pile of small, deterministic cleanups for the specific junk that copied text tends to accumulate — full-width punctuation mixed into ASCII, invisible Unicode code points, curly quotes, em dashes, leftover Markdown, and whitespace noise. The most useful part is the invisible-character scan, not the cleaning The piece I trust most in the whole component is the part that explicitly names which invisible characters it cares about, then counts them by code point. It's not doing a vague "this text seems suspicious" pass. It has a hard-coded inventory: const invisibleDefs = [ { key : " zwsp " , codes : [ 0x200b ] }, { key : " zwnj " , codes : [ 0x200c ] }, { key : " zwj " , codes : [ 0x200d ] }, { key : " bomZwnbsp " , codes : [ 0xfeff ] }, { key : " wordJoiner " , codes : [ 0x2060 ] }, { key : " softHyphen " , codes : [ 0x00ad ] }, { key : " bidiMarks " , codes : [ 0x200e , 0x200f , 0x202a , 0x202b , 0x202c , 0x202d , 0x202e ] }, ]; const codesToRegex = ( codes ) => new RegExp ( `[ ${ codes . map (( c ) => " \\ u " + c . toString ( 16 ). padStart ( 4 , " 0 " )). join ( "" )} ]` , " g " ); const analyzeInvisible = ( str ) => { const breakdown = invisibleDefs . map (( def ) => ({ key : def . key , count : ( str . match ( codesToRegex ( def . codes )) || []). length , })); const total = breakdown . reduce (( sum , row ) => sum + row . count , 0 ); return { breakdown , total }; }; I like this because it's brutall
React Router v8 was released on June 17, 2026, with minimal breaking changes and new baselines. Key updates include an ESM-only build and default middleware settings. React Router v6 and Remix v2 have reached End of Life. Developers should follow specific migration guidelines to update their applications, while some are considering alternatives like TanStack Router. By Daniel Curtis
I didn't want to write another "what's new in Next.js 16.3" post. Enough of those exist. I wanted to...
Hace unos meses empecé a construir Utiligo , una colección de calculadoras en español: horas extras, IVA, aguinaldo, préstamos, IMC. La premisa técnica era simple y me la tomé en serio: cero dependencias de JavaScript en el navegador . Sin React, sin frameworks de UI, sin librerías de gráficos. Ni una. Esto es lo que aprendí construyéndolo. Por qué cero dependencias La mayoría de estas herramientas hacen aritmética. Sumar horas, aplicar un porcentaje, dividir un salario entre 30. Enviar 40 KB de framework al navegador para calcular salario / 30 / 8 es desproporcionado, y en América Latina —donde está mi audiencia— buena parte del tráfico llega por móvil con conexiones irregulares. El stack quedó así: Astro en modo output: 'static' , que genera HTML puro <script is:inline> con JavaScript de toda la vida para la interactividad Cloudflare Pages para servirlo El resultado: páginas que funcionan antes de que termine de cargar cualquier cosa. Lo que sí duele de esta decisión Sería deshonesto contarlo como si no tuviera costes. Los gráficos hay que dibujarlos a mano. El gráfico de pastel del presupuesto mensual es SVG generado con trigonometría: var end = start + pct * 2 * Math . PI ; var x1 = cx + r * Math . cos ( start ), y1 = cy + r * Math . sin ( start ); var x2 = cx + r * Math . cos ( end ), y2 = cy + r * Math . sin ( end ); var large = pct > 0.5 ? 1 : 0 ; svg += ' <path d="M ' + cx + ' , ' + cy + ' L ' + x1 + ' , ' + y1 + ' A ' + r + ' , ' + r + ' 0 ' + large + ' ,1 ' + x2 + ' , ' + y2 + ' Z"/> ' ; Con una librería serían tres líneas. Aquí son treinta y hay que entender el arco elíptico de SVG. ¿Vale la pena? Para un gráfico, sí. Para un dashboard entero, probablemente no. No hay reactividad. Cada oninput actualiza el DOM a mano. Funciona bien con diez campos; con cien sería insostenible. El generador de QR tuve que escribirlo. Codificación Reed-Solomon incluida. Fue el fin de semana más educativo del proyecto y el que menos recomendaría repetir. El bug que me enseñó
Java 11 New Features and Performance Improvements Released in September 2018, Java 11 is a Long-Term Support (LTS) release, making it one of the most important milestones since Java 8. For teams planning migrations, Java 11 offers a compelling mix of new language features, API enhancements, and under-the-hood performance improvements. In this post, we'll explore the most impactful changes and how they affect real-world applications. Why Java 11 Matters Java 11 is the first LTS release after Java 8, meaning it receives extended support and security updates. Unlike the non-LTS releases (9 and 10), it's designed for production stability, which is why many enterprises skipped straight from 8 to 11. Language and API Enhancements 1. Local-Variable Syntax for Lambda Parameters Java 10 introduced var for local variables. Java 11 extends this to lambda parameters, allowing you to apply annotations consistently. // Now valid in Java 11 list . forEach (( var item ) -> System . out . println ( item )); // Useful for annotations list . forEach (( @Nonnull var item ) -> process ( item )); 2. New String Methods The String class gained several convenient methods that reduce boilerplate. // Check if a string is blank (empty or whitespace only) " " . isBlank (); // true // Strip leading/trailing whitespace (Unicode-aware) " hello " . strip (); // "hello" " hello " . stripLeading (); // "hello " " hello " . stripTrailing (); // " hello" // Repeat a string "ab" . repeat ( 3 ); // "ababab" // Stream lines "line1\nline2" . lines (). forEach ( System . out :: println ); Note: strip() differs from trim() because it uses Character.isWhitespace() , correctly handling Unicode whitespace characters. 3. Files Read/Write Convenience Methods Reading and writing strings to files is now a one-liner. import java.nio.file.Files ; import java.nio.file.Path ; Path path = Path . of ( "example.txt" ); // Write Files . writeString ( path , "Hello, Java 11!" ); // Read String content = Files . readString (
I built Suzi Chat to bring back the nostalgic feel of late-90s/early-2000s browser chat rooms. Key Features: Create and customize your own public or private chat rooms instantly from the browser. Built-in multiplayer casual board games (Chess, Checkers, Gomoku). No complicated setup—straightforward web-based access. Built using a NestJS backend and running on a dedicated Linux VPS. Live Platform: https://suzichat.com Looking for feedback from other developers on the UI layout, room creation flow, and multiplayer lobby stability.
The Quest Begins (The "Why") Hey friend, picture this: you’re happily writing JavaScript, tossing objects around like confetti at a parade, and then you decide to give Rust a spin. You open the compiler, write a simple function that returns a slice of a vector, and boom— error[E0505]: cannot move out of … because it is borrowed . Your brain does a double‑take. “Wait, I didn’t even touch anything!” you mutter, staring at the screen like you just missed a plot twist in Inception . That moment was my dragon. I’d spent years trusting the garbage collector to clean up after me, and Rust’s ownership system felt like a strict sensei who wouldn’t let you leave the dojo until you bowed correctly. I was frustrated, curious, and honestly a little scared. But once I grasped the core ideas, the whole language started to click like a well‑oiled machine. So why does ownership matter? Because it gives you memory safety without a runtime garbage collector. No surprise pauses, no hidden allocations—just compile‑time guarantees that your program won’t dereference null or use‑after‑free. For a JS dev used to “it just works”, that’s a superpower worth earning. The Revelation (The Insight) The big surprise? Ownership isn’t just about who “owns” a value; it’s about how that value can be accessed, moved, or borrowed at any point in the program. Three rules govern everything: Each value has a single owner. When the owner goes out of scope, the value is dropped. You can either have one mutable reference or any number of immutable references to a value, but never both at the same time. Sounds simple, right? The gotcha is that Rust treats references as a separate kind of value with its own lifetime. If you try to store a reference beyond the lifetime of what it points to, the compiler says “nope”. This is where many JS devs stumble because in JavaScript a reference (or variable) just points to an object that lives as long as something else holds it—garbage collection decides when it’s gone. Le
I used to think a bulk date converter was basically a dropdown wrapped around a date library. Paste a bunch of rows, pick YYYY-MM-DD , done. Then you look at real exports from spreadsheets, CRMs, logs, and old internal tools and realize the problem isn't "formatting" at all. It's triage. Some rows are obvious. Some are malformed. Some have month names. Some came from a CSV with five unrelated columns. And then there's the classic cursed input: 01/02/2024 , which is either January 2 or February 1 depending on who produced the file. The Vue component behind this tool is interesting because it doesn't pretend that ambiguity goes away if you call the right parser. It models that ambiguity explicitly. It starts by assuming uploaded files are messy, not clean One thing I liked in the source is that it doesn't treat file input as a single happy path. If you upload a TXT file, it works line by line. If the upload looks CSV-ish, it switches into a tiny parser and then tries to figure out which column is actually the date column. The CSV split logic is manual instead of using a naive line.split(",") , which matters because quoted commas are a real thing in exports: const splitCsvLine = ( line ) => { const result = []; let cur = "" ; let inQuotes = false ; for ( let i = 0 ; i < line . length ; i ++ ) { const ch = line [ i ]; if ( ch === ' " ' ) { if ( inQuotes && line [ i + 1 ] === ' " ' ) { cur += ' " ' ; i ++ ; } else { inQuotes = ! inQuotes ; } } else if ( ch === " , " && ! inQuotes ) { result . push ( cur ); cur = "" ; } else { cur += ch ; } } result . push ( cur ); return result . map (( s ) => s . trim ()); }; After that, it doesn't ask the user to map columns immediately. It scores each column by counting how many cells look like dates, then auto-selects the best candidate: for ( let c = 0 ; c < maxCols ; c ++ ) { const count = dataRows . filter (( r ) => isLikelyDateCell ( r [ c ])). length ; columns . push ({ index : c , header : headerRow ? headerRow [ c ] : "" }); i
MergePDF is a 100% client-side PDF tool. No backend, no uploads, no sign-up. Here's the architecture, the tricky parts, and why privacy is a feature, not a setting. Every tax season, the same thing happens. Someone in my family asks me to merge a few PDFs. They Google "merge PDF." They click the first result — a slick, friendly-looking site. They upload their tax returns to a server they've never heard of. That bothered me. So I built MergePDF. It merges, splits, rotates, and rearranges PDF pages — and your files never leave your browser. No backend. No sign-up. No ads. No tracking. iLovePDF uploads your tax returns. We don't. This post is about how it works, the parts that were harder than I expected, and why "client-side only" is a design philosophy, not just a technical choice. The pitch in 30 seconds Drop one or more PDFs onto the page. You get a grid of page thumbnails — real, rendered previews of every page. Drag to reorder. Click to select. Rotate, delete, extract a range. Merge everything into one file, or split into single-page PDFs zipped up. Download. Done. Your browser does all of it. There is no server processing documents. There isn't even a server to process documents. The stack It's a Next.js app, but honestly Next.js is just the host here. The interesting parts are all client-side libraries doing real work: No database. No API routes. No auth. No analytics. The only thing in localStorage is your theme preference. Drag-to-reorder that doesn't fight tap-to-select This one took three attempts. The requirement: Tap a thumbnail → select it (emerald ring) Shift-tap → select a range Long-press + drag → reorder Swipe on mobile → scroll the grid (don't drag) The conflict: if the whole card is the drag handle, taps get swallowed. If only a tiny grip icon is the handle, nobody finds it (especially on mobile, where there's no hover). So split produces a ZIP. fflate's zip packages every single-page PDF into one download. Rotations are honored here too — each spl
Optimizing test execution speed is essential for keeping build pipelines lean. Depending on how your framework is structured, you can achieve full parallel execution either natively using TestNG ** or dynamically using a **Custom Excel Allocator . Here is a step-by-step guide on configuring both approaches, along with a comparison to help you choose the right strategy. Strategy 1: Native TestNG Parallelization (Recommended for Code-Native Suites) TestNG natively supports parallel execution at the methods, classes, tests, or instances level using its XML configuration or Maven parameters. 1. Update testng_regression.xml Modify the tag to set the execution mode and thread pool size: <suite name= "Regression" parallel= "methods" thread-count= "10" > 2. Configure pom.xml for Dynamic Overrides Allow developers and CI pipelines to override execution settings without altering XML files by adding these lines inside the block of the maven-surefire-plugin: <parallel> ${parallel} </parallel> <threadCount> ${threadCount} </threadCount> 3. Execution Commands Default Run: mvn clean test -P runTestNGTests Override Thread Count Dynamically: mvn clean test -P runTestNGTests -DthreadCount = 15 Full Parallel Execution (Match CPU Core Count): mvn clean test -P runTestNGTests -Dparallel = methods -DthreadCount = 24 Strategy 2: Custom Allocator & Run Manager (For Excel-Driven Suites) If your framework relies on an Excel-driven Run Manager to parse keyword flows and data sheets dynamically, parallelism is managed via a custom ExecutorService fixed thread pool. Execution Command mvn clean test -P runAllocator How it works: The allocator reads active test rows (Execute=Yes), dynamically assigns thread pools based on target thread properties, and dispatches concurrent runs. Comparison: Allocator (Run Manager) vs. Native TestNG Feature Allocator (Run Manager) TestNG Native Entry Point allocator.Allocator.main() via Maven Exec Plugin maven-surefire-plugin executing testng.xml Test Selection Re
Accelerating test execution in a Hybrid Automation Framework (combining Data-Driven and Keyword-Driven architectures) requires an efficient parallel execution strategy. By dynamically mapping keyword actions and test data rows to concurrent threads, you can drastically reduce execution time without compromising framework design. Here is a guide on setting up parallel execution using a central Allocator and Run Manager. 1. Overview of the Setup The framework leverages a Run Manager sheet to map keywords to execution steps and pull test data dynamically. Parallelization works by assigning NumberOfThreads to match the exact number of active test cases marked for execution. Key parameters are configured globally inside the Global Settings.properties file. 2. Configuration Steps a. Set the Number of Threads Total the number of test scenarios marked with Execute=Yes across your target keyword and data sheets. Set NumberOfThreads equal to this count. Example: If your Run Manager sheet contains 42 test iterations set to Execute=Yes, update your configuration: NumberOfThreads = 42 b. Disable Profile-Based Execution (If Not Needed) For clean parallel browser execution, set EnableProfile=False. If user profiles are required to maintain session state across keywords, set UseMultiProfile=True and configure separate profile directories per thread to avoid file-lock conflicts. c. Prepare the Run Manager Flag every keyword test case intended for the current run with Execute=Yes. The allocator will read these rows, pair them with their corresponding data sets, and dispatch them to the thread pool. 3. Executing the Test Suite Trigger the allocator flow via Maven: mvn clean test -P runAllocator The allocator reads the mapped keyword sheets and test data, initializes the specified NumberOfThreads, and executes the tests in parallel. 4. Handling Multiple Keyword & Data Sheets Option 1: Use a Master Control Sheet (Recommended) Consolidate execution rows into a single master sheet (e.g.,
MOKSHA — v0.1.1 Devlog Date: 2026-08-18 Milestone: v0.1.1 — https://github.com/weirdcodesofficial/MOKSHA/milestone/11 Highlights Major mobile-focused performance work: reduced per-frame CPU/GPU cost in render path. Replaced hot trig math with a lookup table (LUT) to remove repeated Math.sin/cos calls. Cached per-frame gradients and reduced expensive shadowBlur calls to lower GPU blur passes. Added quality-tier controls and explicit render-state resets for more predictable mobile behaviour. v0.1.1 release PR merged. Merged pull requests (summary) PR #147 — perf(render): replace remaining Math.sin/cos with lutSin/lutCos Replaced ~25 per-frame trig calls in drawScene() with reads from the existing 2048-entry radian LUT (affects ring ticks, pulses, orbit waves, arc heads, timer pill pulses, etc.) — reduces CPU trig cost significantly. https://github.com/weirdcodesofficial/MOKSHA/pull/147 PR #145 — render: Done gradient caching. Implemented caching/baking for commonly created gradients and offscreen sprites (pickup glow, naama, chakravaata, rein gradient buckets) to avoid per-frame gradient allocations and GPU work. https://github.com/weirdcodesofficial/MOKSHA/pull/145 PR #144 — render: quality tier control, explicity reset, 40 shadowBlur calls wr… Added device/quality-tier checks to disable or lower shadowBlur on low-end devices; isolated shadowBlur via save()/restore() and explicit ctx.shadowBlur = 0 resets to avoid leaks. GPU blur pass count reduced. https://github.com/weirdcodesofficial/MOKSHA/pull/144 PR #146 — V0.1.1 (release PR) — bump / release merge. https://github.com/weirdcodesofficial/MOKSHA/pull/146
TypeScript 6.0 Strict Function Types: Why Contravariance Breaks Your Existing Callbacks This article was written with the assistance of AI, under human supervision and review. Most TypeScript migration failures stem from a single misunderstood compiler flag: strictFunctionTypes . The pattern that breaks production is deceptively simple—a callback that accepts a base type where the consumer expects a derived type. TypeScript 6.0 enables strict mode by default, which means codebases that never configured contravariance checking will fail to compile overnight. The failure mode here is subtle but expensive. A callback registered to an array method expects Animal , but the implementation passes Dog . Pre-6.0 TypeScript allowed this through bivariant parameter checking. Post-6.0, the compiler rejects it as unsafe. Teams scramble to fix hundreds of type errors without understanding the underlying variance rules, often choosing any or incorrect casts that introduce runtime bugs. The distinction between function properties and method signatures becomes critical—one enforces contravariance, the other permits bivariance for historical reasons. %% alt: Bivariant checking allows derived types where base types are expected The correct approach requires understanding contravariance: function parameters must accept types that are the same or less specific than what the function signature declares. When strictFunctionTypes activates, TypeScript enforces this rule for function properties but not method signatures. The solution is not to weaken types with any , but to restructure callbacks using proper variance-aware patterns or switch to method syntax where bivariance is intentional. %% alt: Contravariant checking enforces parameter safety at compile time This matters because the TypeScript 6.0 ecosystem assumes strict mode. Third-party libraries ship types built for contravariance. Disabling strictFunctionTypes to silence errors creates a type system that diverges from reality, wher
I recently found myself in one of those classic developer rabbit holes. A friend asked me if I knew their Chinese zodiac sign, and instead of just Googling it like a normal person, I thought: "I could build a tool for this." Because apparently I enjoy reinventing wheels. The twist? I wanted it to work entirely in the browser. No API calls, no server, no database. Just a date input and some JavaScript logic. The challenge was figuring out how to accurately compute Chinese zodiac signs, the Chinese lunar calendar year, and the traditional Ganzhi (干支) system without pulling in a massive calendar library. The Problem with Existing Solutions My first instinct was to search for an API. There are plenty of Chinese calendar APIs out there, but they all had issues: Most require API keys and rate limiting Many are Chinese-language only, which is fine for me but not great for a broader audience They're overkill for what should be a simple calculation Some have questionable accuracy for historical dates I also looked at JavaScript libraries like lunar-javascript and chinese-calendar . They're comprehensive, but they're also huge. For a simple "what's my zodiac sign" tool, pulling in a 100KB+ library felt like using a flamethrower to light a candle. The Math Behind the Madness Here's what I discovered: the Chinese zodiac and Ganzhi calculations are surprisingly straightforward if you understand the underlying math. The Zodiac: Simple Modulo Arithmetic The 12 Chinese zodiac animals follow a cycle that aligns with the 12-year Jupiter cycle. The calculation is embarrassingly simple: const ZODIAC = [ ' 鼠 ' , ' 牛 ' , ' 虎 ' , ' 兔 ' , ' 龙 ' , ' 蛇 ' , ' 马 ' , ' 羊 ' , ' 猴 ' , ' 鸡 ' , ' 狗 ' , ' 猪 ' ]; const zodiac = ZODIAC [( year - 4 ) % 12 ]; That's it. The year 4 AD was the first year of the Rat, so everything since then follows a simple modulo pattern. The Ganzhi System: Two Interlocking Cycles The Ganzhi (干支) system combines the 10 Heavenly Stems (天干) with the 12 Earthly Branches (地支
Sometimes you have GPS coordinates like: 40.7128, -74.0060 But coordinates alone are not very useful to most users. They usually want to know something much simpler: What place is this? The process of converting latitude and longitude into a human-readable address is called reverse geocoding . In this article, we'll build a simple reverse geocoding example with JavaScript. What Is Reverse Geocoding? Normal geocoding converts an address into coordinates: New York, NY ↓ 40.7128, -74.0060 Reverse geocoding does the opposite: 40.7128, -74.0060 ↓ New York, NY, United States This is useful for location tools, GPS applications, travel websites, delivery systems, photo location tools, and map interfaces. Reverse Geocoding with JavaScript For a simple example, we can use the OpenStreetMap Nominatim reverse geocoding endpoint. async function reverseGeocode ( lat , lon ) { const url = `https://nominatim.openstreetmap.org/reverse` + `?lat= ${ lat } &lon= ${ lon } &format=jsonv2` ; const response = await fetch ( url ); if ( ! response . ok ) { throw new Error ( " Reverse geocoding failed " ); } const data = await response . json (); return data ; } reverseGeocode ( 40.7128 , - 74.0060 ) . then ( data => { console . log ( data . display_name ); }) . catch ( error => { console . error ( error ); }); The returned data usually contains a readable location name together with structured address information. Display the Address on a Page We can turn the example into a small browser tool. <input id= "lat" placeholder= "Latitude" > <input id= "lon" placeholder= "Longitude" > <button onclick= "findAddress()" > Find Address </button> <p id= "result" ></p> <script> async function findAddress () { const lat = document . getElementById ( " lat " ). value ; const lon = document . getElementById ( " lon " ). value ; const result = document . getElementById ( " result " ); try { const url = `https://nominatim.openstreetmap.org/reverse` + `?lat= ${ lat } &lon= ${ lon } &format=jsonv2` ; const res