Skip to content

Instantly share code, notes, and snippets.

@mlms13
Created December 21, 2019 05:08
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mlms13/28f94e74e62127de8c81fa5aa7d784e7 to your computer and use it in GitHub Desktop.
Save mlms13/28f94e74e62127de8c81fa5aa7d784e7 to your computer and use it in GitHub Desktop.
Request Weather Data using Relude
open Relude.Globals;
let baseUrl = "http://localhost:5050";
// `getForecast` is an IO that will either succeed with decoded
// ForecastData or fail with a Fetch error.
//
// Since IO is inherently lazy, creating this value doesn't actually
// _do_ anything. Instead it needs to be run, which we do inside an
// `UpdateWithIO` return from a `useReducer` branch in our view.
let getForecast =
ReludeFetch.(
get(baseUrl ++ "/forecast/TOKEN/42.3601%2C-71.0589")
|> IO.flatMap(Response.StatusCode.ensure2xx)
|> IO.flatMap(Response.Json.decode(ForecastData.decode))
);
open Relude.Globals;
// We store our application state in a Relude AsyncResult, which is good at
// representing async data (that could fail) as a snapshot in time, using
// constructors like:
//
// - Init
// - Loading
// - Reloading(...)
// - Complete(Ok(...))
// - Complete(Error(...))
//
// If you've used RemoteData in Elm or PureScript, you may recognize this,
// but we capture failure with a Result and add a Reloading state
type state = AsyncResult.t(ForecastData.t, string);
type action =
| MakeRequest
| Succeed(ForecastData.t)
| Fail(string);
[@react.component]
let make = () => {
open ReludeReact;
let (state, dispatch) =
Reducer.useReducer(
_state =>
fun
| Succeed(data) => Update(AsyncResult.ok(data))
| Fail(err) => Update(AsyncResult.error(err))
| MakeRequest =>
UpdateWithIO(
Loading,
Api.getForecast()
|> IO.map(data => Succeed(data))
|> IO.mapError(ReludeFetch.Error.show(_ => "Decode failure"))
|> IO.mapError(err => Fail(err)),
),
Init,
);
switch (state) {
| Init =>
<button onClick={_ => dispatch(MakeRequest)}>
{React.string("Make Request!")}
</button>
| Loading
| Reloading(_) => React.string("loading")
| Complete(Ok({current, hourly})) => React.string(current.summary)
| Complete(Error(err)) => React.string("Something went wrong! " ++ err)
};
};
/**
* This module defines our data types (which are closely related
* to the data structure exposed by the DarkSky API). Additionally,
* we have some helpers to construct and decode values from JSON.
*/
module Conditions = {
type t = {
time: Js.Date.t,
summary: string,
icon: string, // TODO: enum of valid options
precipProbability: float,
temperature: float,
humidity: float,
};
let make = (time, summary, icon, precipProbability, temperature, humidity) => {
time,
summary,
icon,
precipProbability,
temperature,
humidity,
};
let decode =
Decode.AsResult.OfParseError.Pipeline.(
pure(make)
|> field("time", date)
|> field("summary", string)
|> field("icon", string)
|> field("precipProbability", floatFromNumber)
|> field("temperature", floatFromNumber)
|> field("humidity", floatFromNumber)
);
};
type t = {
current: Conditions.t,
hourly: list(Conditions.t),
};
let make = (current, hourly) => {current, hourly};
let decode =
Decode.AsResult.OfParseError.Pipeline.(
pure(make)
|> field("currently", Conditions.decode)
|> at(["hourly", "data"], list(Conditions.decode))
);
@r17x
Copy link

r17x commented Mar 9, 2020

@mlms13 anyway, how to use Relude.debounce with getForecast at this line https://gist.github.com/mlms13/28f94e74e62127de8c81fa5aa7d784e7#file-api-re-L11 or with case
user type in <input onChange={wantDebounceWithUpdateIO} />

Thanks before

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment