diff --git a/manifest.toml b/manifest.toml index e44670b..28ed2b4 100644 --- a/manifest.toml +++ b/manifest.toml @@ -1,37 +1,32 @@ -# This file was generated by Gleam -# You typically do not need to edit this file +# Do not manually edit this file, it is managed by Gleam. +# +# This file locks the dependency versions used, to make your build +# deterministic and to prevent unexpected versions from being included +# in your application. +# +# You should check this file into your source control repository. packages = [ { name = "datebook", version = "1.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib", "gleam_time"], otp_app = "datebook", source = "hex", outer_checksum = "8895C5D7F66AD8D785E550DDB875FAC9D5151020B1C00F00123A2240C030D76C" }, { name = "gleam_community_colour", version = "2.0.4", build_tools = ["gleam"], requirements = ["gleam_json", "gleam_stdlib"], otp_app = "gleam_community_colour", source = "hex", outer_checksum = "6DB4665555D7D2B27F0EA32EF47E8BEBC4303821765F9C73D483F38EE24894F0" }, - { name = "gleam_erlang", version = "1.3.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_erlang", source = "hex", outer_checksum = "1124AD3AA21143E5AF0FC5CF3D9529F6DB8CA03E43A55711B60B6B7B3874375C" }, { name = "gleam_http", version = "4.3.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_http", source = "hex", outer_checksum = "82EA6A717C842456188C190AFB372665EA56CE13D8559BF3B1DD9E40F619EE0C" }, - { name = "gleam_httpc", version = "5.0.0", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_http", "gleam_stdlib"], otp_app = "gleam_httpc", source = "hex", outer_checksum = "C545172618D07811494E97AAA4A0FB34DA6F6D0061FDC8041C2F8E3BE2B2E48F" }, { name = "gleam_json", version = "3.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_json", source = "hex", outer_checksum = "44FDAA8847BE8FC48CA7A1C089706BD54BADCC4C45B237A992EDDF9F2CDB2836" }, - { name = "gleam_otp", version = "1.2.0", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_stdlib"], otp_app = "gleam_otp", source = "hex", outer_checksum = "BA6A294E295E428EC1562DC1C11EA7530DCB981E8359134BEABC8493B7B2258E" }, - { name = "gleam_stdlib", version = "1.0.0", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "960090C2FB391784BB34267B099DC9315CC1B1F6013E7415BC763CEF1905D7D3" }, + { name = "gleam_stdlib", version = "1.0.3", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "1F543AFBA5D33DA493E6087F4E4C4F20D899411343512686C98A8ABB2963CF22" }, { name = "gleam_time", version = "1.8.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_time", source = "hex", outer_checksum = "533D8723774D61AD4998324F5DD1DABDCDBFABAFB9E87CB5D03C6955448FC97D" }, - { name = "gleeunit", version = "1.10.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleeunit", source = "hex", outer_checksum = "254B697FE72EEAD7BF82E941723918E421317813AC49923EE76A18C788C61E72" }, - { name = "json_value", version = "1.0.0", build_tools = ["gleam"], requirements = ["gleam_json", "gleam_stdlib"], otp_app = "json_value", source = "hex", outer_checksum = "D784AA7A33EAF1349C58EE79E3587484B4086D22079C2C4960DED5DC46FB2899" }, + { name = "gleeunit", version = "1.11.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleeunit", source = "hex", outer_checksum = "EC31ABA74256AEA531EDF8169931D775BBB384FED0A8A1BDC4DD9354E3E21826" }, { name = "multipart_form", version = "1.1.0", build_tools = ["gleam"], requirements = ["gleam_http", "gleam_stdlib"], otp_app = "multipart_form", source = "hex", outer_checksum = "082C77A0C3BB1128FCD55491665E9B72BC943E849B67D02B08CFA6808AD8E47C" }, - { name = "operating_system", version = "1.0.1", build_tools = ["gleam"], requirements = [], otp_app = "operating_system", source = "hex", outer_checksum = "682D4D19496E607A6E6229AA51A38A1400ED5067C2C54D56843DBCB0C61FFA6D" }, { name = "status_code", version = "1.1.0", build_tools = ["gleam"], requirements = [], otp_app = "status_code", source = "hex", outer_checksum = "F6EC765345A634602AD030EB1B4D34A425873CBC223CEC595EBF062073CD70BC" }, ] [requirements] datebook = { version = ">= 1.1.0 and < 2.0.0" } gleam_community_colour = { version = ">= 2.0.4 and < 3.0.0" } -gleam_erlang = { version = ">= 1.3.0 and < 2.0.0" } gleam_http = { version = ">= 4.0.0 and < 5.0.0" } -gleam_httpc = { version = ">= 5.0.0 and < 6.0.0" } gleam_json = { version = ">= 3.0.1 and < 4.0.0" } -gleam_otp = { version = ">= 1.1.0 and < 2.0.0" } gleam_stdlib = { version = ">= 0.44.0 and < 2.0.0" } gleam_time = { version = ">= 1.1.0 and < 2.0.0" } gleeunit = { version = ">= 1.0.0 and < 2.0.0" } -json_value = { version = ">= 1.0.0 and < 2.0.0" } multipart_form = { version = ">= 1.1.0 and < 2.0.0" } -operating_system = { version = ">= 1.0.1 and < 2.0.0" } status_code = { version = ">= 1.0.0 and < 2.0.0" } <<<<<<< HEAD stratus = { version = ">= 3.0.0 and < 4.0.0" } diff --git a/src/grom.gleam b/src/grom.gleam index 1371b03..904ad0e 100644 --- a/src/grom.gleam +++ b/src/grom.gleam @@ -17,7 +17,7 @@ import gleam/time/calendar import gleam/time/duration.{type Duration} import gleam/time/timestamp.{type Timestamp} import gleam_community/colour.{type Colour} -import json_value + import status_code const version: String = "v6.0.0" @@ -645,21 +645,50 @@ pub type ErrorResponse { code: Int, /// User-friendly message briefly explaining what error happened. message: String, - /// This contains a JSON string that is best not parsed. I recommend just printing/logging it if needed. - /// It contains detailed information regarding what error happened. - /// It would be nearly impossible to properly parse it. It is also sometimes absent from the response. - errors: Option(String), + /// Contains a tree of errors + errors: Option(ErrorNode), ) } +pub type ErrorNode { + ErrorNode(List(ErrorItem)) + ErrorBranch(Dict(String, ErrorNode)) +} + +fn error_node_decoder() -> Decoder(ErrorNode) { + use <- decode.recursive + + let leaf = { + use errors <- decode.field("_errors", decode.list(field_error_decoder())) + decode.success(ErrorNode(errors)) + } + + let branch = + decode.dict(decode.string, error_node_decoder()) + |> decode.map(ErrorBranch) + + decode.one_of(leaf, or: [branch]) +} + +pub type ErrorItem { + ErrorItem(code: Int, message: String) +} + +fn field_error_decoder() -> Decoder(ErrorItem) { + use code <- decode.field("code", decode.int) + use message <- decode.field("message", decode.string) + decode.success(ErrorItem(code:, message:)) +} + fn error_response_decoder() -> Decoder(ErrorResponse) { use code <- decode.field("code", decode.int) use message <- decode.field("message", decode.string) use errors <- decode.optional_field( "errors", None, - decode.optional(decode.map(json_value.decoder(), json_value.to_string)), + decode.optional(error_node_decoder()), ) + decode.success(ErrorResponse(code:, message:, errors:)) }