@@ -242,6 +242,106 @@ Because we believe the use case of tagged unions in decoder output is not as com
242242You may use the decoder hook ` avro_decoer_hooks:tag_unions/0 ` to have the decoded values tagged.
243243NOTE: only named complex types are tagged by this hook, you can of course write your own hook for a different tagging behaviour.
244244
245+ # Avro IDL (.avdl) Support
246+
247+ erlavro can parse [ Avro IDL] ( https://avro.apache.org/docs/current/idl-language/ )
248+ files (` .avdl ` ) — the human-readable schema definition language — and convert
249+ them to Avro schemas for encoding and decoding.
250+
251+ ## Loading an .avdl schema file
252+
253+ Given a schema file ` com/example/my_service.avdl ` :
254+
255+ ``` avdl
256+ @namespace("com.example")
257+ protocol MyService {
258+ enum Status { OK, ERROR }
259+
260+ record Response {
261+ string id;
262+ Status status;
263+ union { null, string } message = null;
264+ }
265+
266+ Response process(string id);
267+ }
268+ ```
269+
270+ Load it into a schema store and use it for encoding/decoding:
271+
272+ ``` erlang
273+ % % Load all types from the .avdl file into a schema store
274+ Store = avro_schema_store :new ([], [" com/example/my_service.avdl" ]),
275+
276+ % % Look up a type by its full name and make an encoder/decoder
277+ LookupFun = avro_schema_store :to_lookup_fun (Store ),
278+ Encoder = avro :make_encoder (LookupFun , []),
279+ Decoder = avro :make_decoder (LookupFun , []),
280+
281+ Record = [{" id" , <<" req-1" >>}, {" status" , <<" OK" >>}, {" message" , null }],
282+ Bin = iolist_to_binary (Encoder (" com.example.Response" , Record )),
283+ Record = Decoder (" com.example.Response" , Bin ).
284+ ```
285+
286+ ## Importing types across .avdl files
287+
288+ IDL files can import types from other files using ` import idl ` , ` import schema `
289+ (` .avsc ` ), or ` import protocol ` (` .avpr ` ) statements. Import paths are resolved
290+ relative to the importing file's directory, so nested imports work correctly.
291+
292+ ``` avdl
293+ @namespace("com.example")
294+ protocol Orders {
295+ import idl "common/types.avdl"; %% imports Common.Address, Common.Money
296+ import schema "status.avsc"; %% imports a plain JSON schema
297+
298+ record Order {
299+ string id;
300+ com.example.common.Address shipping_address;
301+ com.example.common.Money total;
302+ }
303+ }
304+ ```
305+
306+ ``` erlang
307+ Store = avro_schema_store :new ([], [" schemas/orders.avdl" ]),
308+ ```
309+
310+ ## In-memory schema loading (no filesystem)
311+
312+ For testing or embedded schemas, supply a custom ` read_fun ` that resolves
313+ import paths from memory instead of the filesystem:
314+
315+ ``` erlang
316+ Files = #{
317+ {" schemas" , " common.avdl" } =>
318+ <<" protocol Common { record Address { string city; } }" >>,
319+ {" schemas" , " orders.avdl" } =>
320+ <<" protocol Orders {\n "
321+ " import idl \" common.avdl\" ;\n "
322+ " record Order { string id; Address addr; }\n "
323+ " }" >>
324+ },
325+ ReadFun = fun (Cwd , Path ) ->
326+ case maps :find ({Cwd , Path }, Files ) of
327+ {ok , Bin } -> {ok , Bin };
328+ error -> {error , enoent }
329+ end
330+ end ,
331+ {ok , Bin } = maps :find ({" schemas" , " orders.avdl" }, Files ),
332+ Schema = avro_idl :decode_schema (
333+ binary_to_list (Bin ), " schemas" ,
334+ [{read_fun , ReadFun }]).
335+ ```
336+
337+ ## Converting .avdl to AVPR (JSON protocol)
338+
339+ ``` erlang
340+ {ok , Bin } = file :read_file (" my_service.avdl" ),
341+ Avpr = avro_idl :str_to_avpr (binary_to_list (Bin ), filename :dirname (" my_service.avdl" )),
342+ io :format (" ~s~n " , [jsone :encode (Avpr )]).
343+ ```
344+
245345# Object container file encoding/decoding
246346
247347See ` avro_ocf.erl ` for details
0 commit comments