Add Task Chain + API setup
							parent
							
								
									2baf012345
								
							
						
					
					
						commit
						7935e112ed
					
				
							
								
								
									
										2
									
								
								elm.json
								
								
								
								
							
							
						
						
									
										2
									
								
								elm.json
								
								
								
								
							| 
						 | 
					@ -14,9 +14,11 @@
 | 
				
			||||||
    "elm-version": "0.19.0 <= v < 0.20.0",
 | 
					    "elm-version": "0.19.0 <= v < 0.20.0",
 | 
				
			||||||
    "dependencies": {
 | 
					    "dependencies": {
 | 
				
			||||||
        "elm/core": "1.0.0 <= v < 2.0.0",
 | 
					        "elm/core": "1.0.0 <= v < 2.0.0",
 | 
				
			||||||
 | 
					        "elm/http": "2.0.0 <= v < 3.0.0",
 | 
				
			||||||
        "elm/json": "1.0.0 <= v < 2.0.0",
 | 
					        "elm/json": "1.0.0 <= v < 2.0.0",
 | 
				
			||||||
        "elm/parser": "1.0.0 <= v < 2.0.0",
 | 
					        "elm/parser": "1.0.0 <= v < 2.0.0",
 | 
				
			||||||
        "elm/time": "1.0.0 <= v < 2.0.0",
 | 
					        "elm/time": "1.0.0 <= v < 2.0.0",
 | 
				
			||||||
 | 
					        "elm/url": "1.0.0 <= v < 2.0.0",
 | 
				
			||||||
        "micahhahn/elm-safe-recursion": "2.0.0 <= v < 3.0.0",
 | 
					        "micahhahn/elm-safe-recursion": "2.0.0 <= v < 3.0.0",
 | 
				
			||||||
        "miniBill/elm-fast-dict": "1.0.0 <= v < 2.0.0"
 | 
					        "miniBill/elm-fast-dict": "1.0.0 <= v < 2.0.0"
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,175 @@
 | 
				
			||||||
 | 
					module Internal.Api.Chain exposing (TaskChain, IdemChain, CompleteChain)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					{-|
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Task chains
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Elm uses a `Task` type to avoid issues that JavaScript deals with, yet the same
 | 
				
			||||||
 | 
					**callback hell** issue might appear that JavaScript developers often deal with.
 | 
				
			||||||
 | 
					For this reason, this module helps chain different `Task` types together such
 | 
				
			||||||
 | 
					that all information is stored and values are dealt with appropriately.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Elm's type checking system helps making this system sufficiently rigorous to
 | 
				
			||||||
 | 
					avoid leaking values passing through the API in unexpected ways.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@docs TaskChain, IdemChain, CompleteChain
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					-}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import Internal.Config.Log exposing (Log)
 | 
				
			||||||
 | 
					import Internal.Values.Context as Context exposing (APIContext)
 | 
				
			||||||
 | 
					import Task
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type alias Backpacked u a =
 | 
				
			||||||
 | 
					    { a | messages : List u, logs : List Log }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					{-| The TaskChain is a piece in the long chain of tasks that need to be completed.
 | 
				
			||||||
 | 
					The type defines four variables:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  - `err` value that may arise on an error
 | 
				
			||||||
 | 
					  - `u` the update msg that should be returned
 | 
				
			||||||
 | 
					  - `a` phantom type before executing the chain's context
 | 
				
			||||||
 | 
					  - `b` phantom type after executing the chain's context
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					-}
 | 
				
			||||||
 | 
					type alias TaskChain err u a b =
 | 
				
			||||||
 | 
					    APIContext a -> Task.Task (FailedChainPiece err u) (TaskChainPiece u a b)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					{-| An IdemChain is a TaskChain that does not influence the chain's context
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  - `err` value that may arise on an error
 | 
				
			||||||
 | 
					  - `u` the update msg that should be executed
 | 
				
			||||||
 | 
					  - `a` phantom type before, during and after the chain's context
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					-}
 | 
				
			||||||
 | 
					type alias IdemChain err u a =
 | 
				
			||||||
 | 
					    TaskChain err u a a
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					{-| A CompleteChain is a complete task chain where all necessary information
 | 
				
			||||||
 | 
					has been defined. In simple terms, whenever a Matrix API call is made, all
 | 
				
			||||||
 | 
					necessary information for that endpoint:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					1.  Was previously known and has been inserted, or
 | 
				
			||||||
 | 
					2.  Was acquired before actually making the API call.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					-}
 | 
				
			||||||
 | 
					type alias CompleteChain u =
 | 
				
			||||||
 | 
					    TaskChain Never u {} {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					{-| A TaskChainPiece is a piece that updates the chain's context.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Once a chain is executed, the process will add the `messages` value to its list
 | 
				
			||||||
 | 
					of updates, and it will update its context according to the `contextChange`
 | 
				
			||||||
 | 
					function.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					-}
 | 
				
			||||||
 | 
					type alias TaskChainPiece u a b =
 | 
				
			||||||
 | 
					    Backpacked u { contextChange : APIContext a -> APIContext b }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					{-| A FailedChainPiece initiates an early breakdown of a chain. Unless caught,
 | 
				
			||||||
 | 
					this halts execution of the chain. The process will add the `messages` value to
 | 
				
			||||||
 | 
					its list of updates, and it will return the given `err` value for a direct
 | 
				
			||||||
 | 
					explanation of what went wrong.
 | 
				
			||||||
 | 
					-}
 | 
				
			||||||
 | 
					type alias FailedChainPiece err u =
 | 
				
			||||||
 | 
					    Backpacked u { error : err }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					{-| Chain two tasks together. The second task will only run if the first one
 | 
				
			||||||
 | 
					succeeds.
 | 
				
			||||||
 | 
					-}
 | 
				
			||||||
 | 
					andThen : TaskChain err u b c -> TaskChain err u a b -> TaskChain err u a c
 | 
				
			||||||
 | 
					andThen f2 f1 =
 | 
				
			||||||
 | 
					    \context ->
 | 
				
			||||||
 | 
					        f1 context
 | 
				
			||||||
 | 
					            |> Task.andThen
 | 
				
			||||||
 | 
					                (\old ->
 | 
				
			||||||
 | 
					                    context
 | 
				
			||||||
 | 
					                        |> old.contextChange
 | 
				
			||||||
 | 
					                        |> f2
 | 
				
			||||||
 | 
					                        |> Task.map
 | 
				
			||||||
 | 
					                            (\new ->
 | 
				
			||||||
 | 
					                                { contextChange = old.contextChange >> new.contextChange
 | 
				
			||||||
 | 
					                                , logs = List.append old.logs new.logs
 | 
				
			||||||
 | 
					                                , messages = List.append old.messages new.messages
 | 
				
			||||||
 | 
					                                }
 | 
				
			||||||
 | 
					                            )
 | 
				
			||||||
 | 
					                        |> Task.mapError
 | 
				
			||||||
 | 
					                            (\new ->
 | 
				
			||||||
 | 
					                                { error = new.error
 | 
				
			||||||
 | 
					                                , logs = List.append old.logs new.logs
 | 
				
			||||||
 | 
					                                , messages = List.append old.messages new.messages
 | 
				
			||||||
 | 
					                                }
 | 
				
			||||||
 | 
					                            )
 | 
				
			||||||
 | 
					                )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					{-| When an error has occurred, "fix" it with an artificial task chain result.
 | 
				
			||||||
 | 
					-}
 | 
				
			||||||
 | 
					catchWith : (err -> TaskChainPiece u a b) -> TaskChain err u a b -> TaskChain err u a b
 | 
				
			||||||
 | 
					catchWith onErr f =
 | 
				
			||||||
 | 
					    onError (\e -> succeed <| onErr e) f
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					{-| Creates a task that always fails.
 | 
				
			||||||
 | 
					-}
 | 
				
			||||||
 | 
					fail : err -> TaskChain err u a b
 | 
				
			||||||
 | 
					fail e _ =
 | 
				
			||||||
 | 
					    Task.fail { error = e, logs = [], messages = [] }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					{-| Optionally run a task that doesn't need to succeed.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					If the provided chain fails, it will be ignored. This way, the chain can be
 | 
				
			||||||
 | 
					executed without breaking the whole chain if it fails. This can be useful for:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					1.  Sending information to the Matrix API and not caring if it actually arrives
 | 
				
			||||||
 | 
					2.  Gaining optional information that might be nice to know, but not necessary
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Consequently, the optional chain cannot add any information that the rest of
 | 
				
			||||||
 | 
					the chain relies on.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					-}
 | 
				
			||||||
 | 
					maybe : IdemChain err u a -> IdemChain err2 u a
 | 
				
			||||||
 | 
					maybe f =
 | 
				
			||||||
 | 
					    { contextChange = identity
 | 
				
			||||||
 | 
					    , logs = []
 | 
				
			||||||
 | 
					    , messages = []
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					        |> succeed
 | 
				
			||||||
 | 
					        |> always
 | 
				
			||||||
 | 
					        |> onError
 | 
				
			||||||
 | 
					        |> (|>) f
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					{-| When an error occurs, this function allows the task chain to go down a
 | 
				
			||||||
 | 
					similar but different route.
 | 
				
			||||||
 | 
					-}
 | 
				
			||||||
 | 
					onError : (err -> TaskChain err2 u a b) -> TaskChain err u a b -> TaskChain err2 u a b
 | 
				
			||||||
 | 
					onError onErr f =
 | 
				
			||||||
 | 
					    \context ->
 | 
				
			||||||
 | 
					        f context
 | 
				
			||||||
 | 
					            |> Task.onError
 | 
				
			||||||
 | 
					                (\old ->
 | 
				
			||||||
 | 
					                    { contextChange = identity
 | 
				
			||||||
 | 
					                    , logs = old.logs
 | 
				
			||||||
 | 
					                    , messages = old.messages
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                        |> succeed
 | 
				
			||||||
 | 
					                        |> andThen (onErr old.error)
 | 
				
			||||||
 | 
					                        |> (|>) context
 | 
				
			||||||
 | 
					                )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					{-| Creates a task that always succeeds.
 | 
				
			||||||
 | 
					-}
 | 
				
			||||||
 | 
					succeed : TaskChainPiece u a b -> TaskChain err u a b
 | 
				
			||||||
 | 
					succeed piece _ =
 | 
				
			||||||
 | 
					    Task.succeed piece
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,284 @@
 | 
				
			||||||
 | 
					module Internal.Api.Request exposing
 | 
				
			||||||
 | 
					    ( ApiCall, ApiPlan, callAPI, withAttributes
 | 
				
			||||||
 | 
					    , accessToken, withTransactionId
 | 
				
			||||||
 | 
					    , fullBody, bodyBool, bodyInt, bodyString, bodyValue, bodyOpBool, bodyOpInt, bodyOpString, bodyOpValue
 | 
				
			||||||
 | 
					    , queryBool, queryInt, queryString, queryOpBool, queryOpInt, queryOpString
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					{-|
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# API module
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This module helps describe API requests.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Plan
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@docs ApiCall, ApiPlan, callAPI, withAttributes
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## API attributes
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### General attributes
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@docs accessToken, withTransactionId
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Body
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@docs fullBody, bodyBool, bodyInt, bodyString, bodyValue, bodyOpBool, bodyOpInt, bodyOpString, bodyOpValue
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Query parameters
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@docs queryBool, queryInt, queryString, queryOpBool, queryOpInt, queryOpString
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					-}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import Http
 | 
				
			||||||
 | 
					import Internal.Tools.Json as Json
 | 
				
			||||||
 | 
					import Internal.Values.Context as Context exposing (APIContext)
 | 
				
			||||||
 | 
					import Url
 | 
				
			||||||
 | 
					import Url.Builder as UrlBuilder
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					{-| The API call is a plan that describes how an interaction is planned with
 | 
				
			||||||
 | 
					the Matrix API.
 | 
				
			||||||
 | 
					-}
 | 
				
			||||||
 | 
					type alias ApiCall ph =
 | 
				
			||||||
 | 
					    { attributes : List ContextAttr
 | 
				
			||||||
 | 
					    , baseUrl : String
 | 
				
			||||||
 | 
					    , context : APIContext ph
 | 
				
			||||||
 | 
					    , method : String
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					{-| Shortcut definition to define a function that bases an APICall on a given
 | 
				
			||||||
 | 
					APIContext.
 | 
				
			||||||
 | 
					-}
 | 
				
			||||||
 | 
					type alias ApiPlan a =
 | 
				
			||||||
 | 
					    APIContext a -> ApiCall a
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					{-| An attribute maps a given context to an attribute for an API call.
 | 
				
			||||||
 | 
					-}
 | 
				
			||||||
 | 
					type alias Attribute a =
 | 
				
			||||||
 | 
					    APIContext a -> ContextAttr
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					{-| A context attribute describes one aspect of the API call that is to be made.
 | 
				
			||||||
 | 
					-}
 | 
				
			||||||
 | 
					type ContextAttr
 | 
				
			||||||
 | 
					    = BodyParam String Json.Value
 | 
				
			||||||
 | 
					    | FullBody Json.Value
 | 
				
			||||||
 | 
					    | Header Http.Header
 | 
				
			||||||
 | 
					    | NoAttr
 | 
				
			||||||
 | 
					    | QueryParam UrlBuilder.QueryParameter
 | 
				
			||||||
 | 
					    | ReplaceInUrl String String
 | 
				
			||||||
 | 
					    | Timeout Float
 | 
				
			||||||
 | 
					    | UrlPath String
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					{-| Attribute that requires an access token to be present
 | 
				
			||||||
 | 
					-}
 | 
				
			||||||
 | 
					accessToken : Attribute { a | accessToken : () }
 | 
				
			||||||
 | 
					accessToken =
 | 
				
			||||||
 | 
					    Context.getAccessToken
 | 
				
			||||||
 | 
					        >> (++) "Bearer "
 | 
				
			||||||
 | 
					        >> Http.header "Authorization"
 | 
				
			||||||
 | 
					        >> Header
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					{-| Attribute that adds a boolean value to the HTTP body.
 | 
				
			||||||
 | 
					-}
 | 
				
			||||||
 | 
					bodyBool : String -> Bool -> Attribute a
 | 
				
			||||||
 | 
					bodyBool key value =
 | 
				
			||||||
 | 
					    bodyValue key <| Json.encode Json.bool value
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					{-| Attribute that adds an integer value to the HTTP body.
 | 
				
			||||||
 | 
					-}
 | 
				
			||||||
 | 
					bodyInt : String -> Int -> Attribute a
 | 
				
			||||||
 | 
					bodyInt key value =
 | 
				
			||||||
 | 
					    bodyValue key <| Json.encode Json.int value
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					{-| Attribute that adds a boolean to the HTTP body if it is given.
 | 
				
			||||||
 | 
					-}
 | 
				
			||||||
 | 
					bodyOpBool : String -> Maybe Bool -> Attribute a
 | 
				
			||||||
 | 
					bodyOpBool key value =
 | 
				
			||||||
 | 
					    case value of
 | 
				
			||||||
 | 
					        Just v ->
 | 
				
			||||||
 | 
					            bodyBool key v
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Nothing ->
 | 
				
			||||||
 | 
					            empty
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					{-| Attribute that adds an integer value to the HTTP body if it is given.
 | 
				
			||||||
 | 
					-}
 | 
				
			||||||
 | 
					bodyOpInt : String -> Maybe Int -> Attribute a
 | 
				
			||||||
 | 
					bodyOpInt key value =
 | 
				
			||||||
 | 
					    case value of
 | 
				
			||||||
 | 
					        Just v ->
 | 
				
			||||||
 | 
					            bodyInt key v
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Nothing ->
 | 
				
			||||||
 | 
					            empty
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					{-| Attribute that adds a string value to the HTTP body if it is given.
 | 
				
			||||||
 | 
					-}
 | 
				
			||||||
 | 
					bodyOpString : String -> Maybe String -> Attribute a
 | 
				
			||||||
 | 
					bodyOpString key value =
 | 
				
			||||||
 | 
					    case value of
 | 
				
			||||||
 | 
					        Just v ->
 | 
				
			||||||
 | 
					            bodyString key v
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Nothing ->
 | 
				
			||||||
 | 
					            empty
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					{-| Attribute that adds a JSON value to the HTTP body if it is given.
 | 
				
			||||||
 | 
					-}
 | 
				
			||||||
 | 
					bodyOpValue : String -> Maybe Json.Value -> Attribute a
 | 
				
			||||||
 | 
					bodyOpValue key value =
 | 
				
			||||||
 | 
					    case value of
 | 
				
			||||||
 | 
					        Just v ->
 | 
				
			||||||
 | 
					            bodyValue key v
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Nothing ->
 | 
				
			||||||
 | 
					            empty
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					{-| Attribute that adds a string value to the HTTP body.
 | 
				
			||||||
 | 
					-}
 | 
				
			||||||
 | 
					bodyString : String -> String -> Attribute a
 | 
				
			||||||
 | 
					bodyString key value =
 | 
				
			||||||
 | 
					    bodyValue key <| Json.encode Json.string value
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					{-| Attribute that adds a JSON value to the HTTP body.
 | 
				
			||||||
 | 
					-}
 | 
				
			||||||
 | 
					bodyValue : String -> Json.Value -> Attribute a
 | 
				
			||||||
 | 
					bodyValue key value _ =
 | 
				
			||||||
 | 
					    BodyParam key value
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					{-| Create a plan to create an API call.
 | 
				
			||||||
 | 
					-}
 | 
				
			||||||
 | 
					callAPI : { method : String, path : List String } -> ApiPlan { a | baseUrl : () }
 | 
				
			||||||
 | 
					callAPI { method, path } context =
 | 
				
			||||||
 | 
					    { attributes =
 | 
				
			||||||
 | 
					        path
 | 
				
			||||||
 | 
					            |> List.map Url.percentEncode
 | 
				
			||||||
 | 
					            |> String.join "/"
 | 
				
			||||||
 | 
					            |> (++) "/"
 | 
				
			||||||
 | 
					            |> UrlPath
 | 
				
			||||||
 | 
					            |> List.singleton
 | 
				
			||||||
 | 
					    , baseUrl = Context.getBaseUrl context
 | 
				
			||||||
 | 
					    , context = context
 | 
				
			||||||
 | 
					    , method = method
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					{-| Add an empty attribute that does nothing.
 | 
				
			||||||
 | 
					-}
 | 
				
			||||||
 | 
					empty : Attribute a
 | 
				
			||||||
 | 
					empty =
 | 
				
			||||||
 | 
					    always NoAttr
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					{-| Adds a JSON value as the HTTP body.
 | 
				
			||||||
 | 
					-}
 | 
				
			||||||
 | 
					fullBody : Json.Value -> Attribute a
 | 
				
			||||||
 | 
					fullBody value _ =
 | 
				
			||||||
 | 
					    FullBody value
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					{-| Add a boolean value as a query parameter to the URL.
 | 
				
			||||||
 | 
					-}
 | 
				
			||||||
 | 
					queryBool : String -> Bool -> Attribute a
 | 
				
			||||||
 | 
					queryBool key value _ =
 | 
				
			||||||
 | 
					    (if value then
 | 
				
			||||||
 | 
					        "true"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					     else
 | 
				
			||||||
 | 
					        "false"
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					        |> UrlBuilder.string key
 | 
				
			||||||
 | 
					        |> QueryParam
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					{-| Add an integer value as a query parameter to the URL.
 | 
				
			||||||
 | 
					-}
 | 
				
			||||||
 | 
					queryInt : String -> Int -> Attribute a
 | 
				
			||||||
 | 
					queryInt key value _ =
 | 
				
			||||||
 | 
					    QueryParam <| UrlBuilder.int key value
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					{-| Add a boolean value as a query parameter to the URL if it exists.
 | 
				
			||||||
 | 
					-}
 | 
				
			||||||
 | 
					queryOpBool : String -> Maybe Bool -> Attribute a
 | 
				
			||||||
 | 
					queryOpBool key value =
 | 
				
			||||||
 | 
					    case value of
 | 
				
			||||||
 | 
					        Just v ->
 | 
				
			||||||
 | 
					            queryBool key v
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Nothing ->
 | 
				
			||||||
 | 
					            empty
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					{-| Add an integer value as a query parameter to the URL if it exists.
 | 
				
			||||||
 | 
					-}
 | 
				
			||||||
 | 
					queryOpInt : String -> Maybe Int -> Attribute a
 | 
				
			||||||
 | 
					queryOpInt key value =
 | 
				
			||||||
 | 
					    case value of
 | 
				
			||||||
 | 
					        Just v ->
 | 
				
			||||||
 | 
					            queryInt key v
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Nothing ->
 | 
				
			||||||
 | 
					            empty
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					{-| Add a string value as a query parameter to the URL if it exists.
 | 
				
			||||||
 | 
					-}
 | 
				
			||||||
 | 
					queryOpString : String -> Maybe String -> Attribute a
 | 
				
			||||||
 | 
					queryOpString key value =
 | 
				
			||||||
 | 
					    case value of
 | 
				
			||||||
 | 
					        Just v ->
 | 
				
			||||||
 | 
					            queryString key v
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Nothing ->
 | 
				
			||||||
 | 
					            empty
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					{-| Add a string value as a query parameter to the URL.
 | 
				
			||||||
 | 
					-}
 | 
				
			||||||
 | 
					queryString : String -> String -> Attribute a
 | 
				
			||||||
 | 
					queryString key value _ =
 | 
				
			||||||
 | 
					    QueryParam <| UrlBuilder.string key value
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					{-| Add more attributes to the API plan.
 | 
				
			||||||
 | 
					-}
 | 
				
			||||||
 | 
					withAttributes : List (Attribute a) -> ApiPlan a -> ApiPlan a
 | 
				
			||||||
 | 
					withAttributes attrs f context =
 | 
				
			||||||
 | 
					    f context
 | 
				
			||||||
 | 
					        |> (\data ->
 | 
				
			||||||
 | 
					                { data
 | 
				
			||||||
 | 
					                    | attributes =
 | 
				
			||||||
 | 
					                        attrs
 | 
				
			||||||
 | 
					                            |> List.map (\attr -> attr data.context)
 | 
				
			||||||
 | 
					                            |> List.append data.attributes
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					           )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					{-| Attribute that requires a transaction id to be present.
 | 
				
			||||||
 | 
					-}
 | 
				
			||||||
 | 
					withTransactionId : Attribute { a | transaction : () }
 | 
				
			||||||
 | 
					withTransactionId =
 | 
				
			||||||
 | 
					    Context.getTransaction >> ReplaceInUrl "txnId"
 | 
				
			||||||
		Loading…
	
		Reference in New Issue