2016-12-03 2 views
2

Я делаю запрос JSON к веб-API о книгах. Мои ответы обычно выглядят какМогу ли я использовать значения по умолчанию в декодере JSON?

{ 
    "status": "successful", 
    "author": "Roald Dahl", 
    "title": "Charlie and the Chocolate Factory" 
} 

Так что я декодировать его в Book типа, используя автора и название поля.

Но иногда, запрашиваемая книга не будет находиться в базе данных, поэтому мой ответ просто

{ 
    "status": "failed" 
} 

В этом случае я бы еще посмотреть, чтобы вернуть Book типа, но с автором и названием установлен на «NOT FOUND».

Я читаю документацию JSON, но я не уверен, что что-то там мне помогает или я могу сделать это в Elm простым способом. По достоинству оцените некоторые советы.

ответ

2

Вы можете использовать Json.Decode.oneOf. Просто напишите декодер для обоих корпусов и дайте oneOf объединить их.

редактировать реагировать с комментарием

Использование oneOf является общим способом обработки обработки нескольких возможностей. Но вот пример кода, который я бы закодировал в соответствии с требованием, которое вы указали.

type Book 
    = Book 
     { author : String 
     , title : String 
     } 


fallBackBook = 
    Book 
     { author = "NOT FOUND" 
     , title = "NOT FOUND" 
     } 


decode : String -> Book 
decode str = 
    let 
     decoder = 
      Json.map3 (,,) 
       (Json.field "status" Json.string) 
       (Json.field "author" Json.string) 
       (Json.field "title" Json.string) 
    in 
     case Json.decodeString decoder str of 
      Ok ("successful", author, title) -> 
       Book { author = author, title = title } 

      _ -> 
       fallBackBook 

Или, вы можете создать еще одно значение, которое представляет NotFound «Книга не была найдена» состояние. Я считаю, что это способ вяза, и рекомендую.

type Book 
    = Book 
     { author : String 
     , title : String 
     } 
    | NotFound 


bookDecoder : Json.Decoder Book 
bookDecoder = 
    Json.map2 (\x y -> Book { author = x, title = y }) 
     (Json.field "author" Json.string) 
     (Json.field "title" Json.string) 


decode : String -> Book 
decode str = 
    Json.decodeString bookDecoder str 
     |> Result.withDefault NotFound 
+0

Как указать значения по умолчанию в одном из декодеров, которые в них нуждаются? Может ли ваш ответ показать два декодера, возможно, с помощью Json.Decode.map3? – Bezewy

2

Вы можете использовать Json.Decode.oneOf и добавить Json.Decode.succeed "NOT FOUND" как последний вариант, а лучше использование Json.Decode.andThen, сначала декодировать состояния, а затем произвести Maybe Book (Just Book если статус успешный и Nothing если это не удалось)

Если есть несколько способов, это может привести к сбою, вы можете использовать Result вместо Maybe.

0

Вы также можете использовать функцию optional у Evan's Json.Decode.Pipeline.

Тогда вы можете написать это:

type alias User = 
    { id : Int 
    , name : String 
    , email : String 
    } 


userDecoder : Decoder User 
userDecoder = 
    decode User 
    |> required "id" int 
    |> optional "name" string "blah" 
    |> required "email" string 
0

В этом случае я хотел бы предложить, что ваш автор и название будет иметь Maybe String типа. И «NOT FOUND» будет выбором дисплея в случае Nothing. Так что это было бы примерно так:

type Book = 
    { status: String 
    , author: Maybe String 
    , title: Maybe String 
    } 

... 

loadSuccessDecoder : Json.Decode.Decoder Book 
loadSuccessDecoder = 
    Json.Decode.map3 Book 
     (Json.Decode.field "status" Json.Decode.String) 
     (Json.Decode.maybe (Json.Decode.field "author" Json.Decode.string)) 
     (Json.Decode.maybe (Json.Decode.field "title" Json.Decode.string)) 

Все остальное, я думаю, должно быть выбором дисплея.

Смежные вопросы