今日已更新 88 条资讯 | 累计 40862 条内容
关于我们

标签:#API

找到 563 篇相关文章

AI 资讯

Why I Put Mirth Connect in Front of FastAPI Instead of Parsing HL7 in Python

When I started building my Maternity HL7-to-FHIR Pipeline , my first instinct was to do everything in Python. Parse the HL7 message, map the fields, validate the FHIR resource, persist it, all in one FastAPI service. It was clean. It was simple. It was wrong. The "Just Parse It in Python" Phase My initial architecture looked like this: Hospital System --MLLP--> Python Script --> HAPI FHIR Server I used python-hl7 to split messages on | and count field positions. For a single ADT^A01 (patient admission) message, it worked fine. I could pull the patient name from PID-5 , the MRN from PID-3 , the gender from PID-8 , and build a FHIR Patient resource from it. Then I tried a real-ish maternity workflow (an admission, an order, and a set of vitals) and things fell apart quickly. Five Problems That Changed My Mind 1. MLLP Is Not HTTP Hospital systems don't send HL7 over HTTP. They send it over MLLP (Minimum Lower Layer Protocol), which is a TCP socket protocol with specific framing bytes ( \x0b at the start, \x1c\x0d at the end). The sender expects an ACK or NACK response in HL7 format, not an HTTP status code. Building an MLLP listener in Python is possible . Libraries like aioml7 exist. But you're now maintaining a custom TCP server alongside your HTTP API server, handling connection pooling, timeouts, and HL7 acknowledgment generation. That's a lot of infrastructure code that has nothing to do with your actual transformation logic. Mirth Connect handles MLLP natively. You point it at a port, it listens, it parses, it ACKs. Done. One config screen, no custom code. 2. HL7 Parsing Is Messier Than It Looks The pipe-delimited format looks simple: PID|1||1234567^^^MRN||TEST^PATIENT^MARY^^MS||19920315|F|||14 SAMPLE ST^^SYDNEY^NSW^2000^AU But consider: Component separators : PID-5 is TEST^PATIENT^MARY^^MS , which is family, given, middle, suffix (empty), prefix. Miss the empty suffix and your prefix ends up as the suffix. Repeating fields : PID-3 can contain multiple identifier

2026-07-26 原文 →
AI 资讯

Claude Opus 5 leads on agentic work — and undercuts Fable 5 on cost

Claude Opus 5 is out, and Artificial Analysis — who supported Anthropic's pre-release evaluation — just dropped their full benchmark breakdown. The headline: new top model for agentic knowledge work, and cheaper per task than Fable 5. That combination doesn't come along often at the frontier. "Opus 5 (max) scores 61 on the Artificial Analysis Intelligence Index, effectively tied with Claude Fable 5 (max, 60), and ahead of GPT-5.6 Sol (max, 59)" What actually changed New agentic leader: 1861 Elo on GDPval-AA v2 — more than 100 points ahead of both Fable 5 and GPT-5.6 Sol. On AA-Briefcase (agentic knowledge work), it's +146 Elo over Fable 5. Joint first on coding: Opus 5 (xhigh) with Claude Code tops the Artificial Analysis Coding Index, including the highest score on SWE-Atlas-QnA. 89% on Terminal-Bench v2.1: Roughly in line with the current terminal leader, GPT-5.6 Sol. Cost per task: $2.03 at max effort — vs Fable 5's $2.75. That's 26% less for equivalent or better intelligence on agentic benchmarks. 1M token context window (same as Opus 4.8), 5 effort settings (low → max), and server-side fallback support. Pricing: $5/$25 per million input/output tokens — same rate as previous Opus launches. The cost-intelligence shift For agentic workloads — the things most teams are actually building on right now — Opus 5 doesn't just match Fable 5. It beats it, and charges less to do it. Fable 5 was the "throw more at it" option. Opus 5 reframes the trade-off: better agentic outcomes and a lower bill. At mid-tier effort settings (high, xhigh), it can outperform both Opus 4.8 and Sonnet 5 on a cost-per-task basis. That's a lot of headroom to play with before you're even at max effort. The caveat worth flagging: factual knowledge still lags. Opus 5 improved +7 points on AA-Omniscience over Opus 4.8, but its hallucination rate climbed 14 points to 50% — it guesses more confidently when uncertain. For retrieval-heavy or factual precision tasks, Fable 5 still holds the edge. What to

2026-07-26 原文 →
AI 资讯

Every EnvCastError Tells You How to Fix It: Designing Error Messages as a Feature

int(os.environ.get("PORT", "8080")) fails constantly in ways that waste your time: ValueError: invalid literal for int() with base 10: 'abc' . No variable name. No hint about what a valid value looks like. You grep the codebase for PORT to even find where the read happened. specenv is a zero-runtime-dependency Python library for typed environment variable loading — casting, validation, schema grouping, prefix namespacing. All of that is useful, but none of it is the actual design decision worth writing about. The decision that shaped everything else was: every error must name the variable and say how to fix it, unconditionally, with no opt-out. Decision 1: The error message is generated at the failure site, not templated afterward It would be easy to build one generic EnvCastError(var_name, raw_value, target_type) and format a message from those three fields in __str__ . specenv doesn't do that — each cast failure builds its own message inline, at the point where the specific failure is known: if cast_type is int : try : return int ( raw ) except ValueError : raise EnvCastError ( f ' Cannot cast { name } = { raw !r} to int. \n ' f ' → Set { name } to a valid integer (e.g. { name } =8080) ' ) from None if cast_type is bool : ... raise EnvCastError ( f ' Cannot cast { name } = { raw !r} to bool. \n ' f ' → Set { name } to one of: 1/0, true/false, yes/no, on/off ' ) The generic version would produce "Cannot cast PORT='abc' to int" and stop there. The inline version gets to add (e.g. PORT=8080) for ints, 1/0, true/false, yes/no, on/off for bools, a namespaced hint for prefixed variables — because at the point of failure, you know exactly what a correct value looks like for that type, and a generic formatter three calls up the stack doesn't. The cost is a few lines of duplication across _caster.py 's type branches. That's a fair trade for every single error message being genuinely actionable instead of generically accurate. Decision 2: Missing-and-required collapses to t

2026-07-25 原文 →
AI 资讯

Swagger docs from your existing TypeScript types — no framework required

The problem Recently I was looking for an npm package to generate OpenAPI (Swagger) documentation for my existing TypeScript project. My biggest requirement was TypeScript type-to-schema conversion: I already have all my request and response types, so why should I maintain the same schemas again in OpenAPI? Zod support would be a nice bonus. After trying most of the existing solutions, I found they generally fall into two categories: 1. Runtime frameworks The most popular example is tsoa . Honestly, tsoa is one of the best OpenAPI generators available today: it understands TypeScript well, generates schemas automatically and detects status codes. There are also contract-first libraries like ts-rest , Zodios and express-zod-api . However, none of these solutions are agnostic when it comes to how you write your code — they all dictate the shape of your routes. 2. Manual generators The best-known example is swagger-jsdoc. You write raw OpenAPI next to your code in JSDoc comments: /** * @openapi * /users: * post: * ... */ swagger-jsdoc is simple and framework-agnostic, but it's too verbose and knows nothing about your types. Then I found a similar tool that solved the verbosity problem: @visulima/jsdoc-open-api . It parses much more readable JSDoc tags: /** * POST /users * @summary Creates a new user. * @tags Users * @bodyContent {User} application/json - User object to create. * @bodyRequired * @response 201 - User created successfully. * @responseContent {User} 201.application/json - The created user object. */ But it still doesn't care about your types. User here is just the name of a component you have to define elsewhere in your document. Why not parse the actual types at generation time? That question inspired me to create Autoswag . The solution - Autoswag Describe your routes with readable JSDoc, and let the generator convert your TS types along the way. It doesn't affect your runtime code in any way, works with any framework, and even with vanilla JS. This is w

2026-07-25 原文 →
AI 资讯

Has an API ever silently changed its response shape and broken your app before you noticed?

I keep running into (and hearing about) a specific kind of bug that never throws an error — an API you depend on quietly changes its response shape. A field disappears. A number becomes a string. Something that was always present is suddenly null. Nothing crashes immediately. It just produces wrong or missing data somewhere downstream, and you find out from a bug report, not a log. I'm curious how common this actually is outside my own experience, so — genuine question, not a pitch: Has this happened to you, with a third-party API or even an internal one your own team owns? How did you find out it happened — a user report, a stack trace somewhere unrelated, manual debugging? Do you currently do anything to catch this kind of thing before it bites you (contract tests, monitoring, or just... hoping)? If you don't do anything about it today, is that because it's not painful enough to bother, or because you just haven't found a lightweight way to? Not selling anything here, just trying to understand how real and how painful this actually is for people building on top of APIs day to day. Would genuinely appreciate hearing your experience, even a one-line "yeah this happened to me once, wasn't a big deal" is useful data.

2026-07-25 原文 →
AI 资讯

Your OpenAPI spec is already a test plan — here's how to turn it into Playwright tests automatically

If you're writing Playwright API tests manually from an OpenAPI/Swagger spec, you're doing work that should be automated. Every endpoint in your spec already tells you: What the request looks like (path, method, parameters, body schema) What responses to expect (200, 401, 404, 422...) What fields are required What security is needed That's not documentation — it's a test plan. You're just not running it yet. What I built I got tired of the boilerplate loop: read spec → write happy path → add 401 test → add missing-field test → repeat for 40 endpoints. So I built a tool that does it for you. swagger-to-playwright.vercel.app takes your OpenAPI 3.x spec (YAML or JSON) and generates a ready-to-run Playwright .spec.ts file. For each endpoint, it produces four tests: 1. Happy path — calls the endpoint with valid data, asserts 2xx response and key fields in the body. 2. Auth check — if your spec declares a security scheme, it calls without a token and asserts 401. Only generated when the spec actually says authentication is required — no false positives. 3. Input validation — sends a request with missing required fields (or wrong types, invalid enums) and asserts 422. Reads directly from your schema's required array and field types. 4. Contract validation — if there's a path parameter, it calls with an invalid value and asserts 404. What the output looks like Here's what you get for a POST /users endpoint with email and password required: import { test , expect } from ' @playwright/test ' ; test . describe ( ' POST /users ' , () => { test ( ' happy path — creates user successfully ' , async ({ request }) => { const res = await request . post ( ' /users ' , { data : { email : ' test@example.com ' , password : ' password123 ' } }); expect ( res . status ()). toBe ( 201 ); const body = await res . json (); expect ( body ). toHaveProperty ( ' id ' ); }); test ( ' auth — 401 without token ' , async ({ request }) => { const res = await request . post ( ' /users ' , { headers : {

2026-07-25 原文 →
AI 资讯

Teaching My Backend to Lock the Door — FastAPI Auth, Phase 3

Hash the password, hand out a token, and make absolutely sure no one can read someone else's expenses. So Phase 2 gave my app a mouth. It could finally talk — create, read, update, and delete expenses over real HTTP endpoints, all clicking together through /docs . But there was a giant, deliberately-ignored problem sitting in the middle of it: the door had no lock. Anyone who could reach the server could read, edit, or delete anything. And every expense I created was quietly stamped with the same hardcoded owner — a "dev user" whose id I'd nailed into the code with a # TEMP note and a promise to fix it "in Phase 3." Well. It's Phase 3. Time to pay that debt. This is where the app grows a bouncer. The buzzword is auth , which actually hides two jobs that sound the same and aren't: authentication ["who are you?"] and authorization ["okay, but are you allowed to touch this ?"]. I went in thinking auth was "add a login form" and came out having learned about one-way hashing, signed tokens, a security bug with the excellent name IDOR , and why the same password can produce two different hashes. Let me dump what I learned [and the parts that tripped me up, because — as usual — there were several]. Auth is the one phase where you have to stop thinking like a builder and start thinking like the person trying to rob you. So every step below is really "here's a way an attacker wins, and here's the gap I closed to stop them." The structure. Let's call it PHASE 3 — The Lock: Give the User table somewhere to store a password [a hashed one, never the real thing] Password hashing helpers — turn a password into something safe to store POST /auth/register — sign up with a hashed password Understand what a JWT actually is [it's just a signed string, and it's readable] POST /auth/login — check the password, hand back a token get_current_user — the gatekeeper that turns a token back into a user Lock every expense endpoint and scope it to the logged-in owner Retire the hardcoded DEV_USE

2026-07-25 原文 →
AI 资讯

I Built an API That Writes Code Documentation in 13 Languages — Here's How

I’ve always disliked writing documentation. Not because it’s hard, but because it’s repetitive. You write a function, you describe what it does, you give an example, and then you realize you need the same thing in another language because half your users don’t speak English. So I decided to automate it. The result is an API that takes source code as input and returns a clean Markdown README, API reference, or inline comments — in any of 13 languages. No templates, no manual translation. curl -X POST "https://ai-code-documentation-generator.p.rapidapi.com/demo" \ -H "x-rapidapi-host: ai-code-documentation-generator.p.rapidapi.com" \ -H "x-rapidapi-key: YOUR_KEY" \ -H "Content-Type: application/json" \ -d '{"code":"def add(a,b): return a+b","code_language":"python","doc_language":"en"}' { "success" : true , "documentation" : "# Add Utility \n\n ## Overview \n A simple function to add two numbers..." , "quality_score" : 9 , "target_language" : "en" } It auto-detects the programming language (Python, JavaScript, Go, Rust…) and spits out a polished doc. The English output is solid, but seeing it generate accurate Japanese or German READMEs from the same code still feels like magic. The Tech Behind It Backend: Python + FastAPI, hosted on Northflank. AI Model: DeepSeek (via API). The model actually understands code structure, so generated docs aren’t just generic wrappers. Language Detection: Pygments for syntax highlighting + language guessing. Caching: 24-hour cache to avoid redundant calls and save cost. Security: Sensitive strings (API keys, passwords) are automatically redacted from the output. The whole thing is open source: https://github.com/zhaochangbo888/docgen-api Why I Didn’t Just Use ChatGPT You could absolutely paste your code into ChatGPT and ask for docs. But integrating an LLM directly into a CI/CD pipeline, or a VS Code extension, or a platform that needs programmatic access gets messy with rate limits, authentication, and output consistency. This API giv

2026-07-25 原文 →
AI 资讯

بارامتر الجهد لكلود أوبوس 5: مقايضة التكلفة مقابل القدرة

كل مقال رئيسي عن إطلاق Claude Opus 5 في 24 يوليو 2026 ذكر الميزة نفسها: التبديل بين التكلفة والقدرة. لكن معظم التغطية لم تشرح ما هي المستويات، أو ما الذي يتغير عند تبديلها، أو أثرها على الفاتورة. جرّب Apidog اليوم الميزة هي معلمة طلب باسم effort تضم خمسة مستويات في Opus 5، وقيمتها الافتراضية هي high . أعادت Anthropic معايرة هذه المستويات لهذا النموذج، لذلك لا تنقل إعدادات Opus 4.8 كما هي. كذلك، تؤدي مجموعة محددة من الإعدادات إلى خطأ 400 شائع أثناء الترحيل. 💡 إذا أردت اختبار المستويات مقابل نقطة نهاية حقيقية، استخدم Apidog لإرسال الطلب نفسه بخمسة إعدادات مختلفة ومقارنة النتائج. ما هي معلمة الجهد ( effort )؟ توجد effort داخل كائن output_config في طلب Messages API: { "model" : "claude-opus-5" , "max_tokens" : 8192 , "output_config" : { "effort" : "high" }, "messages" : [ { "role" : "user" , "content" : "Refactor this module and explain the tradeoffs." } ] } تتحكم المعلمة في مقدار التفكير الداخلي الذي يجريه النموذج قبل إنشاء الإجابة. يعمل Opus 5 بالتفكير التكيفي افتراضيًا، وتحدد effort حجم ميزانية التفكير: جهد أعلى: رموز تفكير أكثر، تكلفة أعلى، وزمن استجابة أطول. جهد أقل: رموز تفكير أقل، تكلفة أقل، وزمن استجابة أقصر. تعرض واجهات المستخدم هذه الفكرة كمحدد للجهد، لكن عند استخدام API فإن output_config.effort هي القيمة التي تتحكم بها فعليًا. راجع دليل واجهة برمجة تطبيقات Opus 5 للحصول على شكل الطلب الكامل، وراجع نظرة Anthropic العامة على النماذج للمرجع الرسمي للمعلمات. ما الذي لا تتحكم به effort ؟ لا تتحكم effort في إسهاب الإجابة أو طول النص المرئي. وفق دليل توجيه Anthropic لـ Opus 5 ، خفض الجهد يقلل التفكير الداخلي، وليس طول الإجابة. إذا أردت استجابة أقصر، اطلب ذلك صراحةً في التوجيه: أجب في خمس نقاط فقط، ولا تضف مقدمة أو شرحًا إضافيًا. لن يؤدي ضبط effort على low وحده إلى تقصير الإجابة. المستويات الخمسة المستوى ماذا يفعل الاستخدام النموذجي low أدنى مقدار من التفكير قبل الإجابة التصنيف واسع النطاق، الاستخراج، التوجيه، الملخصات القصيرة medium تفكير معتدل أسئلة وأجوبة مع سياق مسترجع، تعديلات ملف واحد، تحويلات منظمة high القيمة الافتراضية. تفكير كبير مهام عامة عندما لم تجرِ قيا

2026-07-25 原文 →
AI 资讯

Parâmetro de Esforço do Claude Opus 5: Trocando Custo por Capacidade

Todo artigo principal sobre o lançamento do Claude Opus 5 em 24 de julho de 2026 destacou a mesma funcionalidade: uma forma de alternar entre custo e capacidade. Mas poucos explicaram o que ela controla, quais níveis existem, como afeta a requisição ou o impacto na conta. Experimente o Apidog hoje Essa funcionalidade é o parâmetro effort . No Opus 5, ele tem cinco níveis e o padrão é high . A Anthropic recalibrou esses níveis para o modelo, então configurações ajustadas no Opus 4.8 não devem ser reutilizadas sem avaliação. Além disso, uma combinação específica de parâmetros gera erro 400 durante migrações. 💡 Para comparar os cinco níveis contra um endpoint real, envie a mesma requisição com valores diferentes de effort e registre custo, latência e qualidade da resposta. O que o parâmetro effort realmente faz O effort fica dentro de output_config em uma requisição para a API de Mensagens: { "model" : "claude-opus-5" , "max_tokens" : 8192 , "output_config" : { "effort" : "high" }, "messages" : [ { "role" : "user" , "content" : "Refatorar este módulo e explicar os trade-offs." } ] } Ele controla quanto raciocínio interno o modelo executa antes de responder. No Opus 5, o pensamento adaptativo está ativado por padrão. O valor de effort define o orçamento usado nesse raciocínio: effort mais alto: mais tokens de raciocínio, maior custo e maior latência. effort mais baixo: menos tokens de raciocínio, menor custo e menor latência. Nas interfaces de consumidor, a mesma opção pode aparecer como um seletor entre custo e capacidade. Na API, o controle efetivo é o campo output_config.effort . Consulte o formato completo da requisição no guia da API do Opus 5 e a documentação da Anthropic na visão geral de modelos . effort não controla verbosidade effort não é um controle de tamanho da resposta. Segundo o guia de prompting da Anthropic para o Opus 5 , reduzir o effort diminui o raciocínio interno, não o comprimento do texto visível. Se você precisa de respostas curtas, inclua essa

2026-07-25 原文 →
开发者

Rotating Residential Proxies in Python: requests, Scrapy & Sticky Sessions

When you scrape at any real volume, the bottleneck is rarely your code — it's the target site's rate limiting and IP bans. Rotating residential proxies solve this by routing each request through a different real-user IP. Here's how to wire them into requests and Scrapy in Python, including the sticky-session trick most tutorials skip. The proxy URL format A residential proxy is just an authenticated HTTP/SOCKS endpoint. With a pool gateway, you target a country and control session behavior through the username , not separate endpoints: http://USERNAME_country-us_session-a1b2c3_lifetime-30:PASSWORD@proxy.gproxy.net:1000 country-us — exit country (ISO code) session-a1b2c3 — a sticky-session id; reuse it to keep the same IP , change it to rotate lifetime-30 — how many minutes that session's IP stays fixed Basic request through a rotating proxy import requests USER = " USERNAME " PWD = " PASSWORD " def proxy ( country = " us " , session = None , lifetime = 30 ): tag = f " _country- { country } " if session : tag += f " _session- { session } _lifetime- { lifetime } " url = f " http:// { USER }{ tag } : { PWD } @proxy.gproxy.net:1000 " return { " http " : url , " https " : url } # New IP on every call (no session id): r = requests . get ( " https://api.ipify.org?format=json " , proxies = proxy (), timeout = 30 ) print ( r . json ()[ " ip " ]) Run it in a loop and you'll see a different IP each time — the gateway rotates automatically when no session id is present. Sticky sessions: keep one IP across requests Some flows (login, multi-step checkouts, paginated results behind a cookie) break if your IP changes mid-session. Pin the IP by passing a stable session id: import uuid sess = uuid . uuid4 (). hex [: 8 ] # one id for the whole flow p = proxy ( country = " de " , session = sess , lifetime = 30 ) s = requests . Session () s . proxies . update ( p ) s . get ( " https://example.com/login " ) s . post ( " https://example.com/login " , data = {...}) # same exit IP When you

2026-07-25 原文 →
AI 资讯

We Spent Months Cleaning SEC EDGAR 13F Data So You Don't Have To

The data isn't the hard part. Cleaning it is. SEC EDGAR is public, free, and a mess. Every quarter, 13,000+ institutional investment managers file Form 13F, disclosing their U.S. equity holdings. In theory that's a beautiful dataset — every hedge fund, every pension fund, every bank, all in one place. In practice, the raw filings actively fight you: The same institution files under different names, sometimes even in the same quarter. In our own database right now: BlackRock, Inc. and BlackRock Inc. are two distinct CIK registrations for what most people would call "one" institution. Multiply that across 13,000+ filers and you get a long tail of near-duplicate names that break any naive GROUP BY institution_name . CUSIPs don't map cleanly to tickers. Foreign issuers frequently use CUSIP prefixes that don't resolve through the usual reference data — we ended up building a fallback resolution path (Yahoo Finance lookups plus manual validation rules) just to keep ticker coverage from silently degrading over time. Quarters arrive gradually, not all at once. The SEC gives managers up to 45 days after quarter-end to file. If you naively take "the latest quarter with any data" as your reporting period, you'll rank a barely-started quarter — where only a handful of small filers have reported so far — ahead of the real, complete prior quarter. We learned this the hard way: an unclamped "most recent quarter" query once let 115 newly-onboarded institutions' entire existing portfolios get counted as "new inflow" with nothing to offset them, because a first-time filer has no prior-quarter row to diff against. That's the kind of bug that doesn't throw an error — it just quietly produces a chart that looks plausible and is wrong. Amendments (13F-A) revise, replace, or partially restate earlier filings , and the XML schema itself has shifted over the years, so parsing "just the latest 13F" isn't a fixed target. None of this is exotic — it's the normal cost of working with real-world

2026-07-24 原文 →
AI 资讯

The x-tenant-id Pattern: Multi-Tenant API Without Multi-Tenant Complexity

When you're building a multi-tenant SaaS, the first architectural question is usually: how do you keep tenant data isolated? The options range from separate databases per tenant (maximum isolation, maximum cost) to a shared database with row-level filtering (minimum cost, more careful coding required). But there's an equally important question that gets less attention: how does your API know which tenant context a request belongs to? This post covers a pattern we've used in production: a custom request header for tenant scoping, combined with JWT authentication. Simple to implement, easy to audit, and flexible enough to support multi-tenant access from a single user account. The Three Common Approaches 1. Subdomain-based ( tenant.yourdomain.com ) The tenant is encoded in the hostname. Each subdomain routes to the same backend, which extracts the tenant from the Host header. Good: Intuitive, visible in the URL. Bad: Requires wildcard TLS certs, more complex DNS setup, awkward in development, doesn't work for mobile API clients the same way. 2. URL path-based ( /api/tenants/{tenantId}/... ) The tenant identifier is part of every route path. Good: RESTful, self-documenting. Bad: Bloats all route definitions, requires every endpoint to include the tenant segment, makes API versioning messier. 3. Header-based ( x-tenant-id: <id> ) A custom header carries the tenant context. Routes stay clean. The tenant scope is resolved in middleware before the handler runs. Good: Routes stay simple, middleware handles scoping uniformly, works well with JWT auth, easy to test. Bad: Less visible (the tenant isn't in the URL), requires clients to always include the header. We use the header approach. The Implementation The API accepts two forms of auth: A JWT token in the Authorization header — identifies who is making the request A tenant ID in the x-tenant-id header — identifies on behalf of which tenant POST /api/v1/members Authorization: Bearer eyJhbGciOiJIUzI1NiIs... x-tenant-id: ten

2026-07-24 原文 →
AI 资讯

I keep finding out about API breaking changes from production errors, so I'm building a changelog watcher

I build products solo. Every single one of them sits on top of somebody else's API — Stripe for payments, OpenAI and Anthropic for AI features, Meta for ads, print-on-demand APIs, map APIs. My code is maybe half of what actually runs in production. The other half belongs to vendors, and it changes whenever they decide it changes. Twice this year the first notice I got about a breaking change was a production error. Not an email, not a warning. An error, and then me digging through the vendor's changelog trying to figure out what they changed and when. The information was public the whole time. It was sitting in a changelog page I never visit, because nobody visits changelog pages until something is on fire. So I'm building the thing I wanted to exist BreakWatch is simple: you tell it which APIs your product depends on, and it reads their public changelogs for you. It fetches each changelog page once a day Diffs it against yesterday's snapshot Classifies the real changes: breaking (endpoint removed, field deprecated, "migrate by September") vs. informational (new feature, docs clarification — stuff you can ignore) Alerts you only when something looks like it will break an existing integration Keeps everything in a searchable timeline, so six months later "what changed on their side right before this broke" takes ten seconds instead of an afternoon No SDK, no credentials, nothing installed in your codebase. It only reads public pages. What I tested this week I ran it against the real changelogs of the ten APIs I'm watching first: Stripe, Twilio, OpenAI, Anthropic, Shopify, GitHub, Slack, Cloudflare, Google Maps and Plaid. Some honest findings: 10/10 scrape cleanly now, but it took fixes. Stripe's changelog page alone is 3.3 MB. SendGrid's standalone changelog doesn't exist anymore (it merged into Twilio's). PayPal's developer site serves a JavaScript shell with an HTTP 404 to anything that isn't a full browser, so it's out until I add rendering. The thing I was most a

2026-07-24 原文 →
AI 资讯

Two credentials, two threat models: auth for a content API

A headless content API has two kinds of callers, and it's tempting to secure them the same way. That's the mistake. There's a human logging into an admin UI to edit content, and there's a machine — a website, a build step — pulling published content through a delivery endpoint. They authenticate with different credentials, and those credentials have opposite properties. Treat them identically and you either make the machine path painfully slow or the human path dangerously weak. I built a small headless content API ( Depot ) partly to get this boundary right. Here's the reasoning. The two credentials A session proves "this human is logged in." Short-lived, rides in an httpOnly cookie, checked on management routes. A delivery token proves "this machine may read this account's published content." Long-lived, sent as a Bearer header, checked on every public read. Two auth surfaces, kept explicit: /** * - requireUser() — admin session (httpOnly JWT cookie) for the management API. * - requireToken() — a `depot_…` bearer token for the public delivery API. */ Why they get different hashing Here's the part people get wrong. Both credentials get stored as hashes — never plaintext — but not the same kind of hash , and the reason is entropy. Passwords are low-entropy. Humans pick summer2024 . An attacker who steals your DB will brute-force guesses against the stored hashes, so you want hashing to be deliberately slow — that's exactly what bcrypt's cost factor buys you: import bcrypt from " bcryptjs " ; const ROUNDS = 10 ; // deliberately slow — the point is to resist brute force export function hashPassword ( plain : string ): Promise < string > { return bcrypt . hash ( plain , ROUNDS ); } export function verifyPassword ( plain : string , hash : string ): Promise < boolean > { return bcrypt . compare ( plain , hash ); } Tokens are high-entropy. I generate them — 32 random bytes — so there's nothing to guess. A stolen hash can't be reversed by brute force because the keyspace i

2026-07-24 原文 →
AI 资讯

How AI Endpoints Change the Traditional API Flow

As a backend developer, I have build hundreds of endpoints, so the typical endpoint flow is deeply ingrained in how I think about web applications. But when I started building AI-powered endpoints, I noticed an interesting shift. At first, AI endpoints looked like simple proxy endpoints with some configuration for connecting to a model: API receives request ↓ send prompt to model ↓ receive response ↓ return it to the client And it worked well until I found out that passing a prompt directly from the client was not a good idea. The endpoint could be misused for a completely different purpose, allowing someone else to consume my AI usage credits. Then I realized that the input also needed limits. Sending a large context for a specific task costs more and may produce unexpected results. So when I started looking closer, especially when I needed reliable structured output and predictable application behavior, I quickly realized that it was not that simple. Validation was no longer only guarding execution, it had also become a post-processing step. AI models are probabilistic. Even with the same input, they may return different outputs, omit required information, misunderstand instructions or return something that is technically valid but logically wrong. And because every token has a price, I cannot simply retry the request and hope for a better result. That was when I started questioning whether AI endpoints should be designed in the same way as conventional Web API endpoints. Table of Contents Conventional Web API Endpoint Flow AI-powered Web API Endpoint Flow What This Difference Changes Unpredictable Latency Retry Logic Idempotency and Side Effects Testing AI Endpoints The Output Contract Observability and Cost Summary Conventional Web API Endpoint Flow A conventional Web API endpoint usually follows a similar flow: validate request ↓ execute business logic ↓ return representation The first phase is request validation. We validate the incoming data against property

2026-07-23 原文 →
AI 资讯

A IA Substitui Testes de API? O Que Agentes de IA Podem e Não Podem Fazer

Seu agente escreveu o teste. O Cursor sugeriu três casos extremos que você não havia pensado. O Copilot preencheu o corpo da requisição, e o Claude executou tudo uma vez e reportou “verde”. A pergunta é justa: se o agente faz tudo isso, a IA pode substituir completamente o teste de API? Experimente o Apidog hoje Não. A IA não substitui o teste de API, mas já substitui boa parte da autoria dos testes. Agentes elaboram casos, sugerem cenários extremos e geram payloads com eficiência. Porém, eles não garantem execução idêntica em cada commit, não bloqueiam merges com um resultado confiável e não decidem se um contrato está correto. Para isso, você precisa de uma ferramenta determinística e de revisão humana. Essa separação responde a uma dúvida maior: você ainda precisa de uma ferramenta de API na era dos agentes de IA ? Sim — mas o papel da ferramenta mudou. Use agentes para acelerar a autoria e ferramentas determinísticas para validar, executar e bloquear regressões. Onde este artigo difere do guia prático Se você procura instruções para gerar testes com agentes, consulte o guia sobre como usar agentes de IA para teste de API . Este artigo trata de outra pergunta: quais partes do fluxo você pode delegar a um agente e quais precisam continuar em uma suíte determinística? Uma implementação prática separa o trabalho assim: O agente lê a especificação e cria um rascunho de testes. Um desenvolvedor revisa cenários, asserções e regras de negócio. Um runner headless executa a suíte no CI. O pipeline bloqueia o merge usando o código de saída do runner. Quando algo falha, você inspeciona a requisição e a resposta reais. O que a IA faz bem em testes de API hoje Agentes removem trabalho repetitivo de autoria. Use-os principalmente para criar e expandir artefatos de teste. Elaborar uma primeira suíte a partir de uma especificação Entregue ao agente um endpoint, uma definição OpenAPI ou uma resposta de exemplo. Ele pode gerar rapidamente: verificações de status HTTP; asserções de

2026-07-23 原文 →
AI 资讯

Build a Crypto Payment Support Desk

Most developers think about crypto payments as a checkout problem. Generate an invoice. Show a payment page. Wait for a webhook. Mark the order as paid. That is the clean version. Real merchants do not live in the clean version. They live in support tickets. A customer says they paid, but the order is still pending. A payment arrives after the invoice expires. Someone sends the right amount on the wrong network. A webhook fails. A customer underpays. A support agent cannot tell whether the issue is customer error, blockchain delay, invoice expiry, fulfillment failure, or an internal system bug. This is where developers can build a real product. A Crypto Payment Support Desk is a support and operations layer for merchants that accept crypto payments. It helps support teams search payments, inspect payment timelines, classify issues, explain statuses to customers, escalate real problems, and reduce the amount of manual investigation required for every crypto payment ticket. In this article, I will use OxaPay as the example payment infrastructure because its documentation exposes the primitives needed to build this kind of product: invoice generation, payment status callbacks, HMAC-signed webhooks, payment information lookup, payment history, static addresses, SDKs, plugins, and automation integrations. This is not a generic “add crypto payments to your app” article. It is a blueprint for developers who want to build a support-facing product that merchants may actually pay for. The business idea The idea is simple: Build a support desk that sits between a merchant's payment system, order system, and support team. The merchant already accepts crypto payments. The problem is that their support team cannot quickly answer payment-related questions. Your product gives them one place to investigate cases like: “The customer says they paid, but the order is unpaid.” “The invoice expired, but a transaction later appeared.” “The payment is underpaid.” “The webhook was received,

2026-07-23 原文 →
AI 资讯

Inertia and API responses living together in harmony

I love InertiaJS to the point where it's becoming a personality trait I tend to want to use it for everything, but adding Inertia to an existing Laravel API gets awkward fast. Same thing happens in the other direction: you start with a full Inertia frontend and then realize you want to expose some of that data as a public API too. The naive solutions are: Sprinkle if ($request->wantsJson()) into your controllers Maintain two separate routes that return the exact same data Neither feels right. So I made inertia-split Starting fresh with Inertia: serve both from the same controller class ProjectController extends Controller { use HasHybridResponses ; public function index () { return $this -> respond () -> component ( 'Projects/Index' , [ 'projects' => Project :: all (), ]); // Inertia request → renders the Svelte/Vue/React component // API request → returns JSON } } The controller doesn't check anything. Inertia requests get an Inertia response, API clients get JSON. Existing API? Don't touch it If you just want to make an existing API method Inertia-aware, one annotation is enough: #[InertiaComponent('Users/Show')] public function show ( User $user ): array { return [ 'user' => $user ]; } The method body stays exactly as it was. Inertia requests get the component rendered with your data as props. Everything else gets the same JSON as before. Methods without the annotation are completely unaffected. Wait, how does this even work? The package can out Inertia's ResponseFactory for its own in the service provider (opt-in): $this -> app -> singleton ( ResponseFactory :: class , HybridResponseFactory :: class ); // checks if it's an Inertia request and returns appropriate response Good old OOP. Thank you polymorphism. Wrap-up Whatever the direction of your problem, making Inertia and API endpoints use the same controller is a big win. You're still responsible for writing routes and wiring middlewares, but this should save a lot of time and effort. Still in beta, use accor

2026-07-23 原文 →