A Practical Guide to Everyday Developer Encoding & Formatting
Most day-to-day development involves the same handful of encoding, formatting and inspection tasks: tidying JSON, encoding a value to Base64, hashing a string, decoding a token, or reading a cron schedule. This guide explains what each task actually does, when you need it, and points you to a free tool that runs entirely in your browser — so sensitive data never leaves your device.
Encoding, encryption and hashing are three different things
Almost every serious mistake in this area comes from treating these three as interchangeable. They look similar — text goes in, unreadable text comes out — but they answer completely different questions, and picking the wrong one produces something that feels secure without being secure.
| Operation | Reversible? | Needs a key? | What it is for |
|---|---|---|---|
| Encoding (Base64, URL, hex) | Yes, by anyone | No | Safe transport through a text-only channel |
| Encryption (AES) | Yes, with the key | Yes | Keeping content secret from people without the key |
| Hashing (SHA-256) | No, by design | No | Proving two things are identical without storing one |
The column that matters is the second one. If a value can be turned back into the original by anybody who has it, that value is not protected, whatever it looks like. A Base64 string in a config file is plain text with extra steps.
Formatting and validating JSON
JSON is easy to produce and hard to read once it is minified or malformed. Beautifying adds consistent indentation so you can scan structure quickly, while minifying strips whitespace to shrink payloads. Validating catches the classic culprits before they reach production.
The errors cluster into a small set, and recognising them by shape is faster than reading a parser message:
- A trailing comma after the last item — legal in JavaScript, illegal in JSON, and the single most common cause of a parse failure.
- Single-quoted strings or unquoted keys. Both are valid JavaScript object literals and neither is valid JSON, which is why pasting a console-logged object into a config file so often fails.
- A mismatched bracket, usually reported at the end of the file rather than where the nesting actually went wrong.
- NaN, Infinity or undefined, which JSON has no representation for. A serialiser will often emit them anyway and produce a document nothing can read back.
- An unescaped control character inside a string — most often a literal newline pasted in from somewhere else.
A practical rule: beautify while debugging, validate before committing any config or fixture, and minify only for transport. The saving from minification is real but small next to gzip, so it is rarely worth losing readability in a file humans edit.
Base64: what it is and what it is not
Base64 represents arbitrary bytes using 64 characters that survive any text channel intact. It exists because a great deal of infrastructure — email headers, JSON string fields, URLs, XML documents — was designed for text and will corrupt raw binary that passes through it.
The mechanism explains its cost. Three bytes of input become four characters of output, so anything Base64-encoded is roughly 33% larger than the original, plus padding. That overhead is the price of safe passage, and it is why embedding a large image as a data URL bloats a stylesheet far more than people expect.
Two variants trip people up. Standard Base64 uses + and /, which have reserved meanings in URLs, so tokens use Base64URL with - and _ instead. And padding with = is optional in some implementations and mandatory in others, which is why a value that decodes fine in one language errors in another.
Hashing, checksums and why salting matters
A hash is a one-way fingerprint: the same input always produces the same digest, a different input almost certainly produces a different one, and you cannot work backwards from digest to input. That combination makes hashes the right tool for proving two things match without needing to keep both.
The everyday use is integrity. A project publishes the SHA-256 of a download; you hash the file you received and compare. If the digests match, the bytes are identical — a corrupted transfer or a tampered mirror cannot survive that check.
Password storage is where the naive approach fails. Identical passwords produce identical digests, so a leaked table immediately reveals which accounts share one — and common passwords can be looked up in precomputed tables. A per-user random salt breaks both properties. Beyond that, general-purpose hashes like SHA-256 are designed to be fast, which is precisely wrong for passwords; a purpose-built function such as bcrypt or Argon2 is deliberately slow. MD5 and SHA-1 should not be used for anything security-related at all, as practical collisions exist for both.
Reading a JWT without trusting it
A JSON Web Token is three Base64URL segments separated by dots: a header naming the algorithm, a payload of claims, and a signature over the first two. The first two segments are merely encoded, which means anyone holding the token can read every claim in it.
eyJhbGciOiJIUzI1NiJ9 . eyJzdWIiOiIxMjM0Iiwicm9sZSI6ImFkbWluIn0 . dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk
└─── header ────────┘ └─── payload (readable by anyone) ──┘ └─── signature ─────────────────────┘Two consequences follow directly. Never put anything confidential in a JWT payload — it is visible to the holder and to anything that logs the token. And never trust a decoded token without verifying its signature: decoding proves only that someone produced well-formed Base64, not that your server issued it.
When debugging, the claims worth checking first are exp and iat (expiry and issue time, as Unix timestamps), iss and aud (who issued it and who it is for), and any role or scope claim. An expired token and a token for the wrong audience produce very similar-looking failures.
Regular expressions without the trial and error
Regex has an unusually steep cost curve: trivial patterns are easy, and the next tier is where most of the time goes. Testing against real sample text with live highlighting turns that into a fast feedback loop rather than a guessing game.
A few habits prevent most of the pain. Anchor patterns with ^ and $ when you mean the whole string, or a validator will happily match a fragment inside garbage. Prefer explicit character classes to the dot, which matches more than people expect. And remember that quantifiers are greedy by default — .* runs to the last possible match, not the first, which is why naive HTML tag patterns swallow entire documents.
Also worth knowing: validating an email address with a regex is a famous dead end. The specification permits far more than any short pattern accepts, and the only reliable proof that an address works is sending mail to it. Check for a plausible shape, then verify by email.
Number bases and where they surface
Decimal is a human convention, and a lot of computing is more naturally expressed in other bases. Hexadecimal dominates because one hex digit is exactly four bits, so a byte is always two hex digits — a clean, compact mapping that decimal cannot offer.
| Base | Digits | Where you meet it |
|---|---|---|
| Binary (2) | 0–1 | Bitmasks, flags, permissions, raw data |
| Octal (8) | 0–7 | Unix file permissions (chmod 644) |
| Decimal (10) | 0–9 | Everything human-facing |
| Hexadecimal (16) | 0–9, a–f | Colours, byte values, memory addresses, hashes |
Colour notation is the most common encounter. A CSS colour like #1E90FF is three hex bytes — red 30, green 144, blue 255 — each ranging 00 to FF, which is 0 to 255. Understanding that makes the other notations legible too: rgb() states the same three numbers in decimal, while hsl() re-parameterises them as hue, saturation and lightness, which is far easier to adjust deliberately. Shifting a colour slightly darker is one number in HSL and guesswork in hex.
Octal survives mainly in file permissions, where each digit is three bits — read, write, execute. So 644 is read and write for the owner, read for everyone else, and 755 adds execute, which is why directories and scripts need it. A leading zero also means octal in some languages, which is a genuine trap: writing 0644 as a plain integer does not give you six hundred and forty-four.
Unix timestamps and the traps in them
A Unix timestamp counts seconds since midnight UTC on 1 January 1970. It is compact, unambiguous, timezone-free and sorts naturally, which is why it appears throughout logs, tokens, APIs and databases.
The recurring bug is units. Unix time is conventionally seconds, but JavaScript, Java and several APIs use milliseconds. Mixing them does not error — it produces a date in 1970 or one about fifty thousand years out, both obviously wrong once seen and easy to miss inside a comparison. A rough check: a current timestamp in seconds is ten digits, in milliseconds thirteen.
One more worth knowing: Unix time deliberately ignores leap seconds, so it is not a true count of elapsed seconds. For ordinary application work that is exactly what you want. For anything measuring precise intervals across a leap second, it is a known limitation rather than a bug to file.
Reading a cron expression
Cron is five fields — minute, hour, day of month, month, day of week — and the syntax is compact enough that misreading it is easy and the consequence is a job running at the wrong time for months before anyone notices.
| Field | Range | Common values |
|---|---|---|
| Minute | 0–59 | 0, */15, 30 |
| Hour | 0–23 | 0, */6, 9 |
| Day of month | 1–31 | * or 1 |
| Month | 1–12 | * |
| Day of week | 0–6 (0 = Sunday) | * or 1-5 |
So 0 */6 * * * is every six hours on the hour, and 30 9 * * 1-5 is 09:30 on weekdays. The operators are few: * for every value, */n for every nth, a-b for a range, and a,b,c for a list.
The other recurring trap is the timezone. Cron uses the server's local zone, so a schedule written against a machine in one region behaves differently after a migration, and any job pinned to a local hour will drift by an hour twice a year under daylight saving. For anything where the exact hour matters, run the server in UTC and do the conversion deliberately.
robots.txt: four lines with outsized consequences
The files that control how crawlers treat a site are tiny, hand-written, and unusually unforgiving — which puts them in the same family as cron expressions and regexes.
User-agent: *
Disallow: /admin/
Allow: /admin/public/
Sitemap: https://example.com/sitemap.xmlRules apply to the most recently declared User-agent, so a directive placed under the wrong block silently governs a different crawler. Paths are prefixes rather than patterns, so Disallow: /admin blocks /administrator too. And the whole file only governs the host it is served from, so a subdomain needs its own.
The other thing worth understanding is what robots.txt does not do. It requests that compliant crawlers do not fetch a page; it does not remove one from the index. A URL that other sites link to can still appear in results, listed without a description, because the crawler was told not to fetch it and therefore could not read the noindex tag that would have removed it. Blocking and deindexing are different operations, and using the first when you meant the second is why pages linger in search results long after someone thought they had removed them.
Which tool for which symptom
Most of these tasks arrive as a symptom rather than a request. This maps the symptom to the operation you actually need.
| Symptom | What is likely happening | Reach for |
|---|---|---|
| A long string of letters and digits ending in = or == | Base64 | A Base64 decoder |
| Three dot-separated chunks starting eyJ | A JWT | A JWT decoder |
| A fixed-length hex string, the same every time | A hash digest | A hash generator, to compare |
| %20 and %2F throughout a URL | Percent-encoding | A URL parser |
| A wall of JSON on one line | Minified output | A JSON formatter |
| A scheduled job firing at the wrong time | Cron field or timezone error | A cron decoder |
Debugging an API payload you did not write
How to inspect an unfamiliar API payload
Format it first
Run the raw response through a JSON formatter before reading anything. Structure is invisible in minified output, and a validation error at this stage tells you the problem is the response itself rather than your parsing.
Identify the encoded fields
Scan for values that are not plain data: trailing = padding suggests Base64, a leading eyJ suggests a JWT, and %20 sequences suggest percent-encoding. Each needs decoding before it means anything.
Decode each one in place
Decode the fields individually and read what comes out. A Base64 field frequently contains more JSON, so expect to format a second time once it is decoded.
Check the timestamps
Convert any Unix timestamps to readable dates. Expiry claims and issued-at times explain a large share of authentication failures, and a token that expired minutes ago looks identical to one that was never valid.
Verify rather than assume
If integrity matters, hash the payload and compare against the digest the sender published. If authenticity matters, verify the signature — decoding a token proves nothing about who issued it.