From f6f629abf6080b94c83d86da387e3eab91664390 Mon Sep 17 00:00:00 2001 From: Alexander Bogosyan Date: Wed, 30 Oct 2019 16:45:32 +0300 Subject: [PATCH 1/4] Add external format validators option --- src/jesse.erl | 6 ++++++ src/jesse_state.erl | 11 +++++++++++ src/jesse_validator_draft3.erl | 15 +++++++++++++-- src/jesse_validator_draft4.erl | 15 +++++++++++++-- 4 files changed, 43 insertions(+), 4 deletions(-) diff --git a/src/jesse.erl b/src/jesse.erl index de61bde3..46275ea1 100644 --- a/src/jesse.erl +++ b/src/jesse.erl @@ -41,6 +41,8 @@ , error_handler/0 , error_list/0 , external_validator/0 + , external_format_validator/0 + , external_format_validators_map/0 , json_term/0 , schema/0 , schema_id/0 @@ -71,6 +73,9 @@ -type external_validator() :: fun((json_term(), any()) -> any()) | undefined. +-type external_format_validator() :: fun((json_term()) -> ok | error). +-type external_format_validators_map() :: #{binary() => external_format_validator()}. + %% From https://github.com/erlang/otp/blob/OTP-20.2.3/lib/inets/doc/src/http_uri.xml#L57 -type http_uri_uri() :: string() | unicode:unicode_binary(). @@ -95,6 +100,7 @@ | {default_schema_ver, schema_ver()} | {error_handler, error_handler()} | {external_validator, external_validator()} + | {external_format_validators, external_format_validators_map()} | {meta_schema_ver, schema_ver()} | {parser_fun, parser_fun()} | {schema_loader_fun, schema_loader_fun()}. diff --git a/src/jesse_state.erl b/src/jesse_state.erl index d1155df3..0be85cb2 100644 --- a/src/jesse_state.erl +++ b/src/jesse_state.erl @@ -27,6 +27,7 @@ -export([ add_to_path/2 , get_allowed_errors/1 , get_external_validator/1 + , get_external_format_validator/2 , get_current_path/1 , get_current_schema/1 , get_current_schema_id/1 @@ -59,6 +60,7 @@ , error_handler :: jesse:error_handler() , error_list :: jesse:error_list() , external_validator :: jesse:external_validator() + , external_format_validators :: jesse:external_format_validators_map() , id :: jesse:schema_id() , root_schema :: jesse:schema() , schema_loader_fun :: jesse:schema_loader_fun() @@ -142,6 +144,10 @@ new(JsonSchema, Options) -> ExternalValidator = proplists:get_value( external_validator , Options ), + ExternalFormatValidators = proplists:get_value( external_format_validators + , Options + , #{} + ), LoaderFun = proplists:get_value( schema_loader_fun , Options , ?default_schema_loader_fun @@ -154,6 +160,7 @@ new(JsonSchema, Options) -> , default_schema_ver = DefaultSchemaVer , schema_loader_fun = LoaderFun , external_validator = ExternalValidator + , external_format_validators = ExternalFormatValidators }, set_current_schema(NewState, JsonSchema). @@ -393,3 +400,7 @@ load_schema(#state{schema_loader_fun = LoaderFun}, SchemaURI) -> %% @private get_external_validator(#state{external_validator = Fun}) -> Fun. + +-spec get_external_format_validator(binary(), state()) -> jesse:external_format_validator() | undefined. +get_external_format_validator(Format, #state{external_format_validators = Validators}) -> + maps:get(Format, Validators, undefined). diff --git a/src/jesse_validator_draft3.erl b/src/jesse_validator_draft3.erl index 28ce04fc..a94b9820 100644 --- a/src/jesse_validator_draft3.erl +++ b/src/jesse_validator_draft3.erl @@ -837,8 +837,8 @@ check_enum(Value, Enum, State) -> handle_data_invalid(?not_in_enum, Value, State) end. -check_format(_Value, _Format, State) -> - State. +check_format(Value, Format, State) -> + maybe_external_check_format(Value, Format, State). %% @doc 5.24. divisibleBy %% @@ -1051,3 +1051,14 @@ maybe_external_check_value(Value, State) -> Fun -> Fun(Value, State) end. + +maybe_external_check_format(Value, Format, State) -> + case jesse_state:get_external_format_validator(Format, State) of + undefined -> State; + Fun when is_function(Fun, 1) -> + case Fun(Value) of + ok -> State; + error -> + handle_data_invalid(?wrong_format, Value, State) + end + end. \ No newline at end of file diff --git a/src/jesse_validator_draft4.erl b/src/jesse_validator_draft4.erl index 1a364028..b38938bc 100644 --- a/src/jesse_validator_draft4.erl +++ b/src/jesse_validator_draft4.erl @@ -980,8 +980,8 @@ check_format(Value, _Format = <<"ipv6">>, State) when is_binary(Value) -> check_format(Value, _Format = <<"uri">>, State) when is_binary(Value) -> %% not yet supported State; -check_format(_Value, _Format, State) -> - State. +check_format(Value, Format, State) -> + maybe_external_check_format(Value, Format, State). %% @doc 5.1.1. multipleOf %% @@ -1379,3 +1379,14 @@ maybe_external_check_value(Value, State) -> Fun -> Fun(Value, State) end. + +maybe_external_check_format(Value, Format, State) -> + case jesse_state:get_external_format_validator(Format, State) of + undefined -> State; + Fun when is_function(Fun, 1) -> + case Fun(Value) of + ok -> State; + error -> + handle_data_invalid(?wrong_format, Value, State) + end + end. From e19c469ff5b5d9109f569d6203aef4b3525a7a0e Mon Sep 17 00:00:00 2001 From: Alexander Bogosyan Date: Sat, 11 Apr 2020 00:07:02 +0300 Subject: [PATCH 2/4] Add tests and readme for custom string format validators --- README.md | 33 ++++++++++ src/jesse.erl | 12 +++- src/jesse_state.erl | 13 +++- test/jesse_schema_validator_tests.erl | 95 +++++++++++++++++++++++++++ 4 files changed, 147 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 7520780f..2c955e47 100644 --- a/README.md +++ b/README.md @@ -270,6 +270,39 @@ ErrorType}` where * ErrorType is an atom such as `missing_id_field` or a tuple such as `{wrong_type_dependency, Dependency}`. +## Custom string format validators +Built-in format validators, like `ipv4`, `date-time` are often not enough for `string` type +and usage of pattern (regexps) is not convenient. + +Custom string format validator could be used with `{external_format_validators, Validators}` option. +* `Validators` is a map of `CustomFormatName => ValidationFunction` pairs (`proplists` are also supported) +* `CustomFormatName` is a string that must be used in schema as a `format` value for `string` type +* `ValidationFunction` takes `string` value and must return `ok` or `error` atom indicating validation result + +Simple example: +```erlang +1> Schema = #{ +1> <<"type">> => <<"object">>, +1> <<"properties">> => #{ +1> <<"foo">> => #{ +1> <<"type">> => <<"string">>, +1> <<"format">> => <<"ipv4_and_port">> +1> } +1> } +1> }, +1> Validators = #{ +1> <<"ipv4_and_port">> => fun(<<"127.0.0.1:1234">>) -> ok; (_Else) -> error end +1> }, +1> Options = [{external_format_validators, Validators}], +1> jesse:validate_with_schema(Schema, #{<<"foo">> => <<"127.0.0.1:1234">>}, Options). +{ok,#{<<"foo">> => <<"127.0.0.1:1234">>}} +2> jesse:validate_with_schema(Schema, #{<<"foo">> => <<"Hello, Joe!">>}, Options). +{error,[{data_invalid,#{<<"format">> => <<"ipv4_and_port">>, + <<"type">> => <<"string">>}, + wrong_format,<<"Hello, Joe!">>, + [<<"foo">>]}]} +``` + ## Caveats * pattern and patternProperty attributes: diff --git a/src/jesse.erl b/src/jesse.erl index 46275ea1..d3f45429 100644 --- a/src/jesse.erl +++ b/src/jesse.erl @@ -42,7 +42,7 @@ , error_list/0 , external_validator/0 , external_format_validator/0 - , external_format_validators_map/0 + , external_format_validators/0 , json_term/0 , schema/0 , schema_id/0 @@ -74,7 +74,13 @@ | undefined. -type external_format_validator() :: fun((json_term()) -> ok | error). --type external_format_validators_map() :: #{binary() => external_format_validator()}. + +-ifndef(erlang_deprecated_types). +-type external_format_validators() :: [{binary(), external_format_validator()}] + | #{binary() => external_format_validator()}. +-else. +-type external_format_validators() :: [{binary(), external_format_validator()}]. +-endif. %% From https://github.com/erlang/otp/blob/OTP-20.2.3/lib/inets/doc/src/http_uri.xml#L57 -type http_uri_uri() :: string() | unicode:unicode_binary(). @@ -100,7 +106,7 @@ | {default_schema_ver, schema_ver()} | {error_handler, error_handler()} | {external_validator, external_validator()} - | {external_format_validators, external_format_validators_map()} + | {external_format_validators, external_format_validators()} | {meta_schema_ver, schema_ver()} | {parser_fun, parser_fun()} | {schema_loader_fun, schema_loader_fun()}. diff --git a/src/jesse_state.erl b/src/jesse_state.erl index 9b8a36c3..5488c3d0 100644 --- a/src/jesse_state.erl +++ b/src/jesse_state.erl @@ -60,7 +60,7 @@ , error_handler :: jesse:error_handler() , error_list :: jesse:error_list() , external_validator :: jesse:external_validator() - , external_format_validators :: jesse:external_format_validators_map() + , external_format_validators :: jesse:external_format_validators() , id :: jesse:schema_id() , root_schema :: jesse:schema() , schema_loader_fun :: jesse:schema_loader_fun() @@ -407,8 +407,15 @@ get_external_validator(#state{external_validator = Fun}) -> Fun. -spec get_external_format_validator(binary(), state()) -> jesse:external_format_validator() | undefined. -get_external_format_validator(Format, #state{external_format_validators = Validators}) -> - maps:get(Format, Validators, undefined). +-ifndef(erlang_deprecated_types). +get_external_format_validator(Format, #state{external_format_validators = Validators}) when is_map(Validators) -> + maps:get(Format, Validators, undefined); +get_external_format_validator(Format, #state{external_format_validators = Validators}) when is_list(Validators) -> + proplists:get_value(Format, Validators, undefined). +-else. +get_external_format_validator(Format, #state{external_format_validators = Validators}) when is_list(Validators) -> + proplists:get_value(Format, Validators, undefined). +-endif. %% @private -ifdef(OTP_RELEASE). %% OTP 21+ diff --git a/test/jesse_schema_validator_tests.erl b/test/jesse_schema_validator_tests.erl index 44c67cbd..94bb6e62 100644 --- a/test/jesse_schema_validator_tests.erl +++ b/test/jesse_schema_validator_tests.erl @@ -221,6 +221,54 @@ schema_unsupported_test() -> , jesse_schema_validator:validate(UnsupportedSchema, Json, []) ). +external_format_validator_test() -> + [ external_format_validator_test_draft(URI) + || URI <- [ <<"http://json-schema.org/draft-03/schema#">> + , <<"http://json-schema.org/draft-04/schema#">> + ] + ]. + +external_format_validator_test_draft(URI) -> + CustomFormatSchema = [ + {<<"type">>, <<"string">>}, + {<<"format">>, <<"ipv4_and_port">>} + ], + + Schema = {[ + {<<"$schema">>, URI}, + {<<"type">>, <<"object">>}, + {<<"properties">>, {[ + {<<"foo">>, CustomFormatSchema} + ]}} + ]}, + + Options = [{ + external_format_validators, + [{<<"ipv4_and_port">>, fun(<<"127.0.0.1:1234">>) -> ok; (_Else) -> error end}] + }], + + ValidJson = {[ + {<<"foo">>, <<"127.0.0.1:1234">>} + ]}, + + ?assertEqual( + {ok, ValidJson}, + jesse_schema_validator:validate(Schema, ValidJson, Options) + ), + + InvalidJson = {[ + {<<"foo">>, <<"Hello, Joe!">>} + ]}, + + ?assertThrow([{ + data_invalid, + CustomFormatSchema, + wrong_format, + <<"Hello, Joe!">>, + [<<"foo">>] + }], + jesse_schema_validator:validate(Schema, InvalidJson, Options)). + -ifndef(erlang_deprecated_types). -ifndef(COMMON_TEST). % see Emakefile map_schema_test() -> @@ -270,6 +318,12 @@ map_data_test() -> ] ]. +map_external_format_validator_test() -> + [ map_external_format_validator_test_draft(URI) + || URI <- [ <<"http://json-schema.org/draft-03/schema#">> + , <<"http://json-schema.org/draft-04/schema#">> + ] + ]. map_data_test_draft(URI) -> Schema = {[ {<<"$schema">>, URI} @@ -325,5 +379,46 @@ map_data_test_draft(URI) -> , [{allowed_errors, infinity}] )). +map_external_format_validator_test_draft(URI) -> + CustomFormatSchema = #{ + <<"type">> => <<"string">>, + <<"format">> => <<"ipv4_and_port">> + }, + + Schema = #{ + <<"$schema">> => URI, + <<"type">> => <<"object">>, + <<"properties">> => #{ + <<"foo">> => CustomFormatSchema + } + }, + + Options = [{ + external_format_validators, + #{<<"ipv4_and_port">> => fun(<<"127.0.0.1:1234">>) -> ok; (_Else) -> error end} + }], + + ValidJson = #{ + <<"foo">> => <<"127.0.0.1:1234">> + }, + ?assertEqual( + {ok, ValidJson}, + jesse_schema_validator:validate(Schema, ValidJson, Options) + ), + + InvalidJson = #{ + <<"foo">> => <<"Hello, Joe!">> + }, + + ?assertThrow([{ + data_invalid, + CustomFormatSchema, + wrong_format, + <<"Hello, Joe!">>, + [<<"foo">>] + }], + jesse_schema_validator:validate(Schema, InvalidJson, Options)). + -endif. -endif. + From fe9c54b006f250832f5ab75b89d7f9f889ce6265 Mon Sep 17 00:00:00 2001 From: Alexander Bogosyan Date: Sat, 11 Apr 2020 00:36:50 +0300 Subject: [PATCH 3/4] Make Elvis happy with external format validators code --- src/jesse.erl | 16 ++++++++-------- src/jesse_state.erl | 24 ++++++++++++++---------- src/jesse_validator_draft3.erl | 2 +- src/jesse_validator_draft4.erl | 2 +- test/jesse_schema_validator_tests.erl | 10 ++++++++-- 5 files changed, 32 insertions(+), 22 deletions(-) diff --git a/src/jesse.erl b/src/jesse.erl index d3f45429..c9538183 100644 --- a/src/jesse.erl +++ b/src/jesse.erl @@ -41,8 +41,8 @@ , error_handler/0 , error_list/0 , external_validator/0 - , external_format_validator/0 - , external_format_validators/0 + , ext_format_validator/0 + , ext_format_validators/0 , json_term/0 , schema/0 , schema_id/0 @@ -73,16 +73,16 @@ -type external_validator() :: fun((json_term(), any()) -> any()) | undefined. --type external_format_validator() :: fun((json_term()) -> ok | error). +-type ext_format_validator() :: fun((json_term()) -> ok | error). -ifndef(erlang_deprecated_types). --type external_format_validators() :: [{binary(), external_format_validator()}] - | #{binary() => external_format_validator()}. +-type ext_format_validators() :: [{binary(), ext_format_validator()}] + | #{binary() => ext_format_validator()}. -else. --type external_format_validators() :: [{binary(), external_format_validator()}]. +-type ext_format_validators() :: [{binary(), ext_format_validator()}]. -endif. -%% From https://github.com/erlang/otp/blob/OTP-20.2.3/lib/inets/doc/src/http_uri.xml#L57 +%%github.com/erlang/otp/blob/OTP-20.2.3/lib/inets/doc/src/http_uri.xml#L57 -type http_uri_uri() :: string() | unicode:unicode_binary(). -type json_term() :: term(). @@ -106,7 +106,7 @@ | {default_schema_ver, schema_ver()} | {error_handler, error_handler()} | {external_validator, external_validator()} - | {external_format_validators, external_format_validators()} + | {ext_format_validators, ext_format_validators()} | {meta_schema_ver, schema_ver()} | {parser_fun, parser_fun()} | {schema_loader_fun, schema_loader_fun()}. diff --git a/src/jesse_state.erl b/src/jesse_state.erl index 5488c3d0..aff59f0d 100644 --- a/src/jesse_state.erl +++ b/src/jesse_state.erl @@ -27,7 +27,7 @@ -export([ add_to_path/2 , get_allowed_errors/1 , get_external_validator/1 - , get_external_format_validator/2 + , get_ext_format_validator/2 , get_current_path/1 , get_current_schema/1 , get_current_schema_id/1 @@ -60,7 +60,7 @@ , error_handler :: jesse:error_handler() , error_list :: jesse:error_list() , external_validator :: jesse:external_validator() - , external_format_validators :: jesse:external_format_validators() + , ext_format_validators :: jesse:ext_format_validators() , id :: jesse:schema_id() , root_schema :: jesse:schema() , schema_loader_fun :: jesse:schema_loader_fun() @@ -160,7 +160,7 @@ new(JsonSchema, Options) -> , default_schema_ver = DefaultSchemaVer , schema_loader_fun = LoaderFun , external_validator = ExternalValidator - , external_format_validators = ExternalFormatValidators + , ext_format_validators = ExternalFormatValidators }, set_current_schema(NewState, JsonSchema). @@ -406,15 +406,19 @@ load_schema(#state{schema_loader_fun = LoaderFun}, SchemaURI) -> get_external_validator(#state{external_validator = Fun}) -> Fun. --spec get_external_format_validator(binary(), state()) -> jesse:external_format_validator() | undefined. +-spec get_ext_format_validator(binary(), state()) -> + jesse:external_format_validator() | undefined. -ifndef(erlang_deprecated_types). -get_external_format_validator(Format, #state{external_format_validators = Validators}) when is_map(Validators) -> - maps:get(Format, Validators, undefined); -get_external_format_validator(Format, #state{external_format_validators = Validators}) when is_list(Validators) -> - proplists:get_value(Format, Validators, undefined). +get_ext_format_validator(Format, #state{ext_format_validators = Validators}) + when is_map(Validators) -> + maps:get(Format, Validators, undefined); +get_ext_format_validator(Format, #state{ext_format_validators = Validators}) + when is_list(Validators) -> + proplists:get_value(Format, Validators, undefined). -else. -get_external_format_validator(Format, #state{external_format_validators = Validators}) when is_list(Validators) -> - proplists:get_value(Format, Validators, undefined). +get_ext_format_validator(Format, #state{ext_format_validators = Validators}) + when is_list(Validators) -> + proplists:get_value(Format, Validators, undefined). -endif. %% @private diff --git a/src/jesse_validator_draft3.erl b/src/jesse_validator_draft3.erl index 45d77c73..63d08ab1 100644 --- a/src/jesse_validator_draft3.erl +++ b/src/jesse_validator_draft3.erl @@ -1054,7 +1054,7 @@ maybe_external_check_value(Value, State) -> end. maybe_external_check_format(Value, Format, State) -> - case jesse_state:get_external_format_validator(Format, State) of + case jesse_state:get_ext_format_validator(Format, State) of undefined -> State; Fun when is_function(Fun, 1) -> case Fun(Value) of diff --git a/src/jesse_validator_draft4.erl b/src/jesse_validator_draft4.erl index c223c930..8355395c 100644 --- a/src/jesse_validator_draft4.erl +++ b/src/jesse_validator_draft4.erl @@ -1382,7 +1382,7 @@ maybe_external_check_value(Value, State) -> end. maybe_external_check_format(Value, Format, State) -> - case jesse_state:get_external_format_validator(Format, State) of + case jesse_state:get_ext_format_validator(Format, State) of undefined -> State; Fun when is_function(Fun, 1) -> case Fun(Value) of diff --git a/test/jesse_schema_validator_tests.erl b/test/jesse_schema_validator_tests.erl index 94bb6e62..10b11f5c 100644 --- a/test/jesse_schema_validator_tests.erl +++ b/test/jesse_schema_validator_tests.erl @@ -244,7 +244,10 @@ external_format_validator_test_draft(URI) -> Options = [{ external_format_validators, - [{<<"ipv4_and_port">>, fun(<<"127.0.0.1:1234">>) -> ok; (_Else) -> error end}] + [{ + <<"ipv4_and_port">>, + fun(<<"127.0.0.1:1234">>) -> ok; (_Else) -> error end + }] }], ValidJson = {[ @@ -395,7 +398,10 @@ map_external_format_validator_test_draft(URI) -> Options = [{ external_format_validators, - #{<<"ipv4_and_port">> => fun(<<"127.0.0.1:1234">>) -> ok; (_Else) -> error end} + #{ + <<"ipv4_and_port">> => + fun(<<"127.0.0.1:1234">>) -> ok; (_Else) -> error end + } }], ValidJson = #{ From 78f0389269c67e3dede462c4388d7f8474193280 Mon Sep 17 00:00:00 2001 From: Alexander Bogosyan Date: Fri, 17 Apr 2020 01:01:30 +0300 Subject: [PATCH 4/4] Consistent naming for external format validator types and option tag --- README.md | 4 ++-- src/jesse_state.erl | 26 +++++++++++++------------- test/jesse_schema_validator_tests.erl | 4 ++-- 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index 2c955e47..efbf86c5 100644 --- a/README.md +++ b/README.md @@ -274,7 +274,7 @@ ErrorType}` where Built-in format validators, like `ipv4`, `date-time` are often not enough for `string` type and usage of pattern (regexps) is not convenient. -Custom string format validator could be used with `{external_format_validators, Validators}` option. +Custom string format validator could be used with `{ext_format_validators, Validators}` option. * `Validators` is a map of `CustomFormatName => ValidationFunction` pairs (`proplists` are also supported) * `CustomFormatName` is a string that must be used in schema as a `format` value for `string` type * `ValidationFunction` takes `string` value and must return `ok` or `error` atom indicating validation result @@ -293,7 +293,7 @@ Simple example: 1> Validators = #{ 1> <<"ipv4_and_port">> => fun(<<"127.0.0.1:1234">>) -> ok; (_Else) -> error end 1> }, -1> Options = [{external_format_validators, Validators}], +1> Options = [{ext_format_validators, Validators}], 1> jesse:validate_with_schema(Schema, #{<<"foo">> => <<"127.0.0.1:1234">>}, Options). {ok,#{<<"foo">> => <<"127.0.0.1:1234">>}} 2> jesse:validate_with_schema(Schema, #{<<"foo">> => <<"Hello, Joe!">>}, Options). diff --git a/src/jesse_state.erl b/src/jesse_state.erl index aff59f0d..59826deb 100644 --- a/src/jesse_state.erl +++ b/src/jesse_state.erl @@ -144,23 +144,23 @@ new(JsonSchema, Options) -> ExternalValidator = proplists:get_value( external_validator , Options ), - ExternalFormatValidators = proplists:get_value( external_format_validators - , Options - , #{} - ), + ExtFormatValidators = proplists:get_value( ext_format_validators + , Options + , #{} + ), LoaderFun = proplists:get_value( schema_loader_fun , Options , ?default_schema_loader_fun ), - NewState = #state{ root_schema = JsonSchema - , current_path = [] - , allowed_errors = AllowedErrors - , error_list = [] - , error_handler = ErrorHandler - , default_schema_ver = DefaultSchemaVer - , schema_loader_fun = LoaderFun - , external_validator = ExternalValidator - , ext_format_validators = ExternalFormatValidators + NewState = #state{ root_schema = JsonSchema + , current_path = [] + , allowed_errors = AllowedErrors + , error_list = [] + , error_handler = ErrorHandler + , default_schema_ver = DefaultSchemaVer + , schema_loader_fun = LoaderFun + , external_validator = ExternalValidator + , ext_format_validators = ExtFormatValidators }, set_current_schema(NewState, JsonSchema). diff --git a/test/jesse_schema_validator_tests.erl b/test/jesse_schema_validator_tests.erl index 10b11f5c..5de7bde7 100644 --- a/test/jesse_schema_validator_tests.erl +++ b/test/jesse_schema_validator_tests.erl @@ -243,7 +243,7 @@ external_format_validator_test_draft(URI) -> ]}, Options = [{ - external_format_validators, + ext_format_validators, [{ <<"ipv4_and_port">>, fun(<<"127.0.0.1:1234">>) -> ok; (_Else) -> error end @@ -397,7 +397,7 @@ map_external_format_validator_test_draft(URI) -> }, Options = [{ - external_format_validators, + ext_format_validators, #{ <<"ipv4_and_port">> => fun(<<"127.0.0.1:1234">>) -> ok; (_Else) -> error end