# parse atproto identifiers `at://` URIs, DIDs, handles — parsed and validated, no copying. ```zig const std = @import("std"); const zat = @import("zat"); pub fn main() void { // an at:// URI addresses a record: authority / collection / rkey. // this one points at a post by jcsalterego.bsky.social. const at_uri = "at://did:plc:vc7f4oafdgxsihk4cry2xpze/app.bsky.feed.post/3mpk2wua4jc2x"; const uri = zat.AtUri.parse(at_uri).?; std.debug.print("{s:<14}{s}\n", .{ "authority:", uri.authority() }); std.debug.print("{s:<14}{s}\n", .{ "collection:", uri.collection().? }); std.debug.print("{s:<14}{s}\n", .{ "rkey:", uri.rkey().? }); const did = zat.Did.parse("did:plc:vc7f4oafdgxsihk4cry2xpze").?; std.debug.print("{s:<14}{t}\n", .{ "did method:", did.method() }); // Handle.parse returns null for invalid input std.debug.print("{s:<14}{s}\n", .{ "bsky.app:", validity("bsky.app") }); std.debug.print("{s:<14}{s}\n", .{ "not a handle:", validity("not a handle") }); } fn validity(handle: []const u8) []const u8 { return if (zat.Handle.parse(handle) != null) "valid" else "invalid"; } ``` ``` authority: did:plc:vc7f4oafdgxsihk4cry2xpze collection: app.bsky.feed.post rkey: 3mpk2wua4jc2x did method: plc bsky.app: valid not a handle: invalid ``` This is `examples/01_parse_identifiers.zig` verbatim — copy it and `zig build example-parse-identifiers`. `parse` returns `?T` (or a struct's own optional) — you get a value only if the input is valid, so the type system stops a malformed identifier from being mistaken for a real one. Same shape for `Nsid`, `Rkey`, and `Tid`. A parsed identifier points into the string you passed. Nothing is copied, so it's cheap to create and stays valid only while that string is alive. `std.Uri.parse` works the same way. The authority in an `at://` URI can be a DID or a handle — the same record has a stable DID-based URI and a mutable handle alias for it. And an rkey is chosen by whoever wrote the record: validate its shape, but never read authorization or a naming convention into its value. **See also:** the [`at://` URI](https://atproto.com/specs/at-uri-scheme), [DID](https://atproto.com/specs/did), and [handle](https://atproto.com/specs/handle) specs; Indigo's [`syntax`](https://github.com/bluesky-social/indigo/tree/main/atproto/syntax) is the reference parser. Validating identifiers at the boundary is standard across every PDS and app.
wiring zat into your own build.zig ```zig const zat = b.dependency("zat", .{}).module("zat"); exe.root_module.addImport("zat", zat); ``` after `zig fetch --save https://tangled.org/zat.dev/zat/archive/main`.