Bezeichner is a small Go service that generates and maps identifiers, exposed via gRPC and HTTP.
- gRPC is the primary API surface.
- HTTP is implemented as an RPC gateway that routes by gRPC full method name (so both transports share the same contract).
The API contract lives in:
api/bezeichner/v1/service.proto
Distributed systems often need globally unique identifiers across multiple languages and runtimes. Bezeichner centralizes identifier generation so:
- you don't re-implement ID generation logic per service/language,
- you can standardize generator choices per domain/application,
- you can migrate/translate legacy identifiers via mapping.
The v1 service supports:
GenerateIdentifiers: generatecountidentifiers for a configuredapplicationMapIdentifiers: map a list of identifiers using a configured mapping table
Both endpoints enforce request-size limits in the domain layer for basic DoS protection (limits are currently 1000 items for both generate count and map list).
Bezeichner uses the go-service configuration conventions. A representative configuration used by development and feature tests is:
test/.config/server.yml
Generator configuration selects applications, each of which has:
- a
name(the public application key you pass on requests), - a
kind(the generator implementation to use).
Supported built-in kinds (at time of writing):
uuidksuidulidxidsnowflakenanoidtypeidpg(Postgres sequence-backed)
Example:
generator:
applications:
- name: public-uuid
kind: uuid
- name: internal-ulid
kind: ulid
- name: order-seq
kind: pg
The pg generator reads the next value from a Postgres sequence using:
SELECT nextval($1::regclass)
The sequence name is the configured application.name (i.e., Application.Name).
Important:
- The service does not create sequences. You must provision them separately (migrations/DB tooling/etc.).
Mapper configuration defines a lookup table for identifier translation (useful for legacy migrations):
mapper:
identifiers:
legacy-1: canonical-1
legacy-2: canonical-2
Semantics:
- Mapping is strict: if any input ID is missing from the table, the operation fails.
- Output order matches input order.
Health checks are provided via go-health integration. Timing is configured as durations:
health:
duration: 1s # how often to run checks
timeout: 1s # max time a single check may take
The service registers:
noopandonlinechecks always,- a
pgcheck only if a DB handle is configured/available.
make submodule
make dep
make dev
make dev runs the server using air and a config file like:
./bezeichner server -i file:test/.config/server.yml
make build # builds ./bezeichner (release)
make build-test # builds ./bezeichner test binary (features, race, coverage)
Below are examples for both transports. Exact request/response schemas are defined in api/bezeichner/v1/service.proto.
Assuming the service is listening on localhost:12000 (default in the sample config):
Generate 3 IDs for application public-uuid:
grpcurl -plaintext \
-d '{"application":"public-uuid","count":"3"}' \
localhost:12000 \
bezeichner.v1.Service/GenerateIdentifiers
Map identifiers:
grpcurl -plaintext \
-d '{"ids":["legacy-1","legacy-2"]}' \
localhost:12000 \
bezeichner.v1.Service/MapIdentifiers
HTTP routes are keyed by the gRPC full method name. That means your HTTP client calls the same method identifiers as gRPC.
Assuming the service is listening on localhost:11000 (default in the sample config):
Generate identifiers:
curl -sS \
-X POST \
-H 'content-type: application/json' \
--data '{"application":"public-uuid","count":"3"}' \
http://localhost:11000/bezeichner.v1.Service/GenerateIdentifiers
Map identifiers:
curl -sS \
-X POST \
-H 'content-type: application/json' \
--data '{"ids":["legacy-1","legacy-2"]}' \
http://localhost:11000/bezeichner.v1.Service/MapIdentifiers
Note:
- The exact HTTP path shape is defined by the underlying
go-serviceHTTP RPC router; the important part is that routing is done by gRPC full method name.
Bezeichner is typically deployed as a shared internal service. Depending on your scale and domain boundaries, you can:
- run a single global instance,
- shard by bounded context,
- run per region/cluster.
If you use the pg generator, ensure database connectivity and sequence provisioning are handled as part of your infrastructure/migrations.
Bezeichner builds on established ID generation libraries:
- https://github.com/google/uuid
- https://github.com/segmentio/ksuid
- https://github.com/oklog/ulid
- https://github.com/rs/xid
- https://github.com/sony/sonyflake
- https://go.jetify.com/typeid
Service scaffolding and transport/DI patterns:
The project follows:
- Go (see
go.modfor version) - Ruby (used for end-to-end feature tests; see
.ruby-version)
Most make targets come from the bin/ git submodule:
make submodule
make dep
make setup
Go unit/spec tests:
make specs
make lint
End-to-end feature tests:
make features
See CHANGELOG.md.
