Examples & Recipes
Real-world use cases with copy-pasteable code examples for ResolveDB.
Try It Live
Experiment with real DNS queries before diving into the examples:
API Discovery & Introspection
Explore the ResolveDB API programmatically using JSON Schema endpoints. Perfect for building tools, generating documentation, or enabling LLM-powered applications.
Get Resource Schema
Discover the structure of any resource's response before querying it.
HTTP Request:
curl 'https://api.resolvedb.io/schema?q=weather.public.v1.resolvedb.net'Response:
{
"status": "ok",
"namespace": "public",
"resource": "weather",
"schema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"properties": {
"tc": {
"type": "number",
"description": "Temperature in Celsius. Use for metric regions.",
"example": 22.5
},
"tf": {
"type": "number",
"description": "Temperature in Fahrenheit. Use for US/Imperial regions.",
"example": 72.5
},
"cnd": {
"type": "string",
"description": "Current weather condition. Use for display or weather icons.",
"enum": ["clear", "cloudy", "rain", "snow", "fog"]
}
},
"required": ["tc", "tf", "cnd"]
},
"dns_format": {
"query_template": "get.<city>.weather.public.v1.resolvedb.net",
"example_response": "v=rdb1;s=ok;t=data;tc=22.5;tf=72.5;cnd=clear"
},
"http_format": {
"curl_example": "curl 'https://api.resolvedb.io/resolve?name=get.seattle.weather.public.v1.resolvedb.net&type=TXT'"
},
"error_responses": [
{"status": "notfound", "code": "E004", "description": "City not found"}
]
}JavaScript - Build Dynamic Queries:
async function exploreAPI(resource, namespace, version) {
// Get schema
const schemaUrl = `https://api.resolvedb.io/schema?q=${resource}.${namespace}.${version}.resolvedb.net`;
const schemaResp = await fetch(schemaUrl);
const { schema, dns_format, error_responses } = await schemaResp.json();
console.log(`Query template: ${dns_format.query_template}`);
console.log(`Required fields: ${schema.required.join(', ')}`);
console.log(`Possible errors: ${error_responses.map(e => e.code).join(', ')}`);
// Use schema to validate response
const dns = require('dns').promises;
const query = dns_format.query_template.replace('<city>', 'seattle');
const records = await dns.resolveTxt(query);
// ... validate response against schema
}
exploreAPI('weather', 'public', 'v1');Python - Validate Responses:
import requests
import json
import jsonschema
def validate_response(resource, namespace, version, response_data):
"""Fetch schema and validate response"""
# Get schema
schema_url = f'https://api.resolvedb.io/schema?q={resource}.{namespace}.{version}.resolvedb.net'
schema_resp = requests.get(schema_url).json()
# Extract JSON Schema
json_schema = schema_resp['schema']
# Validate response
try:
jsonschema.validate(instance=response_data, schema=json_schema)
return True, None
except jsonschema.ValidationError as e:
return False, str(e)
# Usage
response = {"tc": 22.5, "tf": 72.5, "cnd": "clear"}
valid, error = validate_response('weather', 'public', 'v1', response)
if valid:
print("Response is valid!")
else:
print(f"Validation error: {error}")Configuration Storage
Store application configuration accessible via DNS. Perfect for feature flags, environment settings, and dynamic configuration.
Feature Flags
Store feature flags that can be queried from any client without an SDK.
DNS Query:
dig TXT get.dark-mode.flags.hooli.v1.resolvedb.net +shortExpected Response:
v=rdb1;s=ok;t=data;f=json;ttl=300;d={"dark_mode":true,"beta_users":false,"max_uploads":10}JavaScript:
const dns = require('dns').promises;
async function getFeatureFlags() {
const records = await dns.resolveTxt('get.dark-mode.flags.hooli.v1.resolvedb.net');
const response = records[0].join('');
const data = response.match(/d=(.+)$/)?.[1];
return JSON.parse(data);
}
// Usage
const flags = await getFeatureFlags();
if (flags.dark_mode) {
enableDarkMode();
}Python:
import dns.resolver
import json
import re
def get_feature_flags():
answers = dns.resolver.resolve('get.dark-mode.flags.hooli.v1.resolvedb.net', 'TXT')
response = str(answers[0]).strip('"')
match = re.search(r'd=(.+)$', response)
if match:
return json.loads(match.group(1))
return {}
# Usage
flags = get_feature_flags()
if flags.get('dark_mode'):
enable_dark_mode()Environment Configuration
Different configurations per environment using namespaced queries.
# Production config
dig TXT get.settings.config.hooli.v1.resolvedb.net +short
# Staging config
dig TXT get.settings.config.hooli-staging.v1.resolvedb.net +short
# Development config
dig TXT get.settings.config.hooli-dev.v1.resolvedb.net +shortPublic Data APIs
Access public data sources via DNS queries. Data is cached at the DNS layer for ultra-fast global access.
Weather Data
Query current weather using multiple location input formats.
Privacy by Design: Location must be explicitly provided in the query. The server never infers location from the client's IP address.
Location Input Formats:
| Format | Example | Description |
|---|---|---|
| City name | get.london.weather... | City name (lowercase, hyphens for spaces) |
| Coordinates | get.51d5074_-0d1278.weather... | Lat/lon with d as decimal, _ separator |
| IP address | get.ip-8-8-8-8.weather... | Weather for IP's geolocation |
| what3words | get.w3w-filled-count-soap.weather... | 3m x 3m precision (NEW) |
DNS Query Examples:
# By city name
dig TXT get.london.weather.public.v1.resolvedb.net +short
# By coordinates (d = decimal point, _ separates lat/lon)
dig TXT get.51d5074_-0d1278.weather.public.v1.resolvedb.net +short
# By IP address (get weather for IP's geolocation)
dig TXT get.ip-8-8-8-8.weather.public.v1.resolvedb.net +short
# By what3words address (hyphens replace dots)
dig TXT get.w3w-filled-count-soap.weather.public.v1.resolvedb.net +short
# 3-day forecast
dig TXT get.london.forecast.public.v1.resolvedb.net +shortExpected Response:
v=rdb1;s=ok;t=data;ttl=300;ts=1767186000;loc=London, England, United Kingdom;tc=8.5;tf=47.3;cnd=cloudy;wnd=12.0;hum=72;d1=6/10/rain;d2=5/9/cloudy;d3=7/11/partly_cloudyResponse Fields:
| Field | Description | Example |
|---|---|---|
loc | Location name | "London, England, United Kingdom" |
tc | Temperature (Celsius) | 8.5 |
tf | Temperature (Fahrenheit) | 47.3 |
cnd | Current conditions | cloudy, clear, rain, snow, fog |
wnd | Wind speed (km/h) | 12.0 |
hum | Humidity (%) | 72 |
d1-d3 | 3-day forecast (min/max/conditions) | 6/10/rain |
DoH (HTTPS) Request:
# Using ResolveDB's JSON API
curl -s "https://api.resolvedb.io/resolve?name=get.london.weather.public.v1.resolvedb.net&type=TXT" \
| jq -r '.Answer[0].data'
# what3words via DoH
curl -s "https://api.resolvedb.io/resolve?name=get.w3w-filled-count-soap.weather.public.v1.resolvedb.net&type=TXT" \
| jq -r '.Answer[0].data'JavaScript:
async function getWeather(location, type = 'city') {
const dns = require('dns').promises;
let query;
switch (type) {
case 'city':
query = `get.${location.toLowerCase()}.weather.public.v1.resolvedb.net`;
break;
case 'w3w':
// Replace dots with hyphens for what3words
query = `get.w3w-${location.replace(/\./g, '-')}.weather.public.v1.resolvedb.net`;
break;
case 'ip':
query = `get.ip-${location.replace(/\./g, '-')}.weather.public.v1.resolvedb.net`;
break;
case 'coords':
const [lat, lon] = location.split(',');
query = `get.${lat.replace('.', 'd')}_${lon.replace('.', 'd')}.weather.public.v1.resolvedb.net`;
break;
}
const records = await dns.resolveTxt(query);
const response = records[0].join('');
// Parse UQRP fields
const tc = response.match(/tc=([^;]+)/)?.[1];
const tf = response.match(/tf=([^;]+)/)?.[1];
const cnd = response.match(/cnd=([^;]+)/)?.[1];
const loc = response.match(/loc=([^;]+)/)?.[1];
return { location: loc, tempC: parseFloat(tc), tempF: parseFloat(tf), conditions: cnd };
}
// By city
const weather1 = await getWeather('london', 'city');
console.log(`${weather1.location}: ${weather1.tempF}°F, ${weather1.conditions}`);
// By what3words (3m x 3m precision)
const weather2 = await getWeather('filled.count.soap', 'w3w');
console.log(`${weather2.location}: ${weather2.tempC}°C`);
// By IP address
const weather3 = await getWeather('8.8.8.8', 'ip');Python:
import dns.resolver
import re
def get_weather(location, location_type='city'):
if location_type == 'city':
query = f'get.{location.lower()}.weather.public.v1.resolvedb.net'
elif location_type == 'w3w':
# Replace dots with hyphens for what3words
w3w_encoded = location.replace('.', '-')
query = f'get.w3w-{w3w_encoded}.weather.public.v1.resolvedb.net'
elif location_type == 'ip':
ip_encoded = location.replace('.', '-')
query = f'get.ip-{ip_encoded}.weather.public.v1.resolvedb.net'
answers = dns.resolver.resolve(query, 'TXT')
response = str(answers[0]).strip('"')
# Parse UQRP fields
fields = {}
for part in response.split(';'):
if '=' in part:
key, value = part.split('=', 1)
fields[key] = value
return {
'location': fields.get('loc'),
'temp_c': float(fields.get('tc', 0)),
'temp_f': float(fields.get('tf', 0)),
'conditions': fields.get('cnd')
}
# By city
weather = get_weather('london', 'city')
print(f"{weather['location']}: {weather['temp_c']}°C, {weather['conditions']}")
# By what3words
weather = get_weather('filled.count.soap', 'w3w')
print(f"{weather['location']}: {weather['temp_c']}°C")GeoIP Lookup
Get geographic information for any IP address.
DNS Query:
# Example IP lookups (dots replaced with hyphens)
dig TXT geoip.ip-8-8-8-8.public.v1.resolvedb.net +short
dig TXT geoip.ip-1-1-1-1.public.v1.resolvedb.net +shortDoH (HTTPS) Request:
curl -s "https://api.resolvedb.io/resolve?name=geoip.ip-8-8-8-8.public.v1.resolvedb.net&type=TXT" | jqExpected Response:
v=rdb1;s=ok;t=data;ttl=86400;ip=8.8.8.8;cc=US;co=United States;rg=California;ct=Mountain View;lat=37.4056;lon=-122.0775;tz=America/Los_Angeles;isp=Google LLCResponse Fields:
| Field | Description | Example |
|---|---|---|
ip | Queried IP address | 8.8.8.8 |
cc | Country code (ISO 3166-1) | US |
co | Country name | United States |
rg | Region/State | California |
ct | City | Mountain View |
lat | Latitude | 37.4056 |
lon | Longitude | -122.0775 |
tz | Timezone | America/Los_Angeles |
isp | ISP name | Google LLC |
Python:
import dns.resolver
def get_geoip(ip):
# Replace dots with hyphens in IP
ip_formatted = ip.replace('.', '-')
query = f'geoip.ip-{ip_formatted}.public.v1.resolvedb.net'
answers = dns.resolver.resolve(query, 'TXT')
response = str(answers[0]).strip('"')
# Parse UQRP fields
fields = {}
for part in response.split(';'):
if '=' in part:
key, value = part.split('=', 1)
fields[key] = value
return fields
info = get_geoip('8.8.8.8')
print(f"{info['ct']}, {info['rg']}, {info['co']}")
# Output: Mountain View, California, United StatesUser Data Storage
Store and retrieve authenticated user data. Requires JWT authentication via the auth- prefix.
User Preferences
Store per-user settings that sync across devices.
Store Preferences (via API):
curl -X POST https://api.resolvedb.io/api/v1/records \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"record": {
"key": "preferences.users.hooli.v1",
"data": "eyJ0aGVtZSI6ImRhcmsiLCJsYW5nIjoiZW4iLCJub3RpZnkiOnRydWV9",
"visibility": "private"
}
}'Retrieve with Authentication:
# JWT token contains user identity
dig TXT get.auth-<jwt_token>.preferences.users.hooli.v1.resolvedb.net +shortJavaScript:
const dns = require('dns').promises;
async function getUserPreferences(jwtToken) {
const query = `get.auth-${jwtToken}.preferences.users.hooli.v1.resolvedb.net`;
const records = await dns.resolveTxt(query);
const response = records[0].join('');
// Check for auth errors
if (response.includes('s=auth')) {
throw new Error('Authentication required');
}
const data = response.match(/d=(.+)$/)?.[1];
return JSON.parse(data);
}
// Usage
const prefs = await getUserPreferences(myJwtToken);
console.log(prefs);
// Output: { theme: "dark", lang: "en", notify: true }Python:
import dns.resolver
import json
import re
def get_user_preferences(jwt_token):
query = f'get.auth-{jwt_token}.preferences.users.hooli.v1.resolvedb.net'
answers = dns.resolver.resolve(query, 'TXT')
response = str(answers[0]).strip('"')
# Check for auth errors
if 's=auth' in response:
raise Exception('Authentication required')
match = re.search(r'd=(.+)$', response)
if match:
return json.loads(match.group(1))
return None
prefs = get_user_preferences(my_jwt_token)
print(prefs)
# Output: {'theme': 'dark', 'lang': 'en', 'notify': True}Large File Handling
DNS TXT records are limited to ~255 bytes per string and ~512 bytes per UDP response. ResolveDB handles larger data through chunking and blob URL fallback.
Chunked Data Retrieval
For data between 512 bytes and 4KB, ResolveDB returns metadata pointing to chunks.
DNS Query:
dig TXT get.largeconfig.hooli.v1.resolvedb.net +shortChunked Response:
v=rdb1;s=partial;t=multi;chunks=3;total=1536;hash=abc123;d=chunk-0.largeconfig.hooli.v1JavaScript - Chunk Reassembly:
const dns = require('dns').promises;
async function getLargeData(key, namespace, version) {
const baseQuery = `get.${key}.${namespace}.${version}.resolvedb.net`;
const records = await dns.resolveTxt(baseQuery);
const response = records[0].join('');
// Check if chunked
if (response.includes('t=multi')) {
const chunks = parseInt(response.match(/chunks=(\d+)/)?.[1] || '0');
// Fetch all chunks in parallel
const chunkPromises = [];
for (let i = 0; i < chunks; i++) {
const chunkQuery = `get.chunk-${i}.${key}.${namespace}.${version}.resolvedb.net`;
chunkPromises.push(dns.resolveTxt(chunkQuery));
}
const chunkResults = await Promise.all(chunkPromises);
const reassembled = chunkResults
.map(r => r[0].join(''))
.map(r => r.match(/d=(.+)$/)?.[1])
.join('');
return JSON.parse(reassembled);
}
// Small data - return directly
const data = response.match(/d=(.+)$/)?.[1];
return JSON.parse(data);
}Blob URL Fallback
For data larger than 4KB, ResolveDB returns a redirect to a CDN-hosted blob.
DNS Query:
dig TXT get.largefile.hooli.v1.resolvedb.net +shortRedirect Response:
v=rdb1;s=redirect;t=url;ttl=3600;d=https://cdn.resolvedb.cloud/blob/abc123def456JavaScript - Handle Redirect:
const dns = require('dns').promises;
async function getData(key, namespace, version) {
const query = `get.${key}.${namespace}.${version}.resolvedb.net`;
const records = await dns.resolveTxt(query);
const response = records[0].join('');
// Check for redirect
if (response.includes('s=redirect')) {
const url = response.match(/d=(.+)$/)?.[1];
// Fetch from CDN
const blobData = await fetch(url).then(r => r.json());
return blobData;
}
// Direct data
const data = response.match(/d=(.+)$/)?.[1];
return JSON.parse(data);
}Python:
import dns.resolver
import json
import re
import requests
def get_data(key, namespace, version):
query = f'get.{key}.{namespace}.{version}.resolvedb.net'
answers = dns.resolver.resolve(query, 'TXT')
response = str(answers[0]).strip('"')
# Check for redirect
if 's=redirect' in response:
match = re.search(r'd=(.+)$', response)
if match:
url = match.group(1)
return requests.get(url).json()
# Direct data
match = re.search(r'd=(.+)$', response)
if match:
return json.loads(match.group(1))
return NoneEncrypted Secrets
Store sensitive data with client-side encryption. ResolveDB never sees the plaintext.
AES-256-GCM Encryption
Encrypt data before storing, decrypt after retrieval.
Store Encrypted Secret (via API):
# Client-side: encrypt data before sending
# encrypted = AES-256-GCM(plaintext, key)
# encoded = base64(nonce + ciphertext + tag)
curl -X POST https://api.resolvedb.io/api/v1/records \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"record": {
"key": "secrets.db-password.prod.v1",
"data": "<base64_encrypted_data>",
"encrypted": true
}
}'JavaScript - Encrypt & Store:
const crypto = require('crypto');
// Encryption key (store securely, e.g., in environment or KMS)
const ENCRYPTION_KEY = Buffer.from(process.env.RESOLVEDB_ENCRYPTION_KEY, 'hex');
function encrypt(plaintext) {
const iv = crypto.randomBytes(12);
const cipher = crypto.createCipheriv('aes-256-gcm', ENCRYPTION_KEY, iv);
let encrypted = cipher.update(plaintext, 'utf8');
encrypted = Buffer.concat([encrypted, cipher.final()]);
const tag = cipher.getAuthTag();
// Combine: iv (12) + encrypted + tag (16)
return Buffer.concat([iv, encrypted, tag]).toString('base64');
}
function decrypt(encryptedBase64) {
const data = Buffer.from(encryptedBase64, 'base64');
const iv = data.subarray(0, 12);
const tag = data.subarray(-16);
const ciphertext = data.subarray(12, -16);
const decipher = crypto.createDecipheriv('aes-256-gcm', ENCRYPTION_KEY, iv);
decipher.setAuthTag(tag);
let decrypted = decipher.update(ciphertext);
decrypted = Buffer.concat([decrypted, decipher.final()]);
return decrypted.toString('utf8');
}
// Store secret
const secret = 'my-database-password';
const encrypted = encrypt(secret);
// Send 'encrypted' to ResolveDB API
// Retrieve and decrypt
const response = await getFromResolveDB('secrets.db-password.prod.v1');
const plaintext = decrypt(response);Python:
from cryptography.hazmat.primitives.ciphers.aead import AESGCM
import os
import base64
# Encryption key (32 bytes for AES-256)
ENCRYPTION_KEY = bytes.fromhex(os.environ['RESOLVEDB_ENCRYPTION_KEY'])
def encrypt(plaintext: str) -> str:
aesgcm = AESGCM(ENCRYPTION_KEY)
nonce = os.urandom(12)
ciphertext = aesgcm.encrypt(nonce, plaintext.encode(), None)
# Combine nonce + ciphertext (includes tag)
return base64.b64encode(nonce + ciphertext).decode()
def decrypt(encrypted_b64: str) -> str:
data = base64.b64decode(encrypted_b64)
nonce = data[:12]
ciphertext = data[12:]
aesgcm = AESGCM(ENCRYPTION_KEY)
plaintext = aesgcm.decrypt(nonce, ciphertext, None)
return plaintext.decode()
# Usage
secret = 'my-database-password'
encrypted = encrypt(secret)
# Store 'encrypted' in ResolveDB
# Later: retrieve and decrypt
plaintext = decrypt(encrypted)Key Management Patterns
Best practices for managing encryption keys:
- Environment-specific keys: Use different encryption keys per environment (dev, staging, prod)
- Key rotation: Store versioned keys, include key version in encrypted data metadata
- Key derivation: Derive per-record keys from master key using HKDF
- Cloud KMS: Use AWS KMS, GCP KMS, or Azure Key Vault for key storage
Key Derivation Example:
const crypto = require('crypto');
function deriveKey(masterKey, recordId) {
return crypto.hkdfSync(
'sha256',
masterKey,
Buffer.from(recordId),
Buffer.from('resolvedb-encryption'),
32
);
}
// Each record gets a unique derived key
const recordKey = deriveKey(masterKey, 'secrets.db-password.prod.v1');Edge Computing / Serverless
ResolveDB is ideal for serverless environments where cold starts matter. DNS resolution happens outside your function, with data already cached at edge locations.
AWS Lambda
Fetch configuration without HTTP client initialization overhead.
JavaScript (Node.js Runtime):
const dns = require('dns').promises;
// DNS is available immediately - no HTTP client needed
exports.handler = async (event) => {
// Resolves in ~1-5ms when cached (vs 50-200ms HTTP cold start)
const records = await dns.resolveTxt('get.settings.config.hooli.v1.resolvedb.net');
const response = records[0].join('');
const config = JSON.parse(response.match(/d=(.+)$/)?.[1]);
// Use config
const threshold = config.rate_limit || 100;
return {
statusCode: 200,
body: JSON.stringify({ processed: true })
};
};Python Runtime:
import dns.resolver
import json
import re
def lambda_handler(event, context):
# DNS resolution is fast - no connection pooling needed
answers = dns.resolver.resolve('get.settings.config.hooli.v1.resolvedb.net', 'TXT')
response = str(answers[0]).strip('"')
match = re.search(r'd=(.+)$', response)
config = json.loads(match.group(1)) if match else {}
# Use config
threshold = config.get('rate_limit', 100)
return {
'statusCode': 200,
'body': json.dumps({'processed': True})
}Cloudflare Workers
Use DNS-over-HTTPS in Workers where native DNS is not available.
export default {
async fetch(request, env) {
// Workers don't have native DNS, use DoH
const dohUrl = 'https://cloudflare-dns.com/dns-query';
const query = 'get.settings.config.hooli.v1.resolvedb.net';
const response = await fetch(
`${dohUrl}?name=${query}&type=TXT`,
{
headers: { 'Accept': 'application/dns-json' }
}
);
const data = await response.json();
const txtRecord = data.Answer?.[0]?.data?.replace(/"/g, '');
const config = JSON.parse(txtRecord.match(/d=(.+)$/)?.[1]);
return new Response(JSON.stringify({
feature_enabled: config.feature_enabled
}), {
headers: { 'Content-Type': 'application/json' }
});
}
};Vercel Edge Functions
Lightweight configuration for edge middleware.
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
export async function middleware(request: NextRequest) {
// Fetch feature flags via DoH (edge has no native DNS)
const doh = await fetch(
'https://dns.google/resolve?name=get.dark-mode.flags.hooli.v1.resolvedb.net&type=TXT'
);
const data = await doh.json();
const record = data.Answer?.[0]?.data?.replace(/"/g, '');
const flags = JSON.parse(record.match(/d=(.+)$/)?.[1]);
// A/B test based on feature flag
if (flags.new_checkout && Math.random() < flags.new_checkout_percent) {
return NextResponse.rewrite(new URL('/checkout-v2', request.url));
}
return NextResponse.next();
}
export const config = {
matcher: '/checkout/:path*'
};Why DNS is faster for serverless
- No TCP/TLS handshake (UDP-based)
- Cached at multiple layers (local, ISP, edge)
- No connection pooling or keep-alive management
- Available immediately in cold start (no client init)
- Sub-millisecond when cached locally
IoT / Embedded
Minimal DNS-only clients for resource-constrained devices. No HTTP stack required, works with any device that can make DNS queries.
Device Configuration
Push configuration to IoT devices via DNS. Devices poll their config periodically using lightweight DNS queries.
DNS Query:
# Device queries its own config by device ID
dig get.config.device-abc123.iot.v1.resolvedb.net TXT +shortExpected Response:
v=rdb1;s=ok;t=data;f=json;ttl=3600;d={"sample_rate":60,"report_interval":300,"firmware":"2.1.0"}Arduino/ESP32 (C++)
#include <WiFi.h>
#include <WiFiUdp.h>
#include <ArduinoJson.h>
WiFiUDP udp;
const char* DNS_SERVER = "8.8.8.8";
const int DNS_PORT = 53;
String dnsQuery(const char* hostname) {
// Simplified DNS query - use a proper DNS library in production
byte packet[512];
int len = buildDnsQuery(packet, hostname, DNS_TYPE_TXT);
udp.beginPacket(DNS_SERVER, DNS_PORT);
udp.write(packet, len);
udp.endPacket();
int responseLen = waitForResponse(packet, 512, 1000);
if (responseLen > 0) {
return parseTxtRecord(packet, responseLen);
}
return "";
}
void updateConfig() {
String deviceId = getDeviceId();
String query = "get.config." + deviceId + ".iot.v1.resolvedb.net";
String response = dnsQuery(query.c_str());
int dataStart = response.indexOf("d=");
if (dataStart > 0) {
String jsonData = response.substring(dataStart + 2);
StaticJsonDocument<256> doc;
deserializeJson(doc, jsonData);
int sampleRate = doc["sample_rate"] | 60;
int reportInterval = doc["report_interval"] | 300;
applySampleRate(sampleRate);
applyReportInterval(reportInterval);
}
}
void loop() {
updateConfig();
delay(3600000); // Check hourly (matches TTL)
}MicroPython (ESP8266/ESP32)
import socket
import ujson
import ure
def dns_query_txt(hostname):
"""Simple TXT record query using system resolver"""
try:
import udns # hypothetical lightweight DNS library
records = udns.query(hostname, 'TXT')
return records[0] if records else None
except Exception as e:
print(f"DNS error: {e}")
return None
def get_config():
device_id = get_device_id()
hostname = f"get.config.{device_id}.iot.v1.resolvedb.net"
response = dns_query_txt(hostname)
if response:
match = ure.search(r'd=(.+)$', response)
if match:
config = ujson.loads(match.group(1))
return config
return {}
# Main loop
while True:
config = get_config()
sample_rate = config.get('sample_rate', 60)
set_sample_rate(sample_rate)
import time
time.sleep(config.get('ttl', 3600))Fleet Configuration Distribution
Push updates to groups of devices simultaneously.
# Global config for all devices
dig get.config.global.iot.v1.resolvedb.net TXT +short
# Config by device type
dig get.config.sensor-v2.iot.v1.resolvedb.net TXT +short
# Config by location
dig get.config.warehouse-nyc.iot.v1.resolvedb.net TXT +short
# Individual device override
dig get.config.device-abc123.iot.v1.resolvedb.net TXT +shortConfiguration Hierarchy (Device Code):
def get_merged_config():
"""Fetch config with fallback hierarchy"""
config = {}
# 1. Start with global defaults
global_config = query_config('global')
config.update(global_config)
# 2. Apply device type overrides
type_config = query_config(f'sensor-{DEVICE_TYPE}')
config.update(type_config)
# 3. Apply location overrides
location_config = query_config(f'location-{DEVICE_LOCATION}')
config.update(location_config)
# 4. Apply device-specific overrides
device_config = query_config(f'device-{DEVICE_ID}')
config.update(device_config)
return configIoT Advantages
- Minimal code footprint - DNS is a standard protocol
- No TLS certificates needed for read-only config
- Works behind NAT without port forwarding
- Firewall-friendly (DNS typically allowed)
- Low power - single UDP packet vs TCP connection
Financial Data
Real-time stock quotes, forex exchange rates, and cryptocurrency prices via DNS. Data is sourced from multiple providers with automatic fallback for reliability.
Stock Quotes
Query real-time stock prices by ticker symbol.
DNS Query:
# Popular stock symbols
dig TXT get.AAPL.stock.public.v1.resolvedb.net +short
dig TXT get.GOOGL.stock.public.v1.resolvedb.net +short
dig TXT get.MSFT.stock.public.v1.resolvedb.net +short
dig TXT get.TSLA.stock.public.v1.resolvedb.net +shortDoH (HTTPS) Request:
curl -s "https://api.resolvedb.io/resolve?name=get.AAPL.stock.public.v1.resolvedb.net&type=TXT" | jqExpected Response:
v=rdb1;s=ok;t=data;ttl=60;ts=1735776000;sym=AAPL;prc=189.95;chg=2.34;pct=1.25;vol=52300000;opn=187.50;hi=191.05;lo=186.82Response Fields:
| Field | Description | Example |
|---|---|---|
sym | Stock symbol | AAPL |
prc | Current price | 189.95 |
chg | Price change | 2.34 |
pct | Percent change | 1.25 |
vol | Volume | 52300000 |
opn | Open price | 187.50 |
hi | Day high | 191.05 |
lo | Day low | 186.82 |
JavaScript:
const dns = require('dns').promises;
async function getStockQuote(ticker) {
const query = `get.${ticker.toUpperCase()}.stock.public.v1.resolvedb.net`;
const records = await dns.resolveTxt(query);
const response = records[0].join('');
// Parse UQRP fields
const price = parseFloat(response.match(/prc=([^;]+)/)?.[1]);
const change = parseFloat(response.match(/chg=([^;]+)/)?.[1]);
const pct = parseFloat(response.match(/pct=([^;]+)/)?.[1]);
return { ticker, price, change, percentChange: pct };
}
const quote = await getStockQuote('AAPL');
console.log(`${quote.ticker}: $${quote.price} (${quote.percentChange > 0 ? '+' : ''}${quote.percentChange}%)`);
// Output: AAPL: $189.95 (+1.25%)Python:
import dns.resolver
import re
def get_stock_quote(ticker):
query = f'get.{ticker.upper()}.stock.public.v1.resolvedb.net'
answers = dns.resolver.resolve(query, 'TXT')
response = str(answers[0]).strip('"')
# Parse UQRP fields
fields = {}
for part in response.split(';'):
if '=' in part:
key, value = part.split('=', 1)
fields[key] = value
return {
'ticker': fields.get('sym'),
'price': float(fields.get('prc', 0)),
'change': float(fields.get('chg', 0)),
'percent_change': float(fields.get('pct', 0))
}
quote = get_stock_quote('AAPL')
print(f"{quote['ticker']}: ${quote['price']:.2f} ({quote['percent_change']:+.2f}%)")Forex Exchange Rates
Query real-time currency exchange rates with accurate mid-market rates.
DNS Query:
# Popular currency pairs
dig TXT get.USD-EUR.forex.public.v1.resolvedb.net +short
dig TXT get.USD-CAD.forex.public.v1.resolvedb.net +short
dig TXT get.EUR-GBP.forex.public.v1.resolvedb.net +short
dig TXT get.GBP-JPY.forex.public.v1.resolvedb.net +shortDoH (HTTPS) Request:
curl -s "https://api.resolvedb.io/resolve?name=get.USD-EUR.forex.public.v1.resolvedb.net&type=TXT" | jqExpected Response:
v=rdb1;s=ok;t=data;ttl=60;ts=1735776000;from=USD;to=CAD;rate=1.438650Response Fields:
| Field | Description | Example |
|---|---|---|
from | Source currency | USD |
to | Target currency | CAD |
rate | Exchange rate | 1.438650 |
JavaScript:
const dns = require('dns').promises;
async function getForexRate(from, to) {
const query = `get.${from.toUpperCase()}-${to.toUpperCase()}.forex.public.v1.resolvedb.net`;
const records = await dns.resolveTxt(query);
const response = records[0].join('');
const rate = parseFloat(response.match(/rate=([^;]+)/)?.[1]);
return { from: from.toUpperCase(), to: to.toUpperCase(), rate };
}
const fx = await getForexRate('USD', 'CAD');
console.log(`1 ${fx.from} = ${fx.rate.toFixed(4)} ${fx.to}`);
// Output: 1 USD = 1.4387 CADPython:
import dns.resolver
import re
def get_forex_rate(from_currency, to_currency):
pair = f'{from_currency.upper()}-{to_currency.upper()}'
query = f'get.{pair}.forex.public.v1.resolvedb.net'
answers = dns.resolver.resolve(query, 'TXT')
response = str(answers[0]).strip('"')
rate_match = re.search(r'rate=([^;]+)', response)
rate = float(rate_match.group(1)) if rate_match else 0.0
return {
'from': from_currency.upper(),
'to': to_currency.upper(),
'rate': rate
}
fx = get_forex_rate('USD', 'CAD')
print(f"1 {fx['from']} = {fx['rate']:.4f} {fx['to']}")Cryptocurrency Prices
Query real-time cryptocurrency prices in various quote currencies.
DNS Query:
# Popular cryptocurrencies
dig TXT get.BTC-USD.crypto.public.v1.resolvedb.net +short
dig TXT get.ETH-USD.crypto.public.v1.resolvedb.net +short
dig TXT get.ETH-EUR.crypto.public.v1.resolvedb.net +short
dig TXT get.SOL-USD.crypto.public.v1.resolvedb.net +shortDoH (HTTPS) Request:
curl -s "https://api.resolvedb.io/resolve?name=get.BTC-USD.crypto.public.v1.resolvedb.net&type=TXT" | jqExpected Response:
v=rdb1;s=ok;t=data;ttl=60;ts=1735776000;sym=BTC;cur=USD;prc=42500.00;chg24=850.00;pct24=2.04Response Fields:
| Field | Description | Example |
|---|---|---|
sym | Crypto symbol | BTC |
cur | Quote currency | USD |
prc | Current price | 42500.00 |
chg24 | 24-hour change | 850.00 |
pct24 | 24-hour percent change | 2.04 |
JavaScript:
const dns = require('dns').promises;
async function getCryptoPrice(symbol, quoteCurrency = 'USD') {
const query = `get.${symbol.toUpperCase()}-${quoteCurrency.toUpperCase()}.crypto.public.v1.resolvedb.net`;
const records = await dns.resolveTxt(query);
const response = records[0].join('');
const price = parseFloat(response.match(/prc=([^;]+)/)?.[1]);
const change24h = parseFloat(response.match(/pct24=([^;]+)/)?.[1] || '0');
return { symbol: symbol.toUpperCase(), quoteCurrency, price, change24h };
}
const btc = await getCryptoPrice('BTC', 'USD');
console.log(`${btc.symbol}: $${btc.price.toLocaleString()} (${btc.change24h > 0 ? '+' : ''}${btc.change24h}% 24h)`);
// Output: BTC: $42,500 (+2.04% 24h)Python:
import dns.resolver
import re
def get_crypto_price(symbol, quote_currency='USD'):
pair = f'{symbol.upper()}-{quote_currency.upper()}'
query = f'get.{pair}.crypto.public.v1.resolvedb.net'
answers = dns.resolver.resolve(query, 'TXT')
response = str(answers[0]).strip('"')
# Parse fields
fields = {}
for part in response.split(';'):
if '=' in part:
key, value = part.split('=', 1)
fields[key] = value
return {
'symbol': fields.get('sym'),
'quote_currency': fields.get('cur'),
'price': float(fields.get('prc', 0)),
'change_24h': float(fields.get('pct24', 0))
}
btc = get_crypto_price('BTC', 'USD')
print(f"{btc['symbol']}: ${btc['price']:,.2f} ({btc['change_24h']:+.2f}% 24h)")Currency Converter
Build a simple currency converter using forex rates.
JavaScript:
const dns = require('dns').promises;
async function convertCurrency(amount, from, to) {
const query = `get.${from.toUpperCase()}-${to.toUpperCase()}.forex.public.v1.resolvedb.net`;
const records = await dns.resolveTxt(query);
const response = records[0].join('');
const rate = parseFloat(response.match(/rate=([^;]+)/)?.[1]);
const converted = amount * rate;
return {
from: { amount, currency: from.toUpperCase() },
to: { amount: converted, currency: to.toUpperCase() },
rate
};
}
// Convert $100 USD to CAD
const result = await convertCurrency(100, 'USD', 'CAD');
console.log(`$${result.from.amount} ${result.from.currency} = $${result.to.amount.toFixed(2)} ${result.to.currency}`);
// Output: $100 USD = $143.87 CADPortfolio Tracker
Track multiple assets with a single batch of DNS queries.
JavaScript:
const dns = require('dns').promises;
async function getPortfolio(holdings) {
const queries = holdings.map(async ({ type, symbol, quantity }) => {
let query;
if (type === 'stock') {
query = `get.${symbol}.stock.public.v1.resolvedb.net`;
} else if (type === 'crypto') {
query = `get.${symbol}-USD.crypto.public.v1.resolvedb.net`;
}
const records = await dns.resolveTxt(query);
const response = records[0].join('');
const price = parseFloat(response.match(/prc=([^;]+)/)?.[1]);
return {
symbol,
type,
quantity,
price,
value: price * quantity
};
});
const positions = await Promise.all(queries);
const totalValue = positions.reduce((sum, p) => sum + p.value, 0);
return { positions, totalValue };
}
const portfolio = await getPortfolio([
{ type: 'stock', symbol: 'AAPL', quantity: 10 },
{ type: 'stock', symbol: 'GOOGL', quantity: 5 },
{ type: 'crypto', symbol: 'BTC', quantity: 0.5 }
]);
console.log(`Total portfolio value: $${portfolio.totalValue.toLocaleString()}`);
portfolio.positions.forEach(p => {
console.log(` ${p.symbol}: ${p.quantity} x $${p.price} = $${p.value.toLocaleString()}`);
});Error Handling
Finance queries return structured errors for invalid symbols or service issues.
Invalid Symbol Response:
v=rdb1;s=err;err=E008;ttl=1;ts=1735776000;d=Symbol not foundRate Limited Response:
v=rdb1;s=err;err=E009;ttl=1;ts=1735776000;retry=60;d=Rate limit exceededJavaScript Error Handling:
const dns = require('dns').promises;
async function safeGetStock(ticker) {
try {
const query = `get.${ticker.toUpperCase()}.stock.public.v1.resolvedb.net`;
const records = await dns.resolveTxt(query);
const response = records[0].join('');
// Check for error status
if (response.includes('s=err')) {
const errorCode = response.match(/err=([^;]+)/)?.[1];
const message = response.match(/d=(.+)$/)?.[1];
throw new Error(`${errorCode}: ${message}`);
}
const price = parseFloat(response.match(/prc=([^;]+)/)?.[1]);
return { ticker, price, success: true };
} catch (error) {
return { ticker, error: error.message, success: false };
}
}
const result = await safeGetStock('INVALID');
if (!result.success) {
console.log(`Failed to get quote: ${result.error}`);
}