AI 资讯
Regex Against a PDF: The One Endpoint That Skips OCR Entirely
Most document pipelines have a reflex. A PDF comes in, and the first instinct is: run OCR, then parse it. That reflex costs time and money on documents that never needed it in the first place. Here's the distinction that gets skipped over. A PDF generated from Word, from an invoicing system, from a web page, from almost any modern software, is "born digital." Every character on the page is already stored as text, positioned and selectable, the same way this article's text is selectable in your browser. A scanned PDF is different: it's a photograph of a page, a grid of pixels with no text underneath it at all. OCR exists to solve that second problem. It reads the pixels and reconstructs a text layer that wasn't there. PDF OCR is PDF4me's endpoint for exactly that job, and its own documentation lists "Intelligent Processing: skip OCR when text is already searchable to optimize performance" as a named feature, which is the whole thesis of this article in one line. But if the PDF already has a text layer, running it through OCR first is a wasted step: extra processing time, extra cost, extra room for OCR to introduce recognition errors into text that was already perfect. A large share of the PDFs moving through business automation, generated invoices, exported reports, system-generated confirmations, contracts drafted in Word and exported to PDF, are born digital from the start. They don't need OCR. They need something that can read the text layer that's already there and pull out exactly the values that matter. That's what Extract Text by Expression does. One regex, one endpoint POST https://api.pdf4me.com/api/v2/ExtractTextByExpression No OCR step. No AI model. No template you have to build in a dashboard first. The request is small: Parameter Type Required Description docContent Base64 String Yes The source PDF, Base64-encoded docName String Yes Filename with .pdf extension expression String Yes A standard regular expression: groups, quantifiers, and anchors all supp
AI 资讯
Vibe Coding vs Prompt-Driven: One Year Later, the Debate Is Already Outdated
A year ago, the debate between “vibe coding” and “prompt-driven development” felt like the right lens for using AI in software. Today it’s outdated. The real frontier is no longer how to phrase a request, but how to build an environment that lets an AI agent explore, modify, and verify code safely. The shift from conversational prompts to structured development harnesses changes what it means to ship reliable software. Below are four concrete ways this evolution is reshaping daily work. From Prompt to Harness A finely crafted prompt can still produce a working feature, but it won’t prevent an agent from inventing APIs, skipping tests, or misreading business rules. The new bottleneck is the harness: Git for traceability, tests for feedback, linting for style, and explicit rules for constraints. When these elements are in place, even a short instruction like “fix the bug” can trigger a reliable, auditable workflow. Code is Abundant; Good Software is Rare Generating hundreds of lines of code costs almost nothing, but verifying that those lines align with product history, security policies, and hidden constraints is still manual. The developer’s scarcest resource is now judgment: deciding what to automate, what to document, and when to override the agent’s plausible but wrong solution. Documentation is Now for Machines README files and ADRs used to serve only humans. Today they also feed the agent’s context. A well-maintained AGENTS.md , coherent tests, and executable examples let an AI act with minimal prompting while remaining aligned with the team’s conventions. The repository becomes a self-explaining environment. Supervision is the Next Skill Single-agent workflows are giving way to multi-agent orchestration. Frontend, API, test analysis, and incident triage agents must coordinate without stepping on each other. Observability, conflict detection, and rollback mechanisms replace prompt tuning as the critical layer of control. The center of gravity has moved from “ho
AI 资讯
I Built a Claude Code Skill That Reverse-Engineers Undocumented APIs
I Built a Claude Code Skill That Reverse-Engineers Undocumented APIs Because "the docs are in the code" is not a documentation strategy. The Week I Lost to Grepping I joined a new team last month. Day 1 task: add a feature to the billing service. Day 1 reality: I opened the API docs and realized they were from 2022. Half the routes had been rewritten. The other half never had docs to begin with. So I did what every backend dev does. I grepped. grep -r "app.get|app.post|router." src/ --include="*.js" Four hours later, I had a notebook full of endpoints, a headache, and zero confidence that I had found everything. I found routes that worked but were not documented. I found docs for routes that did not exist anymore. I found one GET /invoices/:id endpoint with zero auth checks that had been sitting there since 2022. This is normal. And it should not be. The Idea What if I could drop a single file into a repo and have Claude Code map the entire API layer for me? Not from annotations. Not from existing OpenAPI specs. From the actual code. So I built it. Meet API Archaeologist API Archaeologist is a Claude Code / Codex CLI skill that reads your source code and reverse-engineers your API layer. It finds: • Internal endpoints — REST, GraphQL, gRPC, WebSockets • External integrations — third-party APIs, webhooks, SDK clients • Auth flows — JWT, OAuth, API keys, session cookies, RBAC • Security gaps — unauthenticated routes, hardcoded secrets, missing rate limits • Dead code — auth middleware with no endpoints, orphaned routes And it generates two things: API_DISCOVERY.md — A complete catalog with Mermaid diagrams openapi-draft.yaml — A draft OpenAPI spec How It Works The skill is just a SKILL.md file. Claude Code reads it and follows the instructions. It: Discovers route definitions Traces handlers, DTOs, middleware, services, and database calls Maps authentication and authorization Finds external API calls and integrations Flags potential security and reliability risks Gene
AI 资讯
GitHub API Rate Limits: an Unauthenticated 304 Still Costs You a Request
No token. One IP. July 29, 2026: GET /repos/python/cpython 200 5996 B remaining 32 -> 31 + If-None-Match (no Authorization header) 304 0 B remaining 31 -> 30 + If-None-Match 304 0 B remaining 30 -> 29 + If-None-Match 304 0 B remaining 29 -> 28 Three conditional requests. Three 304 Not Modified . Zero bytes of body across all three. Three requests gone from a bucket of 60 per hour. I opened the terminal to write the opposite post. The short version: if you call the GitHub REST API without an Authorization header, an If-None-Match request that comes back 304 still decrements x-ratelimit-remaining . The ETag saves you bytes. It does not save you quota. GitHub's documentation states the claim five times on one page and attaches the condition to two of them, and that clause falls off easily when a sentence gets quoted on its own. The post I meant to write My working title was something like "poll GitHub for free with ETags". I believed it. I had read the sentence about 304 responses not using your rate limit, I had repeated it to other people, and the plan was a tidy little piece with a before-and-after budget chart. The first run killed it. remaining went down. My first reaction was that my counter reading was wrong, which is the normal reaction and usually the correct one. It was not wrong. So the post changed, and the finding turned out to be worth more than the one I went in with. Does a 304 count against the GitHub rate limit? What the docs actually say Here is the part that matters, and I want to be precise because it would be easy and dishonest to turn this into "GitHub's docs are wrong". They are not. On the page Best practices for using the REST API the claim shows up five times. Two of the five carry a condition; three do not. Here is the strict one, the only place on the page where the condition is spelled out as a header: "Making a conditional request does not count against your primary rate limit if a 304 response is returned and the request was made while c
AI 资讯
Designing Reliable APIs for Production Applications: Lessons From Building Real-World Digital Products
Designing Reliable APIs for Production Applications: Lessons From Building Real-World Digital Products APIs are often described as the “bridge” between different parts of an application, but building a production-ready API involves much more than sending data from a frontend to a backend. Through my experience building full-stack applications, I've learned that a good API needs to be designed around reliability, security, maintainability and the actual needs of its users. Here are some of the principles I now consider when designing APIs: Design around resources, not screens An API shouldn't simply mirror the frontend interface. It should expose meaningful resources and operations that can evolve independently from the UI. Validate everything at the API boundary Data coming from a client should never be trusted automatically. Request validation, type checking and clear error responses help prevent invalid data from propagating through the system. Authentication is only the beginning An authenticated user should not automatically have access to every resource. APIs need appropriate authorisation and access-control rules for sensitive operations. Design predictable errors A useful API doesn't just return “something went wrong.” Clients need consistent status codes and structured error responses so that applications can respond appropriately. Think about idempotency This becomes particularly important when an API handles operations such as payments, orders or other actions that shouldn't accidentally happen twice because of a network retry. Don't expose unnecessary data APIs should return what the client needs rather than exposing entire database records. This reduces unnecessary data transfer and can also reduce the risk of accidentally exposing sensitive information. Logging and observability matter An API can appear perfect during development and still fail in production. Good logging and monitoring make it possible to understand what happened when requests fail, la
AI 资讯
Building a Production ML Trading Dashboard with the Dhan API
Real integration notes for wiring NIFTY ML models to live broker data via Dhan. Research/ paper-trading context — not a live-trading recommendation. Why Dhan Dhan's API exposes direct option-chain access — exactly what an options-ML system needs: POST /optionchain — full chain for an underlying POST /optionchain/expirylist — available expiries Fields: security_id , last_price , volume , oi , previous_oi , implied_volatility , top_bid_price , top_ask_price , and greeks (delta/theta/gamma/vega) Security IDs are stable: NIFTY = 13 (IDX_I) , BANKNIFTY = 10001 (IDX_I) . The Pipeline Shape A research dashboard pulls live chain + underlying, runs the trained XGBoost model on each new 15-minute bar, and displays: side score (CE/PE alignment) gate state (entry ready / blocked) contract quality scores a doctrine/backtest report Keep the inference path separate from the execution path . The dashboard shows; a permissioned, human-approved module places orders. Paper Trade First The DhanLiveTrader pattern: load the model, predict on each new bar, place long orders with configurable SL/TP (default 1.0 ATR SL, 2.0 ATR TP), and run in paper mode first . Only after stable out-of-sample + paper evidence should any execution module even be considered. { "client_id" : "YOUR_DHAN_CLIENT_ID" , "access_token" : "YOUR_DHAN_ACCESS_TOKEN" , "is_paper_trade" : true , "nifty_symbol" : "NIFTY" , "quantity" : 50 , "max_trades_per_day" : 3 , "sl_atr_mult" : 1.0 , "tp_atr_mult" : 2.0 } The Hard Part: Stops A known footgun: using a Stop-Loss Limit (SL-L) order with price = sl − 0.05 means it won't fill if price crashes through the stop. Prefer SL-Market for the protective stop. Execution quality is its own research topic — don't bolt it on at the end. Honest Status The ML side of this stack showed real directional skill (60.5% top-decile accuracy) but the fixed-SL backtest was still unprofitable (PF 0.53). A dashboard that displays an honest "RESEARCH / PAPER" status is worth more than one that hid
AI 资讯
How to upload a file over JSON-RPC, when JSON has no type for a file
JSON has no representation for a file. Strings, numbers, arrays, objects - that is the whole list. So every JSON-RPC API eventually runs into the same question: how do you accept a file upload - a photo, a scan, a PDF - when the protocol itself cannot carry binary data? The usual answer is: you don't. The file goes to a separate, ordinary controller that reads $request->files , and the JSON-RPC layer handles everything else next to it. And now you have exactly the ad hoc endpoint sprawl that JSON-RPC was supposed to remove. In otezvikentiy/json-rpc-api 5.2 there is a different answer. And more interesting than the feature is how it came about: I did not write it - an external contributor did. But first things first. Full disclosure: I am the author of the bundle, and I have maintained it alone for almost three years. That is exactly why a release whose headline feature was written by someone else feels like a different kind of event to me. The problem Straight from issue #8 : two services exchange scanned images plus structured metadata (tenant, station, session) on the same call - something like captures.create(tenantId, stationId, image) . Today image cannot be expressed as a parameter of a JSON-RPC method, so that call has to live outside the bundle as a separate multipart controller. What you want is for the method to simply declare a parameter of type UploadedFile and get the file, like any other parameter. The solution: multipart as a transport adapter The key idea is to leave the core untouched. A multipart/form-data request is normalized into the very same JSON-RPC envelope an ordinary request produces, only with UploadedFile objects already sitting inside params . Everything below the transport - hydration, batching, validation - stays completely unaware of multipart, exactly the way it is unaware that a GET request's payload came from a query string. The wire format: one text part named jsonrpc carries the full JSON-RPC envelope as a string (all scalar par
AI 资讯
Three Lines to Draw Before You Scrape Instagram
Most write-ups on this subject are about technique. This one is about the three decisions you should make before you write any code, because in my experience every project that went badly went badly for a reason that was decided on day one and not noticed until much later. I have built this kind of collection twice, for competitive analysis and for a partner-vetting workflow. Neither of them needed to touch anything behind a login, and I want to explain why that turned out to be the useful constraint rather than the limiting one. Line one: the login wall is a boundary A login wall is a statement about who the content is for. Treating it as an engineering obstacle to be routed around is the decision that puts a project on the wrong side of everything: terms of service, the platform's own detection, and in several jurisdictions the law. So the first line is simply: if it requires an account to see, it is out of scope. Not "hard," not "for later." Out of scope. I am not going to discuss techniques for getting past one, and I would be sceptical of any article that does. The interesting engineering question here is not how to see more. It is how much you can actually do with what is openly published, and the honest answer is: considerably more than people assume before they check. This constraint also has a practical benefit that is easy to miss. A pipeline built only on openly available data does not break when authentication changes, does not require credential management, and does not put an account at risk. Mine has survived two platform changes that took down colleagues' authenticated collectors. Line two: public does not mean unrestricted The second line is the one developers get wrong most often, and it has nothing to do with access. Data being publicly visible says nothing about whether you may store it, for how long, or what you may do with it. In the EU and UK, information about an identifiable person is personal data whether or not they published it themselves
AI 资讯
Secure AI APIs in 2026: Authentication, Authorization, Rate Limiting and Protecting Agentic Workflows
Building Secure AI-Powered Applications with Laravel, APIs and Modern Agentic Architectures Introduction AI-powered applications are moving beyond simple chat interfaces. Modern AI systems can interact with APIs, databases, external services, and business workflows, allowing AI agents to perform actions rather than simply generate responses. This creates a new security challenge. A traditional API may follow: User → API → Database → Response An AI-powered application can look more like: User ↓ AI Agent ↓ Tool / API ↓ Business Logic ↓ Database / External Service ↓ Action The difference is important because an AI agent may make multiple decisions and tool calls during a single workflow. OWASP’s current GenAI security guidance identifies risks including prompt injection, sensitive information disclosure, improper output handling, excessive agency, and unbounded consumption. (OWASP Foundation) Therefore, securing an AI API requires more than protecting an API key. Developers need layered controls for authentication, authorization, rate limiting, input validation, tool permissions, data protection, human approval, and monitoring. 1. Why AI APIs Are Different Traditional APIs usually perform clearly defined operations: POST /api/orders The application can authenticate the user, validate the request, check authorization, and process the order. An AI agent introduces another layer: User Request ↓ AI Agent ↓ Select Tool ↓ API Request ↓ Authorization ↓ Business Logic ↓ Action For example, a customer might ask: “Check my latest order and process a refund if I am eligible.” The agent could potentially: Find the customer. Retrieve the order. Check the refund policy. Call a payment API. Create a refund. Notify the customer. Each operation represents a potential security boundary. This is why agentic systems require controls over not only individual API calls, but also the actions an agent is allowed to perform. OWASP specifically identifies excessive functionality, excessive perm
AI 资讯
Moderation Intake Accounting: Bulk LLM Text Classification API With Tenant Chargeback
Short answer: For cheap bulk CSV tagging, use an asynchronous LLM text classification API, estimate each tenant batch before it runs, and attach the eventual export to the same tenant ledger instead of sending one request per row. For a one-person B2B SaaS, the useful comparison is not a model leaderboard. It is the amount of accounting and integration work left in the product after classification finishes. Option Choose it when Tenant-cost consequence Catch Infrai You want a self-describing REST API whose public discovery supplies request and response schemas plus runnable examples One key and one bill make the external side of reconciliation smaller Moderation uses chat classification with JSON Schema because there is no dedicated moderation endpoint OpenAI direct Your product has already standardized on OpenAI Keep tenant attribution in your own job ledger A direct contract does not remove application-level CSV reconciliation Anthropic direct Your model decision is already Anthropic-specific Use the same internal ledger pattern You own the provider-specific adapter and export mapping Google Gemini direct Your model decision is already Gemini-specific Use the same internal ledger pattern You own the provider-specific adapter and export mapping Recommendation: use asynchronous chat classification with a closed label set, but treat the tenant ledger as the primary artifact and the provider batch as an execution detail. That keeps a nightly backfill away from the request path and makes every charge explainable before a human moderator sees the result. The model matters. The accounting boundary matters more. Start with the allocation unit, not the provider A moderation upload arrives as a CSV, but a CSV is a transport format, not a billing unit. The billing unit should be an immutable application job owned by one tenant. Give that job an internal ID, record the source-file identity, preserve the row identifiers, and bind the approved label vocabulary to it. Then estim
AI 资讯
Startup or Enterprise? How to Pick the Right AI API Stack
Look, startup or Enterprise? How to Pick the Right AI API Stack Let me set the scene for you. A few months back, I was chatting with two friends on completely opposite ends of the AI spectrum. One was bootstrapping a side project on pizza and prayers, wondering if he could afford to add an LLM to his SaaS without going bankrupt. The other was leading engineering at a mid-sized fintech, sweating bullets because his CTO wanted enterprise-grade guarantees before signing a single contract. Same problem on paper: "we need an AI API." Completely different universes in practice. Here's how I'd actually walk each of them through it — and why the generic guides you'll find on the internet miss the mark. The Misconception That Trips Everyone Up I want to be honest with you about something. Most AI API guides assume both audiences want the same thing at different scales. That's wrong. Dead wrong. A startup founder I know burned through two weeks trying to wire up DeepSeek's direct API last quarter. He gave up not because the tech was hard, but because he didn't have a Chinese payment method, didn't want to verify with a Chinese phone number, and got stuck in a KYC loop. Meanwhile, an enterprise architect I talked to last month was spending months negotiating with OpenAI's sales team on annual contracts for committed-use pricing — when all he wanted was a predictable API endpoint with a real SLA behind it. The lesson? The "go straight to the provider" advice is a non-starter for a lot of people, and nobody's talking about why. Let me show you what actually matters depending on which side of the fence you're on. What Startups Actually Need (And Don't) Let me break this down. If you're building a startup — early stage, scrappy, maybe pre-seed or seed — your AI API checklist looks something like this: Cost matters more than perfection You want to experiment with multiple models without signing 12 contracts You need to ship this week, not next quarter Your "compliance team" is just
AI 资讯
How to Turn Latitude and Longitude into an Address with JavaScript
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
AI 资讯
Rails Routing & APIs: What Actually Happens Between the URL and Your Controller
When I started studying APIs more seriously, I realized there was a problem with the way I was learning. I knew how to create a Rails API. I knew how to write: resources :products I knew what GET , POST , PATCH and DELETE were supposed to do. But I wasn't always able to explain why things worked the way they did. So I decided to go one step back and review the fundamentals: routing, HTTP, REST and how Rails puts all of these things together. This is what I learned. Rails Routing At its simplest, routing is the thing that connects a URL to some code in your application. In Rails, this happens in routes.rb . For example: get '/about' , to: 'pages#about' If someone requests: GET /about Rails knows that it should call: PagesController #about Pretty straightforward. But Rails gets much more interesting when we start using RESTful routes. resources does a lot of work Instead of manually defining every route for a resource: get '/products' , to: 'products#index' get '/products/:id' , to: 'products#show' post '/products' , to: 'products#create' patch '/products/:id' , to: 'products#update' delete '/products/:id' , to: 'products#destroy' Rails lets us write: resources :products And generates the conventional CRUD routes for us. HTTP Verb Action Purpose GET index List resources GET show Show one resource GET new Form for a new resource POST create Create a resource GET edit Form to edit a resource PATCH update Update a resource DELETE destroy Delete a resource This is one of the reasons Rails feels so productive. The framework isn't just giving us routing functionality. It is encouraging a convention. resource vs resources This one confused me for a while. resources represents a collection: resources :products There can be many products, so Rails generates an index route. resource represents a single resource: resource :profile There isn't an index because we're talking about one profile. It is a small difference, but it makes sense once you think about the resource you're mo
AI 资讯
MCP Is Going Stateless: What Changed and How I Migrated My Currency Converter Server
The Model Context Protocol (MCP) has been evolving quickly. One of the most interesting changes in the latest MCP specification is the move toward a stateless protocol model . I recently updated my MCP currency converter server to work with the newer stateless behavior and the new split TypeScript SDK packages, particularly @modelcontextprotocol/server . In this article, I'll explain: What MCP sessions were doing What "stateless MCP" actually means Why the change matters for production systems How Streamable HTTP changes with the new specification How I migrated my currency converter MCP server What this means for scaling MCP servers What Is MCP? If you're new to MCP, the Model Context Protocol is a standard for connecting AI applications to external tools, resources, and data. Instead of building custom integrations between every AI application and every external service, MCP provides a common protocol. For example, an AI assistant can use an MCP server exposing a tool like: convert_currency The model can then request: Convert 100 USD to EUR. The MCP client communicates with the MCP server, which performs the actual operation and returns the result. MCP servers can expose several primitives, including tools, resources, and prompts. For my example, the server is intentionally simple: it exposes currency-conversion functionality. The Old Mental Model: MCP Sessions Before the stateless changes, Streamable HTTP could maintain a protocol-level session. Conceptually, the flow looked something like this: Client | | POST /mcp | initialize v MCP Server | | Mcp-Session-Id v Client | | POST /mcp | Mcp-Session-Id: abc123 v MCP Server The server creates a session during initialization. Subsequent requests contain the session identifier. That means the server can associate requests with the session that was established earlier. This isn't necessarily bad. Session state can be useful when an application genuinely needs conversational or connection-level state. But it creates an a
AI 资讯
Master Rate Limiting for LLM APIs in MuleSoft with Token-Bucket Policy
Hook: Imagine being able to set up rate limiting for your LLM APIs in MuleSoft—something that typically requires complex code—simply with just three clicks. No need to dive deep into Java or XML; it’s as simple as configuring a few settings on Anypoint. Demystifying Rate Limiting: Your Path to Controlled API Usage If you're a citizen developer or business analyst navigating the world of no-code/low-code automation, one common challenge is managing your LLM API usage without overwhelming your monthly budget. Tools like MuleSoft often present rigid pre-built connectors and complex data mapping transformations that can be daunting if you’re not well-versed in XML or Java. But fear not! The process doesn’t have to be as complicated as it seems. Let’s take a look at how Anypoint simplifies the implementation of rate limiting, allowing your client applications to use LLM APIs responsibly and without breaking the bank. Step 1: Setting Up Token Bucket Policy First, you'll want to set up a token-bucket policy on Anypoint that caps per-client spend. This is where MuleSoft’s flexibility shines through its intuitive interface: Navigate to Your API Gateway: Log in to your Anypoint Platform and select the API Gateway. Choose Rate Limiting Policy: In the policies section, choose 'Rate Limiting'. Configure Token Bucket Settings: Set up a token bucket policy where you define how many tokens (requests) are allowed within a given time frame. This straightforward setup prevents any single client from overusing LLM resources, ensuring fair and sustainable usage across all your applications. Step 2: Handling Excess Requests with Grace Now, what happens when a client exceeds their allocated limit? The magic of MuleSoft lies in its ability to handle these scenarios gracefully: Automated 429 Responses: When the rate limit is exceeded, Anypoint automatically returns a 429 status code (Too Many Requests). This clear response tells the client application that it needs to slow down. Retry-After
AI 资讯
How Do I Send Password Reset Emails from a Backend App Using an Email API?
Here's the full flow the way I've built it, using Notify as the email API. The shape of this is the same regardless of which provider you pick — generate a token, send a link, verify it on submit — so most of this applies no matter what you're using; I'll flag the one part that's specific to Notify. The Flow, End to End User requests a password reset Your backend generates a secure, short-lived reset token Your backend stores a hashed version of that token Your backend sends an email with the reset link, through an email API User clicks the link and submits a new password Your backend verifies the token, updates the password, and invalidates the token Step 1: Generate the Reset Token Use a cryptographically secure random value, not anything guessable, and store only a hashed version in your database — if your database ever leaks, the raw tokens aren't exposed alongside it: const crypto = require ( ' crypto ' ); function generateResetToken () { const token = crypto . randomBytes ( 32 ). toString ( ' hex ' ); const tokenHash = crypto . createHash ( ' sha256 ' ). update ( token ). digest ( ' hex ' ); return { token , tokenHash }; } Give it a short expiration — 15 to 60 minutes is typical. Step 2: Build the Reset URL https://yourapp.com/reset-password?token=RESET_TOKEN The token goes in the link the user clicks; the hash is what you store and check against later. Step 3: Send the Email This is the Notify-specific part. There's no SDK to install — it's a single HTTP request with your API key in the header: async function requestPasswordReset ( email ) { const user = await findUserByEmail ( email ); // Don't reveal whether the email exists if ( ! user ) return ; const { token , tokenHash } = generateResetToken (); const expiresAt = new Date ( Date . now () + 1000 * 60 * 30 ); // 30 minutes await saveResetToken ( user . id , tokenHash , expiresAt ); const resetLink = `https://yourapp.com/reset-password?token= ${ token } ` ; await fetch ( ' https://notify.cx/api/email/send
AI 资讯
I run a surf forecast for 20 breaks in Morocco on EUR 0/month. Here's the stack.
I live on the Taghazout coast in Morocco - a strip of Atlantic between Agadir and Imsouane that's basically one long right-hand point break after another. Two years ago the only way to know if tomorrow was worth it was to check three different global forecast sites, none of which knew the difference between Anchor Point and the beach break 400m south of it. So I built taghazout.io . It now covers 20 named breaks, runs in 10 languages, and costs me nothing per month. Here's how it's actually put together - including the parts I'd do differently. The stack is deliberately boring Hand-rolled PHP. No framework, no build step, no node_modules. About 4,800 files, server-rendered, no hydration. That sounds like a confession, but it was the right call for one reason: my readers are on phones, on cafe Wi-Fi, often on 3G. A server-rendered page that ships HTML and a little CSS beats anything I could have built with a client-side framework in that environment. Time-to-content is the only metric that matters when someone is standing on the beach deciding whether to paddle out. The hosting is a cheap shared plan. The forecast data is free and open. The whole thing runs at EUR 0/month recurring , which was a hard constraint from day one. The interesting part: two ocean models that disagree The forecast blends two sources: Open-Meteo (CC BY 4.0) - the primary, with a marine endpoint that covers our coastal cells. NOAA WaveWatch III via PacIOOS - the second opinion. Here's the thing nobody tells you: they disagree, a lot. On the same hour at the same break I've seen WaveWatch read ~55% higher than Open-Meteo (1.36m vs 0.88m). Offshore models resolve coastal bathymetry badly, and our points are exactly the kind of close-in, shallow-reef setups where that bias shows up. The wrong fix is to pick one and pretend. What I did instead: Run both, cache both. Compute agreement over a 72-hour window - a Pearson correlation on the swell rhythm plus a circular difference on direction (you can'
AI 资讯
Build a POS receipt printer in Node.js
Disclosure: I build Receiptful, the printing API used in this tutorial. The Node and Express parts apply whatever you print with. You have orders coming into your point of sale, and you want each one to print on the thermal printer at the counter. This is a complete walkthrough of a small Node service that does exactly that. By the end you will have an endpoint you can POST an order to and watch paper come out. There is nothing to install next to the printer for this tutorial to work, and no ESC/POS to write by hand. You send HTML, Receiptful prints it. Before you start You need two things from the console : A paired printer, which gives you a printer ID . If you have not done this yet, the getting started guide walks through it in a couple of minutes. An API key (the rf_live_… value), created under API keys and shown only once. On the code side you need Node 18 or newer, so that fetch is available globally with no extra dependency. We will use TypeScript, but the same code works in plain JavaScript if you drop the types. Put your credentials in the environment rather than in the source: export RECEIPTFUL_API_KEY = "rf_live_3f9c…" export RECEIPTFUL_PRINTER_ID = "42" Step 1: model the order Start with the shape of an order. Yours will have more fields, but this is enough to print a useful receipt: interface LineItem { name : string ; quantity : number ; unitPrice : number ; // in cents, to avoid float rounding } interface Order { id : number ; items : LineItem []; placedAt : Date ; } Keeping money in cents and formatting only at the edges saves you from the classic floating point rounding bugs that show up as a receipt total that is one cent off. Step 2: render the order as HTML This is the part that decides how the receipt looks. Receiptful converts the HTML you send into ESC/POS for your specific printer, so you get to lay a receipt out with tags you already know instead of byte codes. function money ( cents : number ): string { return " $ " + ( cents / 100 ). toFi
AI 资讯
Everything You Need for API Automation (A Complete Blueprint)
Setting up an API automation framework requires aligning business goals, developer specifications, infrastructure, and core testing strategies. Here is a comprehensive requirement checklist and workflow to ensure complete coverage across every stage of your API automation setup. 1. Requirements from Client / Business Owner Before writing code, define what needs to be tested: Business requirements (BRD) & user stories / use cases Expected API behavior & acceptance criteria (success & failure cases) Priority APIs (critical vs optional pathing) Performance expectations (SLA, response time) API versioning policy (backward compatibility expectations) Security & compliance requirements (data privacy, PII handling) 2. Technical Details from Developers Understand how the APIs operate: API Documentation: Swagger / OpenAPI specifications Endpoints: Base URL + specific paths HTTP Methods: GET, POST, PUT, DELETE, PATCH Request Details: Headers, query params, request body (JSON/XML) Response Details: Expected status codes (200, 201, 400, 401, 403, 404, 500) and response schema structures Authentication: OAuth, JWT, API keys, or Basic Auth Error Handling: Error codes & error messages API Contracts: Consumer-driven contract definitions (e.g., using Pact) Rate Limits & Throttling: Maximum request limits and wait strategies Downstream Dependencies: Dependent APIs required for mock/stub planning 3. Infrastructure & Environment Setup Coordinate with the Application Owner or Infra Team for execution requirements: Environment URLs: Dev, QA, UAT, and Prod environments Access Control: VPN access, API gateway setups, credentials Test Data Strategy: Valid, invalid, edge case, and boundary value datasets Data seeding scripts for pre-test setup Data teardown/cleanup scripts for post-test cleanup Data isolation per environment Database Access: Direct access for validating API output directly against DB records Mocking/Stubbing: Availability of tools like WireMock or MSW for dependent APIs Secr
AI 资讯
My evidence pipeline was saving Cloudflare block pages as evidence
I build a web service that preserves evidence of harassment on social platforms. The core feature is a single thing: automatically capture a real screenshot of the offending post. There was no substitute for it. I built an alternative that pulled the text through an API and rendered a tidy "evidence card" image, and threw it away. An image you can author freely afterwards proves nothing. Here's the conclusion first. Third-party wrappers eventually die, and when they do, the failure comes back as a plausible-looking image rather than an error. The first approach was refused by the other side I started with Cloudflare Browser Rendering. The wiring worked. The capture didn't. X blocks headless browsers. The request times out YouTube refuses script injection under a Trusted Types CSP. There's no way to make it render the comment Neither is a bug in my implementation — that is how they are built. So I declared Cloudflare alone impossible for this and moved to a service with a real browser and bot avoidance behind it. Both captures started working. For X, open the post page and clip the tweet element. For YouTube, open the URL with &lc= and screenshot just that comment element. Element screenshots have one trap worth knowing: selector_algorithm=clip returns a blank image when the element sits below the fold. The selector matches, the capture "succeeds," and the file is empty. That took a while to see. ytd-comment-thread-renderer :has ( a [ href *= "lc=ID" ]) A parameter that had worked started returning 400 I wanted timestamps rendered in Japan time, so I passed time_zone: Asia/Tokyo . One day every request started coming back 400. Every capture failed. The provider had narrowed which timezones they accept. Nothing changed on my side. I could diagnose it immediately only because I was storing the raw error body in the database. The response went into rawPayload.screenshotError , so opening one row told me why. Without that, this starts as "captures stopped working, no ide