Skip to content

Commit

Permalink
Replace giphy API with dog API in CatGifReactHooks and `CatGifHalog…
Browse files Browse the repository at this point in the history
…enHooks` recipes (#304)

* Use dog.ceo API in stead of giphy.com

* Update filenames, README

* Replace giphy API with dog.ceo in Halogen recipe

* Remove links to Elm example in DogImages recipes

---------

Co-authored-by: Peter Murphy <[email protected]>
  • Loading branch information
pete-murphy and pete-murphy authored Aug 11, 2023
1 parent 7992e8e commit 0dbd2c9
Show file tree
Hide file tree
Showing 18 changed files with 105 additions and 114 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,8 +98,6 @@ Running a web-compatible recipe:
| :heavy_check_mark: | | [CapabilityPatternNode](recipes/CapabilityPatternNode) | A skeletal version of an application structuring pattern |
| | :heavy_check_mark: ([try](https://try.purescript.org/?github=/JordanMartinez/purescript-cookbook/master/recipes/CardsHalogenHooks/src/Main.purs)) | [CardsHalogenHooks](recipes/CardsHalogenHooks) | A Halogen port of the ["Random - Cards" Elm Example](https://elm-lang.org/examples/cards). |
| | :heavy_check_mark: ([try](https://try.purescript.org/?github=/JordanMartinez/purescript-cookbook/master/recipes/CardsReactHooks/src/Main.purs)) | [CardsReactHooks](recipes/CardsReactHooks) | A React port of the ["Random - Cards" Elm Example](https://elm-lang.org/examples/cards). |
| | :heavy_check_mark: ([try](https://try.purescript.org/?github=/JordanMartinez/purescript-cookbook/master/recipes/CatGifsHalogenHooks/src/Main.purs)) | [CatGifsHalogenHooks](recipes/CatGifsHalogenHooks) | A Halogen port of the ["HTTP - Cat GIFs" Elm Example](https://elm-lang.org/examples/cat-gifs). |
| | :heavy_check_mark: ([try](https://try.purescript.org/?github=/JordanMartinez/purescript-cookbook/master/recipes/CatGifsReactHooks/src/Main.purs)) | [CatGifsReactHooks](recipes/CatGifsReactHooks) | A React port of the ["HTTP - Cat GIFs" Elm Example](https://elm-lang.org/examples/cat-gifs). |
| | :heavy_check_mark: ([try](https://try.purescript.org/?github=/JordanMartinez/purescript-cookbook/master/recipes/ClockReactHooks/src/Main.purs)) | [ClockReactHooks](recipes/ClockReactHooks) | A React port of the ["User Interface - Clock" Elm Example](https://elm-lang.org/examples/clock). |
| | :heavy_check_mark: ([try](https://try.purescript.org/?github=/JordanMartinez/purescript-cookbook/master/recipes/ComponentsHalogenHooks/src/Main.purs)) | [ComponentsHalogenHooks](recipes/ComponentsHalogenHooks) | Demonstrates how to nest one Halogen-Hooks-based component inside another and send/receive queries between the two. |
| | :heavy_check_mark: ([try](https://try.purescript.org/?github=/JordanMartinez/purescript-cookbook/master/recipes/ComponentsInputHalogenHooks/src/Main.purs)) | [ComponentsInputHalogenHooks](recipes/ComponentsInputHalogenHooks) | Each time a parent re-renders, it will pass a new input value into the child, and the child will update accordingly. |
Expand All @@ -111,6 +109,8 @@ Running a web-compatible recipe:
| :heavy_check_mark: | :heavy_check_mark: ([try](https://try.purescript.org/?github=/JordanMartinez/purescript-cookbook/master/recipes/DebuggingLog/src/Main.purs)) | [DebuggingLog](recipes/DebuggingLog) | This recipe shows how to do print-debugging using the `Debug` module's `spy` and `traceM` functions. The compiler will emit warnings to remind you to remove these debug functions before you ship production code. |
| :heavy_check_mark: | | [DiceCLI](recipes/DiceCLI) | This recipe shows how to create an interactive command line prompt that repeatedly generates a random number between 1 and 6. |
| :heavy_check_mark: | :heavy_check_mark: ([try](https://try.purescript.org/?github=/JordanMartinez/purescript-cookbook/master/recipes/DiceLog/src/Main.purs)) | [DiceLog](recipes/DiceLog) | This recipe shows how to log a random integer between 1 and 6 (representing a roll of a die) in either the node.js or web browser console. |
| | :heavy_check_mark: ([try](https://try.purescript.org/?github=/JordanMartinez/purescript-cookbook/master/recipes/DogImagesHalogenHooks/src/Main.purs)) | [DogImagesHalogenHooks](recipes/DogImagesHalogenHooks) | Fetches random dog images from the [Dog API](https://dog.ceo/dog-api/). |
| | :heavy_check_mark: ([try](https://try.purescript.org/?github=/JordanMartinez/purescript-cookbook/master/recipes/DogImagesReactHooks/src/Main.purs)) | [DogImagesReactHooks](recipes/DogImagesReactHooks) | Fetches random dog images from the [Dog API](https://dog.ceo/dog-api/). |
| | :heavy_check_mark: ([try](https://try.purescript.org/?github=/JordanMartinez/purescript-cookbook/master/recipes/DragAndDropHalogenHooks/src/Main.purs)) | [DragAndDropHalogenHooks](recipes/DragAndDropHalogenHooks) | A Halogen port of the ["Files - Drag-and-Drop" Elm Example](https://elm-lang.org/examples/drag-and-drop). |
| | :heavy_check_mark: ([try](https://try.purescript.org/?github=/JordanMartinez/purescript-cookbook/master/recipes/DragAndDropReactHooks/src/Main.purs)) | [DragAndDropReactHooks](recipes/DragAndDropReactHooks) | A React port of the ["Files - Drag-and-Drop" Elm Example](https://elm-lang.org/examples/drag-and-drop). |
| | :heavy_check_mark: ([try](https://try.purescript.org/?github=/JordanMartinez/purescript-cookbook/master/recipes/FileUploadHalogenHooks/src/Main.purs)) | [FileUploadHalogenHooks](recipes/FileUploadHalogenHooks) | A Halogen port of the ["Files - Upload" Elm Example](https://elm-lang.org/examples/upload). |
Expand Down
9 changes: 0 additions & 9 deletions recipes/CatGifsHalogenHooks/README.md

This file was deleted.

13 changes: 0 additions & 13 deletions recipes/CatGifsHalogenHooks/web/index.html

This file was deleted.

4 changes: 0 additions & 4 deletions recipes/CatGifsHalogenHooks/web/index.js

This file was deleted.

16 changes: 0 additions & 16 deletions recipes/CatGifsReactHooks/README.md

This file was deleted.

4 changes: 0 additions & 4 deletions recipes/CatGifsReactHooks/web/index.js

This file was deleted.

File renamed without changes.
9 changes: 9 additions & 0 deletions recipes/DogImagesHalogenHooks/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# CatGifsHalogenHooks

Fetches random dog images from the [Dog API](https://dog.ceo/dog-api/).

## Expected Behavior:

### Browser

The browser will display "Loading..." and then display a dog image with a button that will display the next random dog image if the HTTP request succeeds or an error message along with the same button if it fails.
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{ name = "CatGifsHalogenHooks"
{ name = "DogImagesHalogenHooks"
, dependencies =
[ "aff"
, "affjax"
Expand All @@ -19,5 +19,5 @@
, "tuples"
]
, packages = ../../packages.dhall
, sources = [ "recipes/CatGifsHalogenHooks/src/**/*.purs" ]
, sources = [ "recipes/DogImagesHalogenHooks/src/**/*.purs" ]
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
module CatGifsHalogenHooks.Main where
module DogImagesHalogenHooks.Main where

import Prelude

import Affjax.ResponseFormat as AXRF
import Affjax.StatusCode (StatusCode(..))
import Affjax.Web as AX
import CSS (block, display)
import CSS (block, display, marginBottom, maxWidth, px, rem)
import Data.Argonaut.Core (Json)
import Data.Codec (decode)
import Data.Codec.Argonaut (JsonDecodeError)
Expand Down Expand Up @@ -41,64 +41,66 @@ hookComponent = Hooks.component \_ _ -> Hooks.do
content /\ contentIdx <- Hooks.useState RD.NotAsked

let
getNextGif = do
getNextImage = do
Hooks.put contentIdx RD.Loading
errorOrResponse <- liftAff $ AX.request $ AX.defaultRequest
{ url = "https://api.giphy.com/v1/gifs/random?api_key=dc6zaTOxFJmzC&tag=cat"
{ url = "https://dog.ceo/api/breeds/image/random"
, method = Left GET
, responseFormat = AXRF.json
}
let
httpResult = case errorOrResponse of
Right jsonRec | jsonRec.status == StatusCode 200 ->
case decodeJson jsonRec.body of
Right rec -> RD.Success rec.data.images.downsized.url
Right rec -> RD.Success rec.message
_ -> RD.Failure "decode error"
_ ->
RD.Failure "http error"

Hooks.put contentIdx httpResult

Hooks.useLifecycleEffect do
getNextGif
getNextImage
pure Nothing

Hooks.pure $
HH.div_
[ HH.h2_ [ HH.text "Random Cats" ]
[ HH.h2_ [ HH.text "Random Dogs" ]
, case content of
RD.NotAsked ->
HH.text "Loading page..."
RD.Loading ->
HH.text "Loading..."
RD.Failure _ ->
RD.Failure reason ->
HH.div_
[ HH.text "I could not load a random cat for some reason. "
[ HH.text "I could not load a random dog for some reason. "
, HH.pre_ [ HH.text reason ]
, HH.button
[ HE.onClick \_ -> getNextGif
]
[ HE.onClick \_ -> getNextImage ]
[ HH.text "Try Again!" ]
]

RD.Success url ->
HH.div_
[ HH.button
[ HE.onClick \_ -> getNextGif
, HC.style $ display block
[ HE.onClick \_ -> getNextImage
, HC.style do
display block
marginBottom (1.0 # rem)
]
[ HH.text "More Please!" ]
, HH.img [ HP.src url ]
, HH.img
[ HP.src url
, HC.style do
maxWidth (400.0 # px)
]
]
]

decodeJson :: Json -> Either JsonDecodeError { data :: { images :: { downsized :: { url :: String } } } }
decodeJson :: Json -> Either JsonDecodeError { message :: String, status :: String }
decodeJson = decode
$ CA.object "data"
$ CA.object "response"
$ CAR.record
{ data: CA.object "images" $ CAR.record
{ images: CA.object "downsized" $ CAR.record
{ downsized: CA.object "url" $ CAR.record
{ url: CA.string }
}
}
{ message: CA.string
, status: CA.string
}
11 changes: 11 additions & 0 deletions recipes/DogImagesHalogenHooks/web/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>DogImagesHalogenHooks</title>
</head>

<body>
<script type="module" src="./index.js"></script>
</body>
</html>
4 changes: 4 additions & 0 deletions recipes/DogImagesHalogenHooks/web/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
"use strict";
import { main } from "../../../output/DogImagesHalogenHooks.Main/index.js";

main();
File renamed without changes.
14 changes: 14 additions & 0 deletions recipes/DogImagesReactHooks/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# DogImagesReactHooks

Fetches random dog images from the [Dog API](https://dog.ceo/dog-api/).

## Expected Behavior:

### Browser

The browser will display "Loading..." and then display a dog image with a button that will display the next random dog image if the HTTP request succeeds or an error message along with the same button if it fails.

## Dependencies Used:

[react](https://www.npmjs.com/package/react)
[react-dom](https://www.npmjs.com/package/react-dom)
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
{ name = "CatGifsReactHooks"
{ name = "DogImagesReactHooks"
, dependencies =
[ "aff"
, "affjax"
, "affjax-web"
, "argonaut-codecs"
, "bifunctors"
, "effect"
, "either"
, "exceptions"
Expand All @@ -16,5 +17,5 @@
, "web-html"
]
, packages = ../../packages.dhall
, sources = [ "recipes/CatGifsReactHooks/src/**/*.purs" ]
, sources = [ "recipes/DogImagesReactHooks/src/**/*.purs" ]
}
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
module CatGifsReactHooks.Main where
module DogImagesReactHooks.Main where

import Prelude

import Affjax.ResponseFormat as ResponseFormat
import Affjax.Web as Affjax
import Data.Argonaut.Decode (decodeJson)
import Data.Argonaut.Decode.Combinators ((.:))
import Data.Either (hush)
import Data.Maybe (Maybe(..), maybe)
import Data.Argonaut.Decode (decodeJson, printJsonDecodeError)
import Data.Bifunctor (lmap)
import Data.Either (Either(..))
import Data.Maybe (Maybe(..))
import Effect (Effect)
import Effect.Aff (Aff)
import Effect.Exception (throw)
import React.Basic.DOM (css)
import React.Basic.DOM as R
import React.Basic.DOM.Client (createRoot, renderRoot)
import React.Basic.Events (handler_)
Expand All @@ -24,11 +23,6 @@ import Web.HTML (window)
import Web.HTML.HTMLDocument (toNonElementParentNode)
import Web.HTML.Window (document)

data GifState
= Failure
| Loading
| Success String

main :: Effect Unit
main = do
doc <- document =<< window
Expand All @@ -42,48 +36,46 @@ main = do

mkApp :: Component {}
mkApp = do
component "CatGifs" \_ -> React.do
(resetToken /\ reset) <- useResetToken
gifState <- toGifState <$> useAff resetToken getRandomCatGif
let onClick = handler_ reset
component "DogImages" \_ -> React.do
resetToken /\ reset <- useResetToken
response <- useAff resetToken getRandomCatGif

let
onClick = handler_ reset

pure
$ R.div_
[ R.h2_ [ R.text "Random Cats" ]
, case gifState of
Loading -> R.text "Loading..."
Failure ->
[ R.h2_ [ R.text "Random Dogs" ]
, case response of
Nothing -> R.text "Loading..."
Just (Left reason) ->
R.div_
[ R.text "I could not load a random cat for some reason."
[ R.text "I could not load a random dog for some reason."
, R.pre_ [ R.text reason ]
, R.button { onClick, children: [ R.text "Try Again!" ] }
]
Success url ->
Just (Right url) ->
R.div_
[ R.button
{ onClick
, style: css { display: "block" }
, style: R.css { display: "block", marginBlock: "1rem" }
, children: [ R.text "More Please!" ]
}
, R.img { src: url }
, R.img { style: R.css { maxWidth: 400 }, src: url }
]
]

-- | Collapse nested `Maybe`s to our `GifState` type
toGifState :: Maybe (Maybe String) -> GifState
toGifState = maybe Loading (maybe Failure Success)

getRandomCatGif :: Aff (Maybe String)
getRandomCatGif :: Aff (Either String String)
getRandomCatGif = do
response <-
Affjax.get
ResponseFormat.json
"https://api.giphy.com/v1/gifs/random?api_key=dc6zaTOxFJmzC&tag=cat"
pure do
-- Using `hush` to ignore the possible error messages
{ body } <- hush response
hush
( decodeJson body
>>= (_ .: "data")
>>= (_ .: "images")
>>= (_ .: "downsized")
>>= (_ .: "url")
)
"https://dog.ceo/api/breeds/image/random"
let
decodedResult = do
{ body } <- lmap Affjax.printError response
decodedBody :: { message :: String, status :: String } <-
lmap printJsonDecodeError (decodeJson body)
if decodedBody.status == "success" then Right decodedBody.message
else Left (show decodedBody)
pure decodedResult
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<html>
<head>
<meta charset="UTF-8" />
<title>CatGifsReactHooks</title>
<title>DogImagesReactHooks</title>
</head>

<body>
Expand Down
4 changes: 4 additions & 0 deletions recipes/DogImagesReactHooks/web/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
"use strict";
import { main } from "../../../output/DogImagesReactHooks.Main/index.js";

main();

0 comments on commit 0dbd2c9

Please sign in to comment.