1

I've started with Elm and want to get images from Trefle API when searched for plant but I keep getting the "Could not fetch image" error. I do use my own access token but I replaced it here with "MY_API_TOKEN" to keep it private. Can you help me to understand the problem in my code?

I've tried to get a more detailed error message but then my code crashed because I am quite new with using elm and in the web development field.

module Main exposing (..)

import Browser
import Html exposing (Html, button, div, img, input, text)
import Html.Attributes exposing (placeholder, src, type_)
import Html.Events exposing (onClick, onInput)
import Http
import Json.Decode exposing (Decoder, field, list, string)
import Maybe exposing (withDefault, map)


type alias Model =
    { searchTerm : String
    , imageUrl : String
    , error : String
    }


init : () -> ( Model, Cmd Msg )
init _ =
    ( { searchTerm = "", imageUrl = "", error = "" }, Cmd.none )


type Msg
    = UpdateSearchTerm String
    | FetchImage
    | ReceiveImage (Result Http.Error String)


update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
    case msg of
        UpdateSearchTerm term ->
            ( { model | searchTerm = term }, Cmd.none )

        FetchImage ->
            ( model, fetchPlantImage model.searchTerm )

        ReceiveImage result ->
            case result of
                Ok url ->
                    ( { model | imageUrl = url, error = "" }, Cmd.none )

                Err _ ->
                    ( { model | error = "Failed to fetch image." }, Cmd.none )


view : Model -> Html Msg
view model =
    div []
        [ input [ placeholder "Enter plant name", onInput UpdateSearchTerm ] []
        , button [ onClick FetchImage ] [ text "Search" ]
        , if model.imageUrl /= "" then
            img [ src model.imageUrl ] []
          else
            text ""
        , if model.error /= "" then
            div [] [ text model.error ]
          else
            text ""
        ]


fetchPlantImage : String -> Cmd Msg
fetchPlantImage searchTerm =
    let
        url =
            "https://trefle.io/api/v1/plants/search?token=MY_API_TOKEN&q=" ++ searchTerm

        decodeImageUrl : Decoder String
        decodeImageUrl =
            field "data" (list (field "image_url" string))
                |> Json.Decode.map (withDefault "" << map identity << List.head)
    in
    Http.get
        { url = url
        , expect = Http.expectJson ReceiveImage decodeImageUrl
        }


main : Program () Model Msg
main =
    Browser.element
        { init = init
        , update = update
        , subscriptions = \_ -> Sub.none
        , view = view
        }
1
  • Can you post the exact error message? Commented Jun 15, 2024 at 15:55

1 Answer 1

3

tl;dr

It appears trefle.io's SSL certificate has expired, so it's likely a problem on their end.

Details

The first thing I did was update your HTTP response handler to be more explicit when reporting the error (instead of just "Failed to fetch image.")

...


update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
    case msg of
        ...

        ReceiveImage result ->
            case result of
                Ok url ->
                    ( { model | imageUrl = url, error = "" }, Cmd.none )

                Err err ->
                    ( { model
                        | error =
                            case err of
                                Http.BadUrl errorMessage ->
                                    errorMessage

                                Http.Timeout ->
                                    "Timeout"

                                Http.NetworkError ->
                                    "Network error"

                                Http.BadStatus status ->
                                    "Bad status " ++ String.fromInt status

                                Http.BadBody errorMessage ->
                                    errorMessage
                      }
                    , Cmd.none
                    )


...

Ellie: https://ellie-app.com/rqZy7NHmGrGa1

Once you do this, you'll see that the actual error is:

Network error

Implying the service is inaccessible.

Next I just attempted to access that URL using curl, which reports an error with the server's SSL certificat:

% curl "https://trefle.io/api/v1/plants/search?token=MY_API_TOKEN&q=coconut"
curl: (60) SSL certificate problem: certificate has expired
More details here: https://curl.haxx.se/docs/sslcerts.html

curl performs SSL certificate verification by default, using a "bundle"
 of Certificate Authority (CA) public keys (CA certs). If the default
 bundle file isn't adequate, you can specify an alternate file
 using the --cacert option.
If this HTTPS server uses a certificate signed by a CA represented in
 the bundle, the certificate verification probably failed due to a
 problem with the certificate (it might be expired, or the name might
 not match the domain name in the URL).
If you'd like to turn off curl's verification of the certificate, use
 the -k (or --insecure) option.
HTTPS-proxy has similar options --proxy-cacert and --proxy-insecure.
Sign up to request clarification or add additional context in comments.

2 Comments

Looks like the certificate expired 4 days ago. Hopefully they'll resolve it soon.
as at "today" - still not fixed.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.