elm-pages 2.1.10 → 3.0.0-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (136) hide show
  1. package/generator/review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/Pages-Internal-RoutePattern.elmi +0 -0
  2. package/generator/review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/Pages-Internal-RoutePattern.elmo +0 -0
  3. package/generator/review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/Pages-Review-NoContractViolations.elmi +0 -0
  4. package/generator/review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/Pages-Review-NoContractViolations.elmo +0 -0
  5. package/generator/review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/Pages-Review-NoContractViolationsTest.elmi +0 -0
  6. package/generator/review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/Pages-Review-NoContractViolationsTest.elmo +0 -0
  7. package/generator/review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/Reporter.elmi +0 -0
  8. package/generator/review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/Reporter.elmo +0 -0
  9. package/generator/review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/Runner.elmi +0 -0
  10. package/generator/review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/Runner.elmo +0 -0
  11. package/generator/review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/d.dat +0 -0
  12. package/generator/review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/i.dat +0 -0
  13. package/generator/{template/public/style.css → review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/lock} +0 -0
  14. package/generator/review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/o.dat +0 -0
  15. package/generator/review/elm-stuff/tests-0.19.1/elm.json +1 -0
  16. package/generator/review/elm-stuff/tests-0.19.1/js/Reporter.elm.js +6795 -0
  17. package/generator/review/elm-stuff/tests-0.19.1/js/Runner.elm.js +27617 -0
  18. package/generator/review/elm-stuff/tests-0.19.1/js/node_runner.js +110 -0
  19. package/generator/review/elm-stuff/tests-0.19.1/js/node_supervisor.js +187 -0
  20. package/generator/review/elm-stuff/tests-0.19.1/js/package.json +1 -0
  21. package/generator/review/elm-stuff/tests-0.19.1/src/Reporter.elm +26 -0
  22. package/generator/review/elm-stuff/tests-0.19.1/src/Runner.elm +62 -0
  23. package/generator/review/elm.json +13 -4
  24. package/{src → generator/review/src}/Pages/Review/NoContractViolations.elm +148 -148
  25. package/generator/review/tests/Pages/Review/NoContractViolationsTest.elm +331 -0
  26. package/generator/src/RouteBuilder.elm +420 -0
  27. package/generator/src/SharedTemplate.elm +4 -5
  28. package/generator/src/SiteConfig.elm +3 -9
  29. package/generator/src/build.js +308 -95
  30. package/generator/src/cli.js +103 -8
  31. package/generator/src/codegen.js +192 -35
  32. package/generator/src/compile-elm.js +183 -31
  33. package/generator/src/dev-server.js +353 -96
  34. package/generator/src/elm-application.json +3 -1
  35. package/generator/src/elm-codegen.js +34 -0
  36. package/generator/src/elm-file-constants.js +2 -0
  37. package/generator/src/error-formatter.js +20 -1
  38. package/generator/src/generate-template-module-connector.js +120 -924
  39. package/generator/src/hello.ts +5 -0
  40. package/generator/src/pre-render-html.js +58 -104
  41. package/generator/src/render-worker.js +27 -13
  42. package/generator/src/render.js +252 -197
  43. package/generator/src/request-cache-fs.js +18 -0
  44. package/generator/src/request-cache.js +128 -56
  45. package/generator/src/rewrite-client-elm-json.js +49 -0
  46. package/generator/src/route-codegen-helpers.js +62 -1
  47. package/generator/static-code/dev-style.css +22 -0
  48. package/generator/static-code/elm-pages.js +43 -39
  49. package/generator/static-code/hmr.js +98 -88
  50. package/generator/template/app/Api.elm +25 -0
  51. package/generator/template/app/ErrorPage.elm +38 -0
  52. package/generator/template/app/Route/Index.elm +87 -0
  53. package/generator/template/{src → app}/Shared.elm +34 -13
  54. package/generator/template/app/Site.elm +19 -0
  55. package/generator/template/{src → app}/View.elm +0 -0
  56. package/generator/template/elm-pages.config.mjs +5 -0
  57. package/generator/template/elm.json +14 -5
  58. package/generator/template/{public/index.js → index.ts} +7 -3
  59. package/generator/template/package.json +5 -5
  60. package/generator/template/public/favicon.ico +0 -0
  61. package/generator/template/public/images/icon-png.png +0 -0
  62. package/generator/template/src/.gitkeep +0 -0
  63. package/generator/template/style.css +4 -0
  64. package/package.json +30 -23
  65. package/src/ApiRoute.elm +176 -43
  66. package/src/BuildError.elm +10 -1
  67. package/src/CookieParser.elm +84 -0
  68. package/src/DataSource/Env.elm +38 -0
  69. package/src/DataSource/File.elm +27 -16
  70. package/src/DataSource/Glob.elm +126 -80
  71. package/src/DataSource/Http.elm +283 -304
  72. package/src/DataSource/Internal/Glob.elm +5 -21
  73. package/src/DataSource/Internal/Request.elm +25 -0
  74. package/src/DataSource/Port.elm +17 -14
  75. package/src/DataSource.elm +55 -318
  76. package/src/Form/Field.elm +717 -0
  77. package/src/Form/FieldStatus.elm +36 -0
  78. package/src/Form/FieldView.elm +417 -0
  79. package/src/Form/FormData.elm +22 -0
  80. package/src/Form/Validation.elm +391 -0
  81. package/src/Form/Value.elm +118 -0
  82. package/src/Form.elm +1683 -0
  83. package/src/FormData.elm +58 -0
  84. package/src/FormDecoder.elm +102 -0
  85. package/src/Head/Seo.elm +12 -4
  86. package/src/Head.elm +12 -2
  87. package/src/HtmlPrinter.elm +1 -1
  88. package/src/Internal/ApiRoute.elm +17 -4
  89. package/src/Internal/Request.elm +7 -0
  90. package/src/PageServerResponse.elm +68 -0
  91. package/src/Pages/ContentCache.elm +1 -229
  92. package/src/Pages/Fetcher.elm +58 -0
  93. package/src/Pages/FormState.elm +256 -0
  94. package/src/Pages/Generate.elm +800 -0
  95. package/src/Pages/Internal/Form.elm +17 -0
  96. package/src/Pages/Internal/NotFoundReason.elm +3 -55
  97. package/src/Pages/Internal/Platform/Cli.elm +777 -579
  98. package/src/Pages/Internal/Platform/Effect.elm +5 -5
  99. package/src/Pages/Internal/Platform/StaticResponses.elm +178 -394
  100. package/src/Pages/Internal/Platform/ToJsPayload.elm +24 -23
  101. package/src/Pages/Internal/Platform.elm +1244 -504
  102. package/src/Pages/Internal/ResponseSketch.elm +19 -0
  103. package/src/Pages/Internal/RoutePattern.elm +596 -45
  104. package/src/Pages/Manifest.elm +26 -0
  105. package/src/Pages/Msg.elm +79 -0
  106. package/src/Pages/ProgramConfig.elm +67 -14
  107. package/src/Pages/SiteConfig.elm +3 -6
  108. package/src/Pages/StaticHttp/Request.elm +4 -2
  109. package/src/Pages/StaticHttpRequest.elm +50 -215
  110. package/src/Pages/Transition.elm +70 -0
  111. package/src/Path.elm +1 -0
  112. package/src/Pattern.elm +98 -0
  113. package/src/RenderRequest.elm +2 -2
  114. package/src/RequestsAndPending.elm +111 -9
  115. package/src/Server/Request.elm +1253 -0
  116. package/src/Server/Response.elm +292 -0
  117. package/src/Server/Session.elm +316 -0
  118. package/src/Server/SetCookie.elm +169 -0
  119. package/src/TerminalText.elm +1 -1
  120. package/src/Test/Html/Internal/ElmHtml/Markdown.elm +0 -1
  121. package/src/Test/Html/Internal/ElmHtml/ToString.elm +1 -1
  122. package/generator/src/Page.elm +0 -359
  123. package/generator/src/codegen-template-module.js +0 -183
  124. package/generator/src/elm-pages-js-minified.js +0 -1
  125. package/generator/template/src/Api.elm +0 -14
  126. package/generator/template/src/Page/Index.elm +0 -69
  127. package/generator/template/src/Site.elm +0 -41
  128. package/src/DataSource/ServerRequest.elm +0 -60
  129. package/src/Internal/OptimizedDecoder.elm +0 -18
  130. package/src/KeepOrDiscard.elm +0 -6
  131. package/src/OptimizedDecoder/Pipeline.elm +0 -335
  132. package/src/OptimizedDecoder.elm +0 -818
  133. package/src/Pages/Internal/ApplicationType.elm +0 -6
  134. package/src/Pages/Secrets.elm +0 -83
  135. package/src/Secrets.elm +0 -111
  136. package/src/SecretsDict.elm +0 -45
@@ -0,0 +1,1253 @@
1
+ module Server.Request exposing
2
+ ( Parser
3
+ , succeed, fromResult, skip
4
+ , formData, formDataWithServerValidation
5
+ , rawFormData
6
+ , method, rawBody, allCookies, rawHeaders, queryParams
7
+ , requestTime, optionalHeader, expectContentType, expectJsonBody
8
+ , acceptMethod, acceptContentTypes
9
+ , map, map2, oneOf, andMap, andThen
10
+ , queryParam, expectQueryParam
11
+ , cookie, expectCookie
12
+ , expectHeader
13
+ , File, expectMultiPartFormPost
14
+ , expectBody
15
+ , map3, map4, map5, map6, map7, map8, map9
16
+ , Method(..), methodToString
17
+ , errorsToString, errorToString, getDecoder, ValidationError
18
+ )
19
+
20
+ {-|
21
+
22
+ @docs Parser
23
+
24
+ @docs succeed, fromResult, skip
25
+
26
+
27
+ ## Forms
28
+
29
+ @docs formData, formDataWithServerValidation
30
+
31
+ @docs rawFormData
32
+
33
+
34
+ ## Direct Values
35
+
36
+ @docs method, rawBody, allCookies, rawHeaders, queryParams
37
+
38
+ @docs requestTime, optionalHeader, expectContentType, expectJsonBody
39
+
40
+ @docs acceptMethod, acceptContentTypes
41
+
42
+
43
+ ## Transforming
44
+
45
+ @docs map, map2, oneOf, andMap, andThen
46
+
47
+
48
+ ## Query Parameters
49
+
50
+ @docs queryParam, expectQueryParam
51
+
52
+
53
+ ## Cookies
54
+
55
+ @docs cookie, expectCookie
56
+
57
+
58
+ ## Headers
59
+
60
+ @docs expectHeader
61
+
62
+
63
+ ## Multi-part forms and file uploads
64
+
65
+ @docs File, expectMultiPartFormPost
66
+
67
+
68
+ ## Request Parsers That Can Fail
69
+
70
+ @docs expectBody
71
+
72
+
73
+ ## Map Functions
74
+
75
+ @docs map3, map4, map5, map6, map7, map8, map9
76
+
77
+
78
+ ## Method Type
79
+
80
+ @docs Method, methodToString
81
+
82
+
83
+ ## Internals
84
+
85
+ @docs errorsToString, errorToString, getDecoder, ValidationError
86
+
87
+ -}
88
+
89
+ import CookieParser
90
+ import DataSource exposing (DataSource)
91
+ import Dict exposing (Dict)
92
+ import Form
93
+ import Form.Validation exposing (Validation)
94
+ import FormData
95
+ import Internal.Request
96
+ import Json.Decode
97
+ import Json.Encode
98
+ import List.NonEmpty
99
+ import Pages.Internal.Form exposing (Validation(..))
100
+ import QueryParams
101
+ import Time
102
+ import Url
103
+
104
+
105
+ {-| A `Server.Request.Parser` lets you send a `Server.Response.Response` based on an incoming HTTP request. For example,
106
+ using a `Server.Request.Parser`, you could check a session cookie to decide whether to respond by rendering a page
107
+ for the logged-in user, or else respond with an HTTP redirect response (see the [`Server.Response` docs](Server-Response)).
108
+
109
+ You can access the incoming HTTP request's:
110
+
111
+ - Headers
112
+ - Cookies
113
+ - [`method`](#method)
114
+ - URL query parameters
115
+ - [`requestTime`](#requestTime) (as a `Time.Posix`)
116
+
117
+ Note that this data is not available for pre-rendered pages or pre-rendered API Routes, only for server-rendered pages.
118
+ This is because when a page is pre-rendered, there _is_ no incoming HTTP request to respond to, it is rendered before a user
119
+ requests the page and then the pre-rendered page is served as a plain file (without running your Route Module).
120
+
121
+ That's why `RouteBuilder.preRender` has `data : RouteParams -> DataSource Data`:
122
+
123
+ import DataSource exposing (DataSource)
124
+ import RouteBuilder exposing (StatelessRoute)
125
+
126
+ type alias Data =
127
+ {}
128
+
129
+ data : RouteParams -> DataSource Data
130
+ data routeParams =
131
+ DataSource.succeed Data
132
+
133
+ route : StatelessRoute RouteParams Data ActionData
134
+ route =
135
+ RouteBuilder.preRender
136
+ { data = data
137
+ , head = head
138
+ , pages = pages
139
+ }
140
+ |> RouteBuilder.buildNoState { view = view }
141
+
142
+ A server-rendered Route Module _does_ have access to a user's incoming HTTP request because it runs every time the page
143
+ is loaded. That's why `data` is a `Request.Parser` in server-rendered Route Modules. Since you have an incoming HTTP request for server-rendered routes,
144
+ `RouteBuilder.serverRender` has `data : RouteParams -> Request.Parser (DataSource (Response Data))`. That means that you
145
+ can use the incoming HTTP request data to choose how to respond. For example, you could check for a dark-mode preference
146
+ cookie and render a light- or dark-themed page and render a different page.
147
+
148
+ That's a mouthful, so let's unpack what it means.
149
+
150
+ `Request.Parser` means you can pull out
151
+
152
+ data from the request payload using a Server Request Parser.
153
+
154
+ import DataSource exposing (DataSource)
155
+ import RouteBuilder exposing (StatelessRoute)
156
+ import Server.Request as Request exposing (Request)
157
+ import Server.Response as Response exposing (Response)
158
+
159
+ type alias Data =
160
+ {}
161
+
162
+ data :
163
+ RouteParams
164
+ -> Request.Parser (DataSource (Response Data))
165
+ data routeParams =
166
+ {}
167
+ |> Server.Response.render
168
+ |> DataSource.succeed
169
+ |> Request.succeed
170
+
171
+ route : StatelessRoute RouteParams Data ActionData
172
+ route =
173
+ RouteBuilder.serverRender
174
+ { head = head
175
+ , data = data
176
+ }
177
+ |> RouteBuilder.buildNoState { view = view }
178
+
179
+ -}
180
+ type alias Parser decodesTo =
181
+ Internal.Request.Parser decodesTo ValidationError
182
+
183
+
184
+ oneOfInternal : List ValidationError -> List (Json.Decode.Decoder ( Result ValidationError decodesTo, List ValidationError )) -> Json.Decode.Decoder ( Result ValidationError decodesTo, List ValidationError )
185
+ oneOfInternal previousErrors optimizedDecoders =
186
+ -- elm-review: known-unoptimized-recursion
187
+ case optimizedDecoders of
188
+ [] ->
189
+ Json.Decode.succeed ( Err (OneOf previousErrors), [] )
190
+
191
+ [ single ] ->
192
+ single
193
+ |> Json.Decode.map
194
+ (\result ->
195
+ result
196
+ |> Tuple.mapFirst (Result.mapError (\error -> OneOf (previousErrors ++ [ error ])))
197
+ )
198
+
199
+ first :: rest ->
200
+ first
201
+ |> Json.Decode.andThen
202
+ (\( firstResult, firstErrors ) ->
203
+ case ( firstResult, firstErrors ) of
204
+ ( Ok okFirstResult, [] ) ->
205
+ Json.Decode.succeed ( Ok okFirstResult, [] )
206
+
207
+ ( Ok _, otherErrors ) ->
208
+ oneOfInternal (previousErrors ++ otherErrors) rest
209
+
210
+ ( Err error, _ ) ->
211
+ case error of
212
+ OneOf errors ->
213
+ oneOfInternal (previousErrors ++ errors) rest
214
+
215
+ _ ->
216
+ oneOfInternal (previousErrors ++ [ error ]) rest
217
+ )
218
+
219
+
220
+ {-| -}
221
+ succeed : value -> Parser value
222
+ succeed value =
223
+ Internal.Request.Parser (Json.Decode.succeed ( Ok value, [] ))
224
+
225
+
226
+ {-| TODO internal only
227
+ -}
228
+ getDecoder : Parser (DataSource response) -> Json.Decode.Decoder (Result ( ValidationError, List ValidationError ) (DataSource response))
229
+ getDecoder (Internal.Request.Parser decoder) =
230
+ decoder
231
+ |> Json.Decode.map
232
+ (\( result, validationErrors ) ->
233
+ case ( result, validationErrors ) of
234
+ ( Ok value, [] ) ->
235
+ value
236
+ |> Ok
237
+
238
+ ( Ok _, firstError :: rest ) ->
239
+ Err ( firstError, rest )
240
+
241
+ ( Err fatalError, errors ) ->
242
+ Err ( fatalError, errors )
243
+ )
244
+
245
+
246
+ {-| -}
247
+ type ValidationError
248
+ = ValidationError String
249
+ | OneOf (List ValidationError)
250
+ | MissingQueryParam { missingParam : String, allQueryParams : String }
251
+
252
+
253
+ {-| -}
254
+ errorsToString : ( ValidationError, List ValidationError ) -> String
255
+ errorsToString validationErrors =
256
+ validationErrors
257
+ |> List.NonEmpty.toList
258
+ |> List.map errorToString
259
+ |> String.join "\n"
260
+
261
+
262
+ {-| TODO internal only
263
+ -}
264
+ errorToString : ValidationError -> String
265
+ errorToString validationError_ =
266
+ -- elm-review: known-unoptimized-recursion
267
+ case validationError_ of
268
+ ValidationError message ->
269
+ message
270
+
271
+ OneOf validationErrors ->
272
+ "Server.Request.oneOf failed in the following "
273
+ ++ String.fromInt (List.length validationErrors)
274
+ ++ " ways:\n\n"
275
+ ++ (validationErrors
276
+ |> List.indexedMap (\index error -> "(" ++ String.fromInt (index + 1) ++ ") " ++ errorToString error)
277
+ |> String.join "\n\n"
278
+ )
279
+
280
+ MissingQueryParam record ->
281
+ "Missing query param \"" ++ record.missingParam ++ "\". Query string was `" ++ record.allQueryParams ++ "`"
282
+
283
+
284
+ {-| -}
285
+ map : (a -> b) -> Parser a -> Parser b
286
+ map mapFn (Internal.Request.Parser decoder) =
287
+ Internal.Request.Parser
288
+ (Json.Decode.map
289
+ (\( result, errors ) ->
290
+ ( Result.map mapFn result, errors )
291
+ )
292
+ decoder
293
+ )
294
+
295
+
296
+ {-| -}
297
+ oneOf : List (Parser a) -> Parser a
298
+ oneOf serverRequests =
299
+ Internal.Request.Parser
300
+ (oneOfInternal []
301
+ (List.map
302
+ (\(Internal.Request.Parser decoder) -> decoder)
303
+ serverRequests
304
+ )
305
+ )
306
+
307
+
308
+ {-| Decode an argument and provide it to a function in a decoder.
309
+
310
+ decoder : Decoder String
311
+ decoder =
312
+ succeed (String.repeat)
313
+ |> andMap (field "count" int)
314
+ |> andMap (field "val" string)
315
+
316
+
317
+ """ { "val": "hi", "count": 3 } """
318
+ |> decodeString decoder
319
+ --> Success "hihihi"
320
+
321
+ -}
322
+ andMap : Parser a -> Parser (a -> b) -> Parser b
323
+ andMap =
324
+ map2 (|>)
325
+
326
+
327
+ {-| -}
328
+ andThen : (a -> Parser b) -> Parser a -> Parser b
329
+ andThen toRequestB (Internal.Request.Parser requestA) =
330
+ Json.Decode.andThen
331
+ (\value ->
332
+ case value of
333
+ ( Ok okValue, _ ) ->
334
+ okValue
335
+ |> toRequestB
336
+ |> unwrap
337
+
338
+ ( Err error, errors ) ->
339
+ Json.Decode.succeed ( Err error, errors )
340
+ )
341
+ requestA
342
+ |> Internal.Request.Parser
343
+
344
+
345
+ unwrap : Parser a -> Json.Decode.Decoder ( Result ValidationError a, List ValidationError )
346
+ unwrap (Internal.Request.Parser decoder_) =
347
+ decoder_
348
+
349
+
350
+ {-| -}
351
+ map2 : (a -> b -> c) -> Parser a -> Parser b -> Parser c
352
+ map2 f (Internal.Request.Parser jdA) (Internal.Request.Parser jdB) =
353
+ Internal.Request.Parser
354
+ (Json.Decode.map2
355
+ (\( result1, errors1 ) ( result2, errors2 ) ->
356
+ ( Result.map2 f result1 result2
357
+ , errors1 ++ errors2
358
+ )
359
+ )
360
+ jdA
361
+ jdB
362
+ )
363
+
364
+
365
+ {-| -}
366
+ map3 :
367
+ (value1 -> value2 -> value3 -> valueCombined)
368
+ -> Parser value1
369
+ -> Parser value2
370
+ -> Parser value3
371
+ -> Parser valueCombined
372
+ map3 combineFn request1 request2 request3 =
373
+ succeed combineFn
374
+ |> andMap request1
375
+ |> andMap request2
376
+ |> andMap request3
377
+
378
+
379
+ {-| -}
380
+ map4 :
381
+ (value1 -> value2 -> value3 -> value4 -> valueCombined)
382
+ -> Parser value1
383
+ -> Parser value2
384
+ -> Parser value3
385
+ -> Parser value4
386
+ -> Parser valueCombined
387
+ map4 combineFn request1 request2 request3 request4 =
388
+ succeed combineFn
389
+ |> andMap request1
390
+ |> andMap request2
391
+ |> andMap request3
392
+ |> andMap request4
393
+
394
+
395
+ {-| -}
396
+ map5 :
397
+ (value1 -> value2 -> value3 -> value4 -> value5 -> valueCombined)
398
+ -> Parser value1
399
+ -> Parser value2
400
+ -> Parser value3
401
+ -> Parser value4
402
+ -> Parser value5
403
+ -> Parser valueCombined
404
+ map5 combineFn request1 request2 request3 request4 request5 =
405
+ succeed combineFn
406
+ |> andMap request1
407
+ |> andMap request2
408
+ |> andMap request3
409
+ |> andMap request4
410
+ |> andMap request5
411
+
412
+
413
+ {-| -}
414
+ map6 :
415
+ (value1 -> value2 -> value3 -> value4 -> value5 -> value6 -> valueCombined)
416
+ -> Parser value1
417
+ -> Parser value2
418
+ -> Parser value3
419
+ -> Parser value4
420
+ -> Parser value5
421
+ -> Parser value6
422
+ -> Parser valueCombined
423
+ map6 combineFn request1 request2 request3 request4 request5 request6 =
424
+ succeed combineFn
425
+ |> andMap request1
426
+ |> andMap request2
427
+ |> andMap request3
428
+ |> andMap request4
429
+ |> andMap request5
430
+ |> andMap request6
431
+
432
+
433
+ {-| -}
434
+ map7 :
435
+ (value1 -> value2 -> value3 -> value4 -> value5 -> value6 -> value7 -> valueCombined)
436
+ -> Parser value1
437
+ -> Parser value2
438
+ -> Parser value3
439
+ -> Parser value4
440
+ -> Parser value5
441
+ -> Parser value6
442
+ -> Parser value7
443
+ -> Parser valueCombined
444
+ map7 combineFn request1 request2 request3 request4 request5 request6 request7 =
445
+ succeed combineFn
446
+ |> andMap request1
447
+ |> andMap request2
448
+ |> andMap request3
449
+ |> andMap request4
450
+ |> andMap request5
451
+ |> andMap request6
452
+ |> andMap request7
453
+
454
+
455
+ {-| -}
456
+ map8 :
457
+ (value1 -> value2 -> value3 -> value4 -> value5 -> value6 -> value7 -> value8 -> valueCombined)
458
+ -> Parser value1
459
+ -> Parser value2
460
+ -> Parser value3
461
+ -> Parser value4
462
+ -> Parser value5
463
+ -> Parser value6
464
+ -> Parser value7
465
+ -> Parser value8
466
+ -> Parser valueCombined
467
+ map8 combineFn request1 request2 request3 request4 request5 request6 request7 request8 =
468
+ succeed combineFn
469
+ |> andMap request1
470
+ |> andMap request2
471
+ |> andMap request3
472
+ |> andMap request4
473
+ |> andMap request5
474
+ |> andMap request6
475
+ |> andMap request7
476
+ |> andMap request8
477
+
478
+
479
+ {-| -}
480
+ map9 :
481
+ (value1 -> value2 -> value3 -> value4 -> value5 -> value6 -> value7 -> value8 -> value9 -> valueCombined)
482
+ -> Parser value1
483
+ -> Parser value2
484
+ -> Parser value3
485
+ -> Parser value4
486
+ -> Parser value5
487
+ -> Parser value6
488
+ -> Parser value7
489
+ -> Parser value8
490
+ -> Parser value9
491
+ -> Parser valueCombined
492
+ map9 combineFn request1 request2 request3 request4 request5 request6 request7 request8 request9 =
493
+ succeed combineFn
494
+ |> andMap request1
495
+ |> andMap request2
496
+ |> andMap request3
497
+ |> andMap request4
498
+ |> andMap request5
499
+ |> andMap request6
500
+ |> andMap request7
501
+ |> andMap request8
502
+ |> andMap request9
503
+
504
+
505
+ optionalField : String -> Json.Decode.Decoder a -> Json.Decode.Decoder (Maybe a)
506
+ optionalField fieldName decoder_ =
507
+ let
508
+ finishDecoding : Json.Decode.Value -> Json.Decode.Decoder (Maybe a)
509
+ finishDecoding json =
510
+ case Json.Decode.decodeValue (Json.Decode.field fieldName Json.Decode.value) json of
511
+ Ok _ ->
512
+ -- The field is present, so run the decoder on it.
513
+ Json.Decode.map Just (Json.Decode.field fieldName decoder_)
514
+
515
+ Err _ ->
516
+ -- The field was missing, which is fine!
517
+ Json.Decode.succeed Nothing
518
+ in
519
+ Json.Decode.value
520
+ |> Json.Decode.andThen finishDecoding
521
+
522
+
523
+ {-| Turn a Result into a Request. Useful with `andThen`. Turns `Err` into a skipped request handler (non-matching request),
524
+ and `Ok` values into a `succeed` (matching request).
525
+ -}
526
+ fromResult : Result String value -> Parser value
527
+ fromResult result =
528
+ case result of
529
+ Ok okValue ->
530
+ succeed okValue
531
+
532
+ Err error ->
533
+ skipInternal (ValidationError error)
534
+
535
+
536
+ jsonFromResult : Result String value -> Json.Decode.Decoder value
537
+ jsonFromResult result =
538
+ case result of
539
+ Ok okValue ->
540
+ Json.Decode.succeed okValue
541
+
542
+ Err error ->
543
+ Json.Decode.fail error
544
+
545
+
546
+ {-| -}
547
+ expectHeader : String -> Parser String
548
+ expectHeader headerName =
549
+ optionalField (headerName |> String.toLower) Json.Decode.string
550
+ |> Json.Decode.field "headers"
551
+ |> noErrors
552
+ |> Internal.Request.Parser
553
+ |> andThen
554
+ (\value ->
555
+ fromResult
556
+ (value |> Result.fromMaybe "Missing field headers")
557
+ )
558
+
559
+
560
+ {-| -}
561
+ rawHeaders : Parser (Dict String String)
562
+ rawHeaders =
563
+ Json.Decode.field "headers" (Json.Decode.dict Json.Decode.string)
564
+ |> noErrors
565
+ |> Internal.Request.Parser
566
+
567
+
568
+ {-| -}
569
+ requestTime : Parser Time.Posix
570
+ requestTime =
571
+ Json.Decode.field "requestTime"
572
+ (Json.Decode.int |> Json.Decode.map Time.millisToPosix)
573
+ |> noErrors
574
+ |> Internal.Request.Parser
575
+
576
+
577
+ noErrors : Json.Decode.Decoder value -> Json.Decode.Decoder ( Result ValidationError value, List ValidationError )
578
+ noErrors decoder =
579
+ decoder
580
+ |> Json.Decode.map (\value -> ( Ok value, [] ))
581
+
582
+
583
+ {-| -}
584
+ acceptContentTypes : ( String, List String ) -> Parser value -> Parser value
585
+ acceptContentTypes ( accepted1, accepted ) (Internal.Request.Parser decoder) =
586
+ -- TODO this should parse content-types so it doesn't need to be an exact match (support `; q=...`, etc.)
587
+ optionalField ("Accept" |> String.toLower) Json.Decode.string
588
+ |> Json.Decode.field "headers"
589
+ |> Json.Decode.andThen
590
+ (\acceptHeader ->
591
+ if List.NonEmpty.fromCons accepted1 accepted |> List.NonEmpty.member (acceptHeader |> Maybe.withDefault "") then
592
+ decoder
593
+
594
+ else
595
+ decoder
596
+ |> appendError
597
+ (ValidationError
598
+ ("Expected Accept header " ++ String.join ", " (accepted1 :: accepted) ++ " but was " ++ (acceptHeader |> Maybe.withDefault ""))
599
+ )
600
+ )
601
+ |> Internal.Request.Parser
602
+
603
+
604
+ {-| -}
605
+ acceptMethod : ( Method, List Method ) -> Parser value -> Parser value
606
+ acceptMethod ( accepted1, accepted ) (Internal.Request.Parser decoder) =
607
+ (Json.Decode.field "method" Json.Decode.string
608
+ |> Json.Decode.map methodFromString
609
+ |> Json.Decode.andThen
610
+ (\method_ ->
611
+ if (accepted1 :: accepted) |> List.member method_ then
612
+ decoder
613
+
614
+ else
615
+ decoder
616
+ |> appendError
617
+ (ValidationError
618
+ ("Expected HTTP method " ++ String.join ", " ((accepted1 :: accepted) |> List.map methodToString) ++ " but was " ++ methodToString method_)
619
+ )
620
+ )
621
+ )
622
+ |> Internal.Request.Parser
623
+
624
+
625
+ {-| -}
626
+ method : Parser Method
627
+ method =
628
+ Json.Decode.field "method" Json.Decode.string
629
+ |> Json.Decode.map methodFromString
630
+ |> noErrors
631
+ |> Internal.Request.Parser
632
+
633
+
634
+ appendError : ValidationError -> Json.Decode.Decoder ( value, List ValidationError ) -> Json.Decode.Decoder ( value, List ValidationError )
635
+ appendError error decoder =
636
+ decoder
637
+ |> Json.Decode.map (Tuple.mapSecond (\errors -> error :: errors))
638
+
639
+
640
+ {-| -}
641
+ expectQueryParam : String -> Parser String
642
+ expectQueryParam name =
643
+ rawUrl
644
+ |> andThen
645
+ (\url_ ->
646
+ case url_ |> Url.fromString |> Maybe.andThen .query of
647
+ Just queryString ->
648
+ let
649
+ maybeParamValue : Maybe String
650
+ maybeParamValue =
651
+ queryString
652
+ |> QueryParams.fromString
653
+ |> QueryParams.toDict
654
+ |> Dict.get name
655
+ |> Maybe.andThen List.head
656
+ in
657
+ case maybeParamValue of
658
+ Just okParamValue ->
659
+ succeed okParamValue
660
+
661
+ Nothing ->
662
+ skipInternal
663
+ (MissingQueryParam
664
+ { missingParam = name
665
+ , allQueryParams = queryString
666
+ }
667
+ )
668
+
669
+ Nothing ->
670
+ skipInternal (ValidationError ("Expected query param \"" ++ name ++ "\", but there were no query params."))
671
+ )
672
+
673
+
674
+ {-| -}
675
+ queryParam : String -> Parser (Maybe String)
676
+ queryParam name =
677
+ rawUrl
678
+ |> andThen
679
+ (\url_ ->
680
+ url_
681
+ |> Url.fromString
682
+ |> Maybe.andThen .query
683
+ |> Maybe.andThen (findFirstQueryParam name)
684
+ |> succeed
685
+ )
686
+
687
+
688
+ findFirstQueryParam : String -> String -> Maybe String
689
+ findFirstQueryParam name queryString =
690
+ queryString
691
+ |> QueryParams.fromString
692
+ |> QueryParams.toDict
693
+ |> Dict.get name
694
+ |> Maybe.andThen List.head
695
+
696
+
697
+ {-| -}
698
+ queryParams : Parser (Dict String (List String))
699
+ queryParams =
700
+ rawUrl
701
+ |> map
702
+ (\rawUrl_ ->
703
+ rawUrl_
704
+ |> Url.fromString
705
+ |> Maybe.andThen .query
706
+ |> Maybe.map QueryParams.fromString
707
+ |> Maybe.map QueryParams.toDict
708
+ |> Maybe.withDefault Dict.empty
709
+ )
710
+
711
+
712
+ {-| This is a Request.Parser that will never match an HTTP request. Similar to `Json.Decode.fail`.
713
+
714
+ Why would you want it to always fail? It's helpful for building custom `Server.Request.Parser`. For example, let's say
715
+ you wanted to define a custom `Server.Request.Parser` to use an XML Decoding package on the request body.
716
+ You could define a custom function like this
717
+
718
+ import Server.Request as Request
719
+
720
+ expectXmlBody : XmlDecoder value -> Request.Parser value
721
+ expectXmlBody xmlDecoder =
722
+ Request.expectBody
723
+ |> Request.andThen
724
+ (\bodyAsString ->
725
+ case runXmlDecoder xmlDecoder bodyAsString of
726
+ Ok decodedXml ->
727
+ Request.succeed decodedXml
728
+
729
+ Err error ->
730
+ Request.skip ("XML could not be decoded " ++ xmlErrorToString error)
731
+ )
732
+
733
+ Note that when we said `Request.skip`, remaining Request Parsers will run (for example if you use [`Server.Request.oneOf`](#oneOf)).
734
+ You could build this with different semantics if you wanted to handle _any_ valid XML body. This Request Parser will _not_
735
+ handle any valid XML body. It will only handle requests that can match the XmlDecoder that is passed in.
736
+
737
+ So when you define your `Server.Request.Parser`s, think carefully about whether you want to handle invalid cases and give an
738
+ error, or fall through to other Parsers. There's no universal right answer, it's just something to decide for your use case.
739
+
740
+ expectXmlBody : Request.Parser value
741
+ expectXmlBody =
742
+ Request.map2
743
+ acceptContentTypes
744
+ Request.expectBody
745
+ |> Request.andThen
746
+ (\bodyAsString ->
747
+ case runXmlDecoder xmlDecoder bodyAsString of
748
+ Ok decodedXml ->
749
+ Request.succeed decodedXml
750
+
751
+ Err error ->
752
+ Request.skip ("XML could not be decoded " ++ xmlErrorToString error)
753
+ )
754
+
755
+ -}
756
+ skip : String -> Parser value
757
+ skip errorMessage =
758
+ skipInternal (ValidationError errorMessage)
759
+
760
+
761
+ skipInternal : ValidationError -> Parser value
762
+ skipInternal validationError_ =
763
+ Internal.Request.Parser
764
+ (Json.Decode.succeed
765
+ ( Err validationError_, [] )
766
+ )
767
+
768
+
769
+ {-| -}
770
+ rawUrl : Parser String
771
+ rawUrl =
772
+ Json.Decode.maybe
773
+ (Json.Decode.string
774
+ |> Json.Decode.field "rawUrl"
775
+ )
776
+ |> Json.Decode.map
777
+ (\url_ ->
778
+ case url_ of
779
+ Just justValue ->
780
+ ( Ok justValue, [] )
781
+
782
+ Nothing ->
783
+ ( Err (ValidationError "Internal error - expected rawUrl field but the adapter script didn't provide one."), [] )
784
+ )
785
+ |> Internal.Request.Parser
786
+
787
+
788
+ {-| -}
789
+ optionalHeader : String -> Parser (Maybe String)
790
+ optionalHeader headerName =
791
+ optionalField (headerName |> String.toLower) Json.Decode.string
792
+ |> Json.Decode.field "headers"
793
+ |> noErrors
794
+ |> Internal.Request.Parser
795
+
796
+
797
+ {-| -}
798
+ expectCookie : String -> Parser String
799
+ expectCookie name =
800
+ cookie name
801
+ |> andThen
802
+ (\maybeCookie ->
803
+ case maybeCookie of
804
+ Just justValue ->
805
+ succeed justValue
806
+
807
+ Nothing ->
808
+ skipInternal (ValidationError ("Missing cookie " ++ name))
809
+ )
810
+
811
+
812
+ {-| -}
813
+ cookie : String -> Parser (Maybe String)
814
+ cookie name =
815
+ allCookies
816
+ |> map (Dict.get name)
817
+
818
+
819
+ {-| -}
820
+ allCookies : Parser (Dict String String)
821
+ allCookies =
822
+ Json.Decode.field "headers"
823
+ (optionalField "cookie"
824
+ Json.Decode.string
825
+ |> Json.Decode.map (Maybe.map CookieParser.parse)
826
+ )
827
+ |> Json.Decode.map (Maybe.withDefault Dict.empty)
828
+ |> noErrors
829
+ |> Internal.Request.Parser
830
+
831
+
832
+ formField_ : String -> Parser String
833
+ formField_ name =
834
+ optionalField name Json.Decode.string
835
+ |> Json.Decode.map
836
+ (\value ->
837
+ case value of
838
+ Just justValue ->
839
+ ( Ok justValue, [] )
840
+
841
+ Nothing ->
842
+ ( Err (ValidationError ("Missing form field '" ++ name ++ "'")), [] )
843
+ )
844
+ |> Internal.Request.Parser
845
+
846
+
847
+ optionalFormField_ : String -> Parser (Maybe String)
848
+ optionalFormField_ name =
849
+ optionalField name Json.Decode.string
850
+ |> noErrors
851
+ |> Internal.Request.Parser
852
+
853
+
854
+ {-| -}
855
+ type alias File =
856
+ { name : String
857
+ , mimeType : String
858
+ , body : String
859
+ }
860
+
861
+
862
+ fileField_ : String -> Parser File
863
+ fileField_ name =
864
+ optionalField name
865
+ (Json.Decode.map3 File
866
+ (Json.Decode.field "filename" Json.Decode.string)
867
+ (Json.Decode.field "mimeType" Json.Decode.string)
868
+ (Json.Decode.field "body" Json.Decode.string)
869
+ )
870
+ |> Json.Decode.map
871
+ (\value ->
872
+ case value of
873
+ Just justValue ->
874
+ ( Ok justValue, [] )
875
+
876
+ Nothing ->
877
+ ( Err (ValidationError ("Missing form field " ++ name)), [] )
878
+ )
879
+ |> Internal.Request.Parser
880
+
881
+
882
+ {-| -}
883
+ formDataWithServerValidation :
884
+ Form.ServerForms error (DataSource (Validation error combined kind constraints))
885
+ -> Parser (DataSource (Result (Form.Response error) ( Form.Response error, combined )))
886
+ formDataWithServerValidation formParsers =
887
+ rawFormData
888
+ |> andThen
889
+ (\rawFormData_ ->
890
+ let
891
+ ( maybeDecoded, errors ) =
892
+ Form.runOneOfServerSide
893
+ rawFormData_
894
+ formParsers
895
+ in
896
+ case ( maybeDecoded, errors |> Dict.toList |> List.filter (\( _, value ) -> value |> List.isEmpty |> not) |> List.NonEmpty.fromList ) of
897
+ ( Just decoded, Nothing ) ->
898
+ succeed
899
+ (decoded
900
+ |> DataSource.map
901
+ (\(Validation _ _ ( maybeParsed, errors2 )) ->
902
+ case ( maybeParsed, errors2 |> Dict.toList |> List.filter (\( _, value ) -> value |> List.isEmpty |> not) |> List.NonEmpty.fromList ) of
903
+ ( Just decodedFinal, Nothing ) ->
904
+ Ok
905
+ ( Form.Response
906
+ { fields = rawFormData_
907
+ , errors = Dict.empty
908
+ }
909
+ , decodedFinal
910
+ )
911
+
912
+ ( _, maybeErrors ) ->
913
+ Err
914
+ (Form.Response
915
+ { fields = rawFormData_
916
+ , errors =
917
+ maybeErrors
918
+ |> Maybe.map List.NonEmpty.toList
919
+ |> Maybe.withDefault []
920
+ |> Dict.fromList
921
+ }
922
+ )
923
+ )
924
+ )
925
+
926
+ ( _, maybeErrors ) ->
927
+ Err
928
+ (Form.Response
929
+ { fields = rawFormData_
930
+ , errors =
931
+ maybeErrors
932
+ |> Maybe.map List.NonEmpty.toList
933
+ |> Maybe.withDefault []
934
+ |> Dict.fromList
935
+ }
936
+ )
937
+ |> DataSource.succeed
938
+ |> succeed
939
+ )
940
+
941
+
942
+ {-| -}
943
+ formData :
944
+ Form.ServerForms error combined
945
+ -> Parser (Result { fields : List ( String, String ), errors : Dict String (List error) } combined)
946
+ formData formParsers =
947
+ rawFormData
948
+ |> andThen
949
+ (\rawFormData_ ->
950
+ let
951
+ ( maybeDecoded, errors ) =
952
+ Form.runOneOfServerSide
953
+ rawFormData_
954
+ formParsers
955
+ in
956
+ case ( maybeDecoded, errors |> Dict.toList |> List.filter (\( _, value ) -> value |> List.isEmpty |> not) |> List.NonEmpty.fromList ) of
957
+ ( Just decoded, Nothing ) ->
958
+ Ok decoded
959
+ |> succeed
960
+
961
+ ( _, maybeErrors ) ->
962
+ Err
963
+ { fields = rawFormData_
964
+ , errors =
965
+ maybeErrors
966
+ |> Maybe.map List.NonEmpty.toList
967
+ |> Maybe.withDefault []
968
+ |> Dict.fromList
969
+ }
970
+ |> succeed
971
+ )
972
+
973
+
974
+ {-| -}
975
+ rawFormData : Parser (List ( String, String ))
976
+ rawFormData =
977
+ -- TODO make an optional version
978
+ map4 (\parsedContentType a b c -> ( ( a, parsedContentType ), b, c ))
979
+ (rawContentType |> map (Maybe.map parseContentType))
980
+ (matchesContentType "application/x-www-form-urlencoded")
981
+ method
982
+ (rawBody |> map (Maybe.withDefault "")
983
+ -- TODO warn of empty body in case when field decoding fails?
984
+ )
985
+ |> andThen
986
+ (\( ( validContentType, parsedContentType ), validMethod, justBody ) ->
987
+ if validMethod == Get then
988
+ queryParams
989
+ |> map Dict.toList
990
+ |> map (List.map (Tuple.mapSecond (List.head >> Maybe.withDefault "")))
991
+
992
+ else if not ((validContentType |> Maybe.withDefault False) && validMethod == Post) then
993
+ Json.Decode.succeed
994
+ ( Err
995
+ (ValidationError <|
996
+ case ( validContentType |> Maybe.withDefault False, validMethod == Post, parsedContentType ) of
997
+ ( False, True, Just contentType_ ) ->
998
+ "expectFormPost did not match - Was form POST but expected content-type `application/x-www-form-urlencoded` and instead got `" ++ contentType_ ++ "`"
999
+
1000
+ ( False, True, Nothing ) ->
1001
+ "expectFormPost did not match - Was form POST but expected content-type `application/x-www-form-urlencoded` but the request didn't have a content-type header"
1002
+
1003
+ _ ->
1004
+ "expectFormPost did not match - expected method POST, but the method was " ++ methodToString validMethod
1005
+ )
1006
+ , []
1007
+ )
1008
+ |> Internal.Request.Parser
1009
+
1010
+ else
1011
+ justBody
1012
+ |> FormData.parse
1013
+ |> succeed
1014
+ |> andThen
1015
+ (\parsedForm ->
1016
+ let
1017
+ thing : Json.Encode.Value
1018
+ thing =
1019
+ parsedForm
1020
+ |> Dict.toList
1021
+ |> List.map
1022
+ (Tuple.mapSecond
1023
+ (\( first, _ ) ->
1024
+ Json.Encode.string first
1025
+ )
1026
+ )
1027
+ |> Json.Encode.object
1028
+
1029
+ innerDecoder : Json.Decode.Decoder ( Result ValidationError (List ( String, String )), List ValidationError )
1030
+ innerDecoder =
1031
+ Json.Decode.keyValuePairs Json.Decode.string
1032
+ |> noErrors
1033
+ in
1034
+ Json.Decode.decodeValue innerDecoder thing
1035
+ |> Result.mapError Json.Decode.errorToString
1036
+ |> jsonFromResult
1037
+ |> Internal.Request.Parser
1038
+ )
1039
+ )
1040
+
1041
+
1042
+ {-| -}
1043
+ expectMultiPartFormPost :
1044
+ ({ field : String -> Parser String
1045
+ , optionalField : String -> Parser (Maybe String)
1046
+ , fileField : String -> Parser File
1047
+ }
1048
+ -> Parser decodedForm
1049
+ )
1050
+ -> Parser decodedForm
1051
+ expectMultiPartFormPost toForm =
1052
+ map2
1053
+ (\_ value ->
1054
+ value
1055
+ )
1056
+ (expectContentType "multipart/form-data")
1057
+ (toForm
1058
+ { field = formField_
1059
+ , optionalField = optionalFormField_
1060
+ , fileField = fileField_
1061
+ }
1062
+ |> (\(Internal.Request.Parser decoder) -> decoder)
1063
+ -- @@@ TODO is it possible to do multipart form data parsing in pure Elm?
1064
+ |> Json.Decode.field "multiPartFormData"
1065
+ |> Internal.Request.Parser
1066
+ |> acceptMethod ( Post, [] )
1067
+ )
1068
+
1069
+
1070
+ {-| -}
1071
+ expectContentType : String -> Parser ()
1072
+ expectContentType expectedContentType =
1073
+ optionalField "content-type" Json.Decode.string
1074
+ |> Json.Decode.field "headers"
1075
+ |> noErrors
1076
+ |> Internal.Request.Parser
1077
+ |> andThen
1078
+ (\maybeContentType ->
1079
+ case maybeContentType of
1080
+ Nothing ->
1081
+ skipInternal <|
1082
+ ValidationError ("Expected content-type `" ++ expectedContentType ++ "` but there was no content-type header.")
1083
+
1084
+ Just contentType ->
1085
+ if (contentType |> parseContentType) == (expectedContentType |> parseContentType) then
1086
+ succeed ()
1087
+
1088
+ else
1089
+ skipInternal <| ValidationError ("Expected content-type to be " ++ expectedContentType ++ " but it was " ++ contentType)
1090
+ )
1091
+
1092
+
1093
+ rawContentType : Parser (Maybe String)
1094
+ rawContentType =
1095
+ optionalField ("content-type" |> String.toLower) Json.Decode.string
1096
+ |> noErrors
1097
+ |> Internal.Request.Parser
1098
+
1099
+
1100
+ matchesContentType : String -> Parser (Maybe Bool)
1101
+ matchesContentType expectedContentType =
1102
+ optionalField ("content-type" |> String.toLower) Json.Decode.string
1103
+ |> Json.Decode.field "headers"
1104
+ |> Json.Decode.map
1105
+ (\maybeContentType ->
1106
+ case maybeContentType of
1107
+ Nothing ->
1108
+ Nothing
1109
+
1110
+ Just contentType ->
1111
+ if (contentType |> parseContentType) == (expectedContentType |> parseContentType) then
1112
+ Just True
1113
+
1114
+ else
1115
+ Just False
1116
+ )
1117
+ |> noErrors
1118
+ |> Internal.Request.Parser
1119
+
1120
+
1121
+ parseContentType : String -> String
1122
+ parseContentType contentTypeString =
1123
+ contentTypeString
1124
+ |> String.split ";"
1125
+ |> List.head
1126
+ |> Maybe.map String.trim
1127
+ |> Maybe.withDefault contentTypeString
1128
+
1129
+
1130
+ {-| -}
1131
+ expectJsonBody : Json.Decode.Decoder value -> Parser value
1132
+ expectJsonBody jsonBodyDecoder =
1133
+ map2 (\_ secondValue -> secondValue)
1134
+ (expectContentType "application/json")
1135
+ (rawBody
1136
+ |> andThen
1137
+ (\rawBody_ ->
1138
+ (case rawBody_ of
1139
+ Just body_ ->
1140
+ Json.Decode.decodeString
1141
+ jsonBodyDecoder
1142
+ body_
1143
+ |> Result.mapError Json.Decode.errorToString
1144
+
1145
+ Nothing ->
1146
+ Err "Tried to parse JSON body but the request had no body."
1147
+ )
1148
+ |> fromResult
1149
+ )
1150
+ )
1151
+
1152
+
1153
+ {-| -}
1154
+ rawBody : Parser (Maybe String)
1155
+ rawBody =
1156
+ Json.Decode.field "body" (Json.Decode.nullable Json.Decode.string)
1157
+ |> noErrors
1158
+ |> Internal.Request.Parser
1159
+
1160
+
1161
+ {-| Same as [`rawBody`](#rawBody), but will only match when a body is present in the HTTP request.
1162
+ -}
1163
+ expectBody : Parser String
1164
+ expectBody =
1165
+ rawBody
1166
+ |> andThen
1167
+ (Result.fromMaybe "Expected body but none was present."
1168
+ >> fromResult
1169
+ )
1170
+
1171
+
1172
+ {-| -}
1173
+ type Method
1174
+ = Connect
1175
+ | Delete
1176
+ | Get
1177
+ | Head
1178
+ | Options
1179
+ | Patch
1180
+ | Post
1181
+ | Put
1182
+ | Trace
1183
+ | NonStandard String
1184
+
1185
+
1186
+ methodFromString : String -> Method
1187
+ methodFromString rawMethod =
1188
+ case rawMethod |> String.toLower of
1189
+ "connect" ->
1190
+ Connect
1191
+
1192
+ "delete" ->
1193
+ Delete
1194
+
1195
+ "get" ->
1196
+ Get
1197
+
1198
+ "head" ->
1199
+ Head
1200
+
1201
+ "options" ->
1202
+ Options
1203
+
1204
+ "patch" ->
1205
+ Patch
1206
+
1207
+ "post" ->
1208
+ Post
1209
+
1210
+ "put" ->
1211
+ Put
1212
+
1213
+ "trace" ->
1214
+ Trace
1215
+
1216
+ _ ->
1217
+ NonStandard rawMethod
1218
+
1219
+
1220
+ {-| Gets the HTTP Method as a String, like 'GET', 'PUT', etc.
1221
+ -}
1222
+ methodToString : Method -> String
1223
+ methodToString method_ =
1224
+ case method_ of
1225
+ Connect ->
1226
+ "CONNECT"
1227
+
1228
+ Delete ->
1229
+ "DELETE"
1230
+
1231
+ Get ->
1232
+ "GET"
1233
+
1234
+ Head ->
1235
+ "HEAD"
1236
+
1237
+ Options ->
1238
+ "OPTIONS"
1239
+
1240
+ Patch ->
1241
+ "PATCH"
1242
+
1243
+ Post ->
1244
+ "POST"
1245
+
1246
+ Put ->
1247
+ "PUT"
1248
+
1249
+ Trace ->
1250
+ "TRACE"
1251
+
1252
+ NonStandard nonStandardMethod ->
1253
+ nonStandardMethod