@tlsft/service-key
v0.6.0
Published
The service key — [METHOD] [service]/resource — a string naming one call to one service
Maintainers
Readme
@tlsft/service-key
Name a call by the service that answers it, not by where that service lives:
POST [billing]/invoicesWhy a service key
A URL answers where: a host, a port, a protocol. Once that's written into a caller, every move becomes a code change: a service splits off, a region is added, a tenant's data has to stay on its own infrastructure. A service key answers what: which service, which resource, which verb. Where the call goes is then a lookup from service to address, and that lookup can differ per environment, per network or per tenant without touching callers.
- Transport-neutral. The verb is optional, so REST (
GET [users]/:id) and RPC ([helloworld.Greeter]/SayHello) share one grammar. - One name everywhere. The same string can serve as the route, the access rule and the log line. Wildcards (
* [*]/**) parse with the same grammar, so access rules use it too. - Small. No dependencies; it parses and formats, and leaves resolution and matching to you.
Grammar
[METHOD] [service]/resource
| Key | Meaning |
| --- | --- |
| POST [billing]/invoices | REST call |
| [helloworld.Greeter]/SayHello | no verb (method: null) |
| GET [@billing]/invoices | confined: true: the call's data stays in the caller's own custody, never sent to a host it doesn't hold; the library only records the flag |
| * [*]/** | wildcard pattern |
Use
import {parseServiceKey, formatServiceKey} from '@tlsft/service-key'
parseServiceKey('POST [billing]/invoices')
// {method: 'POST', service: 'billing', resource: '/invoices', confined: false}
formatServiceKey({service: 'helloworld.Greeter', resource: '/SayHello'})
// '[helloworld.Greeter]/SayHello'parseServiceKey returns null for anything that isn't a key, so a caller can ask "is this a key?" and raise its own error with its own context. formatServiceKey throws a TypeError on malformed parts: that's a programming error, not a question.
Parts are what an answering service should match on; the string form is just the caller's notation. serviceKeyFormat bundles the pair as {parse, format}, so a different notation can be another pair, and code written against parts doesn't change.
Rust
The service-key crate implements the same grammar, checked against the same test cases (test/cases.json), and its version tracks this package's. It parses with regress, an ECMAScript regex engine, so the pattern and its meaning are the same as here.
use service_key::ServiceKey;
let key = ServiceKey::parse("POST [@billing]/invoices").unwrap();
// ServiceKey {method: Some("POST"), service: "billing", resource: "/invoices", confined: true}
key.to_string()
// "POST [@billing]/invoices"ServiceKey::parse returns None for anything that isn't a key. Parts are typed, so formatting cannot fail.
Related
MicroQL uses service keys to name the service calls in a query.
