Skip to content

Commit 347466f

Browse files
committed
Use gleam/dynamic/decode module for decoding JSON
1 parent 12c7203 commit 347466f

File tree

5 files changed

+85
-78
lines changed

5 files changed

+85
-78
lines changed

README.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ Further documentation can be found at <https://hexdocs.pm/fiber>.
2929
## Client Example
3030

3131
```gleam
32-
import gleam/dynamic
32+
import gleam/dynamic/decode
3333
import gleam/json
3434
import gleeunit/should
3535
@@ -45,7 +45,7 @@ fn start_client(fiber) {
4545
fn ping() {
4646
request.new(method: "ping")
4747
// We expect "pong" from this, so we can decode the result into a string.
48-
|> request.with_decoder(dynamic.string)
48+
|> request.with_decoder(decode.string)
4949
}
5050
5151
fn file_updated(file_name) {
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
---
2-
version: 1.2.3
2+
version: 1.2.6
33
title: invalid request error message
44
file: ./test/message_test.gleam
55
test_name: invalid_message_test
66
---
7-
UnexpectedFormat([DecodeError("another type", "Dict", [])])
7+
UnableToDecode([DecodeError("Message", "Dict", [])])

src/fiber.gleam

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import gleam/dict
22
import gleam/dynamic.{type Dynamic}
3+
import gleam/dynamic/decode
34
import gleam/erlang/process
45
import gleam/list
56
import gleam/option
@@ -64,7 +65,7 @@ pub fn server_only(builder: backend.FiberBuilder) -> backend.FiberBuilder {
6465

6566
pub type RequestError(a) {
6667
ReturnedError(message.ErrorData(Dynamic))
67-
DecodeError(dynamic.DecodeErrors)
68+
DecodeError(List(decode.DecodeError))
6869
CallError(process.CallError(a))
6970
}
7071

@@ -85,7 +86,7 @@ pub fn call(
8586
|> result.map(fn(call_result) {
8687
call_result
8788
|> result.map(fn(data) {
88-
request.decoder(data)
89+
decode.run(data, request.decoder)
8990
|> result.map_error(DecodeError)
9091
})
9192
|> result.map_error(ReturnedError)

src/fiber/message.gleam

+74-69
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import gleam/dynamic.{type Dynamic}
2+
import gleam/dynamic/decode
23
import gleam/json.{type Json}
34
import gleam/option.{type Option}
45
import gleam/pair
@@ -35,87 +36,91 @@ pub type Message(dyn) {
3536
BatchResponseMessage(List(Response(dyn)))
3637
}
3738

38-
fn id_decoder() {
39-
dynamic.any([
40-
fn(data) { dynamic.int(data) |> result.map(IntId) },
41-
fn(data) { dynamic.string(data) |> result.map(StringId) },
39+
fn id_decoder() -> decode.Decoder(Id) {
40+
decode.one_of(decode.int |> decode.map(IntId), [
41+
decode.string |> decode.map(StringId),
4242
])
43+
|> decode.collapse_errors("Id")
4344
}
4445

45-
fn error_data_decoder() {
46-
dynamic.any([
47-
fn(v) { dynamic.string(v) |> result.map(ErrorString) },
48-
dynamic.decode3(
49-
ErrorData,
50-
dynamic.optional_field("data", dynamic.dynamic),
51-
dynamic.field("code", dynamic.int),
52-
dynamic.field("message", dynamic.string),
53-
),
54-
])
55-
}
56-
57-
fn request_decoder() {
58-
dynamic.any([
59-
dynamic.decode3(
60-
Request,
61-
dynamic.optional_field("params", dynamic.dynamic),
62-
dynamic.field("method", dynamic.string),
63-
dynamic.field("id", id_decoder()),
64-
),
65-
dynamic.decode2(
66-
Notification,
67-
dynamic.optional_field("params", dynamic.dynamic),
68-
dynamic.field("method", dynamic.string),
69-
),
70-
])
71-
}
72-
73-
fn response_decoder() {
74-
dynamic.any([
75-
dynamic.decode2(
76-
SuccessResponse,
77-
dynamic.field("result", dynamic.dynamic),
78-
dynamic.field("id", id_decoder()),
79-
),
80-
dynamic.decode2(
81-
ErrorResponse,
82-
dynamic.field("error", error_data_decoder()),
83-
dynamic.field("id", id_decoder()),
84-
),
46+
fn error_data_decoder() -> decode.Decoder(ErrorData(Dynamic)) {
47+
decode.one_of(decode.string |> decode.map(ErrorString), [
48+
{
49+
use data <- decode.optional_field(
50+
"data",
51+
option.None,
52+
decode.optional(decode.dynamic),
53+
)
54+
use code <- decode.field("code", decode.int)
55+
use message <- decode.field("message", decode.string)
56+
decode.success(ErrorData(data, code, message))
57+
},
8558
])
59+
|> decode.collapse_errors("ErrorData")
8660
}
8761

88-
fn error_decoder() {
89-
dynamic.field("error", error_data_decoder())
90-
}
91-
92-
fn message_decoder() {
93-
dynamic.any([
94-
fn(d) {
95-
response_decoder()(d)
96-
|> result.map(ResponseMessage)
97-
},
98-
fn(d) {
99-
request_decoder()(d)
100-
|> result.map(RequestMessage)
101-
},
102-
fn(d) {
103-
error_decoder()(d)
104-
|> result.map(ErrorMessage)
105-
},
106-
fn(d) {
107-
dynamic.list(request_decoder())(d)
108-
|> result.map(BatchRequestMessage)
62+
fn request_decoder() -> decode.Decoder(Request(Dynamic)) {
63+
decode.one_of(
64+
{
65+
use params <- decode.optional_field(
66+
"params",
67+
option.None,
68+
decode.optional(decode.dynamic),
69+
)
70+
use method <- decode.field("method", decode.string)
71+
use id <- decode.field("id", id_decoder())
72+
decode.success(Request(params, method, id))
10973
},
110-
fn(d) {
111-
dynamic.list(response_decoder())(d)
112-
|> result.map(BatchResponseMessage)
74+
[
75+
{
76+
use params <- decode.optional_field(
77+
"params",
78+
option.None,
79+
decode.optional(decode.dynamic),
80+
)
81+
use method <- decode.field("method", decode.string)
82+
decode.success(Notification(params, method))
83+
},
84+
],
85+
)
86+
|> decode.collapse_errors("Request")
87+
}
88+
89+
fn response_decoder() -> decode.Decoder(Response(Dynamic)) {
90+
decode.one_of(
91+
{
92+
use result <- decode.field("result", decode.dynamic)
93+
use id <- decode.field("id", id_decoder())
94+
decode.success(SuccessResponse(result, id))
11395
},
96+
[
97+
{
98+
use error <- decode.field("error", error_data_decoder())
99+
use id <- decode.field("id", id_decoder())
100+
decode.success(ErrorResponse(error, id))
101+
},
102+
],
103+
)
104+
|> decode.collapse_errors("Response")
105+
}
106+
107+
fn error_decoder() -> decode.Decoder(ErrorData(Dynamic)) {
108+
use error <- decode.field("error", error_data_decoder())
109+
decode.success(error)
110+
}
111+
112+
fn message_decoder() -> decode.Decoder(Message(Dynamic)) {
113+
decode.one_of(response_decoder() |> decode.map(ResponseMessage), [
114+
request_decoder() |> decode.map(RequestMessage),
115+
error_decoder() |> decode.map(ErrorMessage),
116+
decode.list(request_decoder()) |> decode.map(BatchRequestMessage),
117+
decode.list(response_decoder()) |> decode.map(BatchResponseMessage),
114118
])
119+
|> decode.collapse_errors("Message")
115120
}
116121

117122
pub fn decode(text: String) -> Result(Message(Dynamic), json.DecodeError) {
118-
json.decode(text, message_decoder())
123+
json.parse(text, message_decoder())
119124
}
120125

121126
pub fn from_json(text: String) -> Result(Message(Dynamic), json.DecodeError) {

src/fiber/request.gleam

+4-3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import gleam/dynamic.{type Dynamic}
2+
import gleam/dynamic/decode
23
import gleam/json.{type Json}
34
import gleam/option.{type Option}
45
import youid/uuid
@@ -9,7 +10,7 @@ pub type Request(return) {
910
Request(
1011
method: String,
1112
params: Option(Json),
12-
decoder: dynamic.Decoder(return),
13+
decoder: decode.Decoder(return),
1314
id: Option(message.Id),
1415
)
1516
}
@@ -18,7 +19,7 @@ pub fn new(method method: String) -> Request(Dynamic) {
1819
Request(
1920
method:,
2021
params: option.None,
21-
decoder: dynamic.dynamic,
22+
decoder: decode.dynamic,
2223
id: option.None,
2324
)
2425
}
@@ -29,7 +30,7 @@ pub fn with_params(request: Request(a), params: Json) -> Request(a) {
2930

3031
pub fn with_decoder(
3132
request: Request(a),
32-
decoder decoder: dynamic.Decoder(b),
33+
decoder decoder: decode.Decoder(b),
3334
) -> Request(b) {
3435
Request(
3536
method: request.method,

0 commit comments

Comments
 (0)