git.iko.soy/rowtype-yoga/purescript-yoga-http-api
on feat/custom-type-errors help sign in
refactor: Remove Request wrapper for cleaner syntax
7cce927Mark
src/Yoga/HTTP/API/Route.purs+1−1
@@ -19,7 +19,7 @@ import Yoga.HTTP.API.Path (Path, Root, Lit, Capture, PathCons, Param, QueryParam
19import Yoga.HTTP.API.Route.Auth (BearerToken(..), BasicAuth(..), ApiKeyHeader(..), ApiKeyCookie(..), DigestAuth(..))
19import Yoga.HTTP.API.Route.Auth (BearerToken(..), BasicAuth(..), ApiKeyHeader(..), ApiKeyCookie(..), DigestAuth(..))
20import Yoga.HTTP.API.Route.BearerToken (BearerToken(..))
20import Yoga.HTTP.API.Route.BearerToken (BearerToken(..))
21import Yoga.HTTP.API.Route.Encoding (JSON, FormData, MultipartFormData, PlainText, XML, CustomContentType, NoBody)
21import Yoga.HTTP.API.Route.Encoding (JSON, FormData, MultipartFormData, PlainText, XML, CustomContentType, NoBody)
22−import Yoga.HTTP.API.Route.Handler (HandlerFn, Request)
22+import Yoga.HTTP.API.Route.Handler (HandlerFn)
23import Yoga.HTTP.API.Route.HeaderError (HeaderError(..))
23import Yoga.HTTP.API.Route.HeaderError (HeaderError(..))
24import Yoga.HTTP.API.Route.HeaderValue (class HeaderValue, class HeaderValueType, headerValueType, parseHeader, printHeader)
24import Yoga.HTTP.API.Route.HeaderValue (class HeaderValue, class HeaderValueType, headerValueType, parseHeader, printHeader)
25import Yoga.HTTP.API.Route.Method (DELETE, GET, PATCH, POST, PUT)
25import Yoga.HTTP.API.Route.Method (DELETE, GET, PATCH, POST, PUT)
src/Yoga/HTTP/API/Route/Handler.purs+6−21
@@ -1,6 +1,5 @@
1module Yoga.HTTP.API.Route.Handler
1module Yoga.HTTP.API.Route.Handler
2 ( HandlerFn
2 ( HandlerFn
3− , Request(..)
4 , class DefaultRequestFields
3 , class DefaultRequestFields
5 , class DefaultRequestFieldsRL
4 , class DefaultRequestFieldsRL
6 , class SegmentPathParams
5 , class SegmentPathParams
@@ -22,20 +21,6 @@ import Prim.RowList as RL
22import Yoga.HTTP.API.Path (Path, PathCons, Capture, Param, QueryParams, Required)
21import Yoga.HTTP.API.Path (Path, PathCons, Capture, Param, QueryParams, Required)
23import Yoga.HTTP.API.Route.Encoding (JSON, NoBody)
22import Yoga.HTTP.API.Route.Encoding (JSON, NoBody)
24
23
25−--------------------------------------------------------------------------------
26−-- Request Data Type
27−--------------------------------------------------------------------------------
28−
29−-- | Request data combining headers and body
30−-- |
31−-- | Usage:
32−-- | Request { body :: JSON User } -- body only
33−-- | Request { headers :: { auth :: String } } -- headers only
34−-- | Request { body :: JSON User, headers :: { auth :: String } } -- both
35−-- | Request {} -- neither
36−data Request :: Type -> Type
37−data Request r = Request r
38−
39--------------------------------------------------------------------------------
24--------------------------------------------------------------------------------
40-- Handler Type
25-- Handler Type
41--------------------------------------------------------------------------------
26--------------------------------------------------------------------------------
@@ -162,7 +147,7 @@ instance encodingBodyNoBody :: EncodingBody NoBody Unit
162-- RequestHeaders: Extract headers row from a request type
147-- RequestHeaders: Extract headers row from a request type
163--------------------------------------------------------------------------------
148--------------------------------------------------------------------------------
164
149
165−-- | Extract the headers row from a Request type.
150+-- | Extract the headers row from a request record type.
166-- |
151-- |
167-- | The request is expected to have a `headers` field.
152-- | The request is expected to have a `headers` field.
168class RequestHeaders (request :: Type) (headers :: Row Type) | request -> headers
153class RequestHeaders (request :: Type) (headers :: Row Type) | request -> headers
@@ -170,13 +155,13 @@ class RequestHeaders (request :: Type) (headers :: Row Type) | request -> header
170instance requestHeadersRequest ::
155instance requestHeadersRequest ::
171 ( Row.Cons "headers" (Record headers) _rest requestRow
156 ( Row.Cons "headers" (Record headers) _rest requestRow
172 ) =>
157 ) =>
173− RequestHeaders (Request (Record requestRow)) headers
158+ RequestHeaders (Record requestRow) headers
174
159
175--------------------------------------------------------------------------------
160--------------------------------------------------------------------------------
176-- RequestCookies: Extract cookies row from a request type
161-- RequestCookies: Extract cookies row from a request type
177--------------------------------------------------------------------------------
162--------------------------------------------------------------------------------
178
163
179−-- | Extract the cookies row from a Request type.
164+-- | Extract the cookies row from a request record type.
180-- |
165-- |
181-- | The request is expected to have a `cookies` field.
166-- | The request is expected to have a `cookies` field.
182class RequestCookies (request :: Type) (cookies :: Row Type) | request -> cookies
167class RequestCookies (request :: Type) (cookies :: Row Type) | request -> cookies
@@ -184,13 +169,13 @@ class RequestCookies (request :: Type) (cookies :: Row Type) | request -> cookie
184instance requestCookiesRequest ::
169instance requestCookiesRequest ::
185 ( Row.Cons "cookies" (Record cookies) _rest requestRow
170 ( Row.Cons "cookies" (Record cookies) _rest requestRow
186 ) =>
171 ) =>
187− RequestCookies (Request (Record requestRow)) cookies
172+ RequestCookies (Record requestRow) cookies
188
173
189--------------------------------------------------------------------------------
174--------------------------------------------------------------------------------
190-- RequestBody: Extract body encoding from a request type
175-- RequestBody: Extract body encoding from a request type
191--------------------------------------------------------------------------------
176--------------------------------------------------------------------------------
192
177
193−-- | Extract the body encoding type from a Request type.
178+-- | Extract the body encoding type from a request record type.
194-- |
179-- |
195-- | The request is expected to have a `body` field.
180-- | The request is expected to have a `body` field.
196class RequestBody (request :: Type) (encoding :: Type) | request -> encoding
181class RequestBody (request :: Type) (encoding :: Type) | request -> encoding
@@ -198,7 +183,7 @@ class RequestBody (request :: Type) (encoding :: Type) | request -> encoding
198instance requestBodyRequest ::
183instance requestBodyRequest ::
199 ( Row.Cons "body" encoding _rest requestRow
184 ( Row.Cons "body" encoding _rest requestRow
200 ) =>
185 ) =>
201− RequestBody (Request (Record requestRow)) encoding
186+ RequestBody (Record requestRow) encoding
202
187
203--------------------------------------------------------------------------------
188--------------------------------------------------------------------------------
204-- DefaultRequestFields: Compute defaults for missing request fields
189-- DefaultRequestFields: Compute defaults for missing request fields
src/Yoga/HTTP/API/Route/Route.purs+5−6
@@ -12,9 +12,8 @@ import Prim.Row (class Cons, class Lacks, class Union)
12import Prim.RowList (class RowToList, RowList)
12import Prim.RowList (class RowToList, RowList)
13import Prim.RowList as RL
13import Prim.RowList as RL
14import Type.Proxy (Proxy(..))
14import Type.Proxy (Proxy(..))
15−import Unsafe.Coerce (unsafeCoerce)
16import Yoga.HTTP.API.Path (class PathPattern, pathPattern)
15import Yoga.HTTP.API.Path (class PathPattern, pathPattern)
17−import Yoga.HTTP.API.Route.Handler (Request, class DefaultRequestFields, class SegmentPathParams, class SegmentQueryParams)
16+import Yoga.HTTP.API.Route.Handler (class DefaultRequestFields, class SegmentPathParams, class SegmentQueryParams)
18import Yoga.HTTP.API.Route.OpenAPI (class CollectOperations, class RenderHeadersSchema, renderHeadersSchema, class RenderCookieParamsSchema, renderCookieParamsSchema, class RenderPathParamsSchema, renderPathParamsSchema, class RenderQueryParamsSchema, renderQueryParamsSchema, class RenderRequestBodySchema, renderRequestBodySchema, class RenderVariantResponseSchemaRL, renderVariantResponseSchemaRL, class DetectSecurity, detectSecurity, class DetectCookieSecurity, detectCookieSecurity, class ToOpenAPI, toOpenAPIImpl, class CollectSchemas, collectSchemas, class CollectVariantSchemasRL, collectVariantSchemasRL, class CollectRouteSchemas, class CollectSchemaNames, class CollectVariantSchemaNames, class CollectRouteSchemaNames)
17import Yoga.HTTP.API.Route.OpenAPI (class CollectOperations, class RenderHeadersSchema, renderHeadersSchema, class RenderCookieParamsSchema, renderCookieParamsSchema, class RenderPathParamsSchema, renderPathParamsSchema, class RenderQueryParamsSchema, renderQueryParamsSchema, class RenderRequestBodySchema, renderRequestBodySchema, class RenderVariantResponseSchemaRL, renderVariantResponseSchemaRL, class DetectSecurity, detectSecurity, class DetectCookieSecurity, detectCookieSecurity, class ToOpenAPI, toOpenAPIImpl, class CollectSchemas, collectSchemas, class CollectVariantSchemasRL, collectVariantSchemasRL, class CollectRouteSchemas, class CollectSchemaNames, class CollectVariantSchemaNames, class CollectRouteSchemaNames)
19import Yoga.HTTP.API.Route.OpenAPIMetadata (class HasOperationMetadata, operationMetadata)
18import Yoga.HTTP.API.Route.OpenAPIMetadata (class HasOperationMetadata, operationMetadata)
20import Yoga.HTTP.API.Route.RenderMethod (class RenderMethod, renderMethod)
19import Yoga.HTTP.API.Route.RenderMethod (class RenderMethod, renderMethod)
@@ -67,9 +66,9 @@ instance
67 , RenderRequestBodySchema encoding
66 , RenderRequestBodySchema encoding
68 , RowToList userResp rl
67 , RowToList userResp rl
69 , RenderVariantResponseSchemaRL rl
68 , RenderVariantResponseSchemaRL rl
70− , HasOperationMetadata (Route method segments (Request (Record partialRequest)) userResp)
69+ , HasOperationMetadata (Route method segments (Record partialRequest) userResp)
71 ) =>
70 ) =>
72− ToOpenAPI (Route method segments (Request (Record partialRequest)) userResp) where
71+ ToOpenAPI (Route method segments (Record partialRequest) userResp) where
73 toOpenAPIImpl proxy =
72 toOpenAPIImpl proxy =
74 let
73 let
75 methodStr = renderMethod (Proxy :: Proxy method)
74 methodStr = renderMethod (Proxy :: Proxy method)
@@ -122,7 +121,7 @@ instance
122 , RowToList userResp rl
121 , RowToList userResp rl
123 , CollectVariantSchemasRL rl
122 , CollectVariantSchemasRL rl
124 ) =>
123 ) =>
125− CollectRouteSchemas (Route method segments (Request (Record partialRequest)) userResp) where
124+ CollectRouteSchemas (Route method segments (Record partialRequest) userResp) where
126 collectRouteSchemas _ =
125 collectRouteSchemas _ =
127 let
126 let
128 requestSchemas = collectSchemas (Proxy :: Proxy encoding)
127 requestSchemas = collectSchemas (Proxy :: Proxy encoding)
@@ -138,4 +137,4 @@ instance
138 , CollectVariantSchemaNames rl respNames
137 , CollectVariantSchemaNames rl respNames
139 , Union reqNames respNames names
138 , Union reqNames respNames names
140 ) =>
139 ) =>
141− CollectRouteSchemaNames (Route method segments (Request (Record partialRequest)) userResp) names
140+ CollectRouteSchemaNames (Route method segments (Record partialRequest) userResp) names
src/Yoga/HTTP/API/Route/RouteHandler.purs+1−2
@@ -14,7 +14,6 @@ import Prim.RowList (class RowToList)
14import Unsafe.Coerce (unsafeCoerce)
14import Unsafe.Coerce (unsafeCoerce)
15import Yoga.HTTP.API.Route.Handler
15import Yoga.HTTP.API.Route.Handler
16 ( HandlerFn
16 ( HandlerFn
17− , Request
18 , class DefaultRequestFields
17 , class DefaultRequestFields
19 , class EncodingBody
18 , class EncodingBody
20 , class SegmentPathParams
19 , class SegmentPathParams
@@ -42,7 +41,7 @@ instance
42 , ConvertResponseVariant userResp respVariant
41 , ConvertResponseVariant userResp respVariant
43 ) =>
42 ) =>
44 RouteHandler
43 RouteHandler
45− (Route method segments (Request (Record partialRequest)) userResp)
44+ (Route method segments (Record partialRequest) userResp)
46 pathParams
45 pathParams
47 queryParams
46 queryParams
48 fullHeaders
47 fullHeaders
test-compile-fail/cases/BodyTypeMismatch.purs+2−2
@@ -5,14 +5,14 @@ import Prelude
5import Data.Variant (Variant)
5import Data.Variant (Variant)
6import Effect.Aff (Aff)
6import Effect.Aff (Aff)
7import Yoga.HTTP.API.Path (Path, Lit)
7import Yoga.HTTP.API.Path (Path, Lit)
8−import Yoga.HTTP.API.Route.Handler (Request)
8+import Yoga.HTTP.API.Route.Handler
9import Yoga.HTTP.API.Route.Method (GET)
9import Yoga.HTTP.API.Route.Method (GET)
10import Yoga.HTTP.API.Route.Response (Response, respondNoHeaders)
10import Yoga.HTTP.API.Route.Response (Response, respondNoHeaders)
11import Yoga.HTTP.API.Route.Route (Route)
11import Yoga.HTTP.API.Route.Route (Route)
12import Yoga.HTTP.API.Route.RouteHandler (Handler, mkHandler)
12import Yoga.HTTP.API.Route.RouteHandler (Handler, mkHandler)
13
13
14-- Route has no body (defaults to NoBody/Unit), but handler uses body as String
14-- Route has no body (defaults to NoBody/Unit), but handler uses body as String
15−type MyRoute = Route GET (Path (Lit "health")) (Request {}) (ok :: { body :: String })
15+type MyRoute = Route GET (Path (Lit "health")) {} (ok :: { body :: String })
16
16
17test :: Handler MyRoute
17test :: Handler MyRoute
18test = mkHandler \{ body } ->
18test = mkHandler \{ body } ->
test-compile-fail/cases/DuplicateCaptureNames.purs+2−2
@@ -7,14 +7,14 @@ import Data.Variant (Variant)
7import Effect.Aff (Aff)
7import Effect.Aff (Aff)
8import Yoga.HTTP.API.Path (Path, Lit, Capture, type (/), type (:))
8import Yoga.HTTP.API.Path (Path, Lit, Capture, type (/), type (:))
9import Yoga.HTTP.API.Route.Encoding (NoBody)
9import Yoga.HTTP.API.Route.Encoding (NoBody)
10−import Yoga.HTTP.API.Route.Handler (Request)
10+import Yoga.HTTP.API.Route.Handler
11import Yoga.HTTP.API.Route.Method (GET)
11import Yoga.HTTP.API.Route.Method (GET)
12import Yoga.HTTP.API.Route.Response (Response, respondNoHeaders)
12import Yoga.HTTP.API.Route.Response (Response, respondNoHeaders)
13import Yoga.HTTP.API.Route.Route (Route)
13import Yoga.HTTP.API.Route.Route (Route)
14import Yoga.HTTP.API.Route.RouteHandler (Handler, mkHandler)
14import Yoga.HTTP.API.Route.RouteHandler (Handler, mkHandler)
15
15
16-- Two captures both named "id" with different types
16-- Two captures both named "id" with different types
17−type MyRoute = Route GET (Path (Capture "id" Int / Capture "id" String)) (Request {}) (ok :: { body :: String })
17+type MyRoute = Route GET (Path (Capture "id" Int / Capture "id" String)) {} (ok :: { body :: String })
18
18
19test :: Handler MyRoute
19test :: Handler MyRoute
20test = mkHandler \{ path: { id } } ->
20test = mkHandler \{ path: { id } } ->
test-compile-fail/cases/HandlerSignatureMismatch.purs+2−2
@@ -7,13 +7,13 @@ import Data.Variant (Variant)
7import Effect.Aff (Aff)
7import Effect.Aff (Aff)
8import Yoga.HTTP.API.Path (Path, Lit, Capture, type (/), type (:))
8import Yoga.HTTP.API.Path (Path, Lit, Capture, type (/), type (:))
9import Yoga.HTTP.API.Route.Encoding (NoBody)
9import Yoga.HTTP.API.Route.Encoding (NoBody)
10−import Yoga.HTTP.API.Route.Handler (Request)
10+import Yoga.HTTP.API.Route.Handler
11import Yoga.HTTP.API.Route.Method (GET)
11import Yoga.HTTP.API.Route.Method (GET)
12import Yoga.HTTP.API.Route.Response (Response, respondNoHeaders)
12import Yoga.HTTP.API.Route.Response (Response, respondNoHeaders)
13import Yoga.HTTP.API.Route.Route (Route)
13import Yoga.HTTP.API.Route.Route (Route)
14import Yoga.HTTP.API.Route.RouteHandler (Handler, mkHandler)
14import Yoga.HTTP.API.Route.RouteHandler (Handler, mkHandler)
15
15
16−type MyRoute = Route GET (Path (Lit "users" / Capture "id" Int)) (Request {}) (ok :: { body :: String })
16+type MyRoute = Route GET (Path (Lit "users" / Capture "id" Int)) {} (ok :: { body :: String })
17
17
18-- Handler takes { id :: String } but route has Capture "id" Int
18-- Handler takes { id :: String } but route has Capture "id" Int
19test :: Handler MyRoute
19test :: Handler MyRoute
test-compile-fail/cases/InvalidResponseRecordStructure.purs+2−2
@@ -3,14 +3,14 @@ module Test.CompileFail.InvalidResponseRecordStructure where
3
3
4import Prelude
4import Prelude
5import Yoga.HTTP.API.Path (Path, Lit)
5import Yoga.HTTP.API.Path (Path, Lit)
6−import Yoga.HTTP.API.Route.Handler (Request)
6+import Yoga.HTTP.API.Route.Handler
7import Yoga.HTTP.API.Route.Method (GET)
7import Yoga.HTTP.API.Route.Method (GET)
8import Yoga.HTTP.API.Route.Route (Route)
8import Yoga.HTTP.API.Route.Route (Route)
9import Yoga.HTTP.API.Route.RouteHandler (Handler, mkHandler)
9import Yoga.HTTP.API.Route.RouteHandler (Handler, mkHandler)
10import Yoga.HTTP.API.Route.Response (respondNoHeaders)
10import Yoga.HTTP.API.Route.Response (respondNoHeaders)
11
11
12-- Response record has "status" field which is not "body" or "headers"
12-- Response record has "status" field which is not "body" or "headers"
13−type MyRoute = Route GET (Path (Lit "health")) (Request {}) (ok :: { body :: String, status :: Int })
13+type MyRoute = Route GET (Path (Lit "health")) {} (ok :: { body :: String, status :: Int })
14
14
15test :: Handler MyRoute
15test :: Handler MyRoute
16test = mkHandler \_ ->
16test = mkHandler \_ ->
test-compile-fail/cases/MissingRequiredQueryParam.purs+2−2
@@ -5,7 +5,7 @@ import Prelude
5import Data.Variant (Variant)
5import Data.Variant (Variant)
6import Effect.Aff (Aff)
6import Effect.Aff (Aff)
7import Yoga.HTTP.API.Path (Path, Lit, QueryParams, type (:?))
7import Yoga.HTTP.API.Path (Path, Lit, QueryParams, type (:?))
8−import Yoga.HTTP.API.Route.Handler (Request)
8+import Yoga.HTTP.API.Route.Handler
9import Yoga.HTTP.API.Route.Method (GET)
9import Yoga.HTTP.API.Route.Method (GET)
10import Yoga.HTTP.API.Route.Response (Response, respondNoHeaders)
10import Yoga.HTTP.API.Route.Response (Response, respondNoHeaders)
11import Yoga.HTTP.API.Route.Route (Route)
11import Yoga.HTTP.API.Route.Route (Route)
@@ -13,7 +13,7 @@ import Yoga.HTTP.API.Route.RouteHandler (Handler, mkHandler)
13
13
14-- Query param "limit" is optional (no Required wrapper), so handler gets Maybe Int
14-- Query param "limit" is optional (no Required wrapper), so handler gets Maybe Int
15-- But handler tries to use it as plain Int
15-- But handler tries to use it as plain Int
16−type MyRoute = Route GET (Path (Lit "items") :? (limit :: Int)) (Request {}) (ok :: { body :: String })
16+type MyRoute = Route GET (Path (Lit "items") :? (limit :: Int)) {} (ok :: { body :: String })
17
17
18test :: Handler MyRoute
18test :: Handler MyRoute
19test = mkHandler \{ query: { limit } } ->
19test = mkHandler \{ query: { limit } } ->
test-compile-fail/cases/SchemaNameCollision.purs+3−3
@@ -4,7 +4,7 @@ module Test.CompileFail.SchemaNameCollision where
4import Data.Maybe (Maybe(..))
4import Data.Maybe (Maybe(..))
5import Yoga.HTTP.API.Path (Path, Lit)
5import Yoga.HTTP.API.Path (Path, Lit)
6import Yoga.HTTP.API.Route.Encoding (JSON)
6import Yoga.HTTP.API.Route.Encoding (JSON)
7−import Yoga.HTTP.API.Route.Handler (Request)
7+import Yoga.HTTP.API.Route.Handler
8import Yoga.HTTP.API.Route.Method (GET, POST)
8import Yoga.HTTP.API.Route.Method (GET, POST)
9import Yoga.HTTP.API.Route.OpenAPIMetadata (Schema)
9import Yoga.HTTP.API.Route.OpenAPIMetadata (Schema)
10import Yoga.HTTP.API.Route.OpenAPI (buildOpenAPISpec, OpenAPISpec)
10import Yoga.HTTP.API.Route.OpenAPI (buildOpenAPISpec, OpenAPISpec)
@@ -14,8 +14,8 @@ type UserV1 = { id :: Int, name :: String }
14type UserV2 = { id :: Int, email :: String, age :: Int }
14type UserV2 = { id :: Int, email :: String, age :: Int }
15
15
16type CollisionAPI =
16type CollisionAPI =
17− { getUser :: Route GET (Path (Lit "users")) (Request {}) (ok :: { body :: Schema "User" UserV1 })
17+ { getUser :: Route GET (Path (Lit "users")) {} (ok :: { body :: Schema "User" UserV1 })
18− , createUser :: Route POST (Path (Lit "users")) (Request { body :: JSON (Schema "User" UserV2) }) (created :: { body :: Schema "User" UserV2 })
18+ , createUser :: Route POST (Path (Lit "users")) { body :: JSON (Schema "User" UserV2) } (created :: { body :: Schema "User" UserV2 })
19 }
19 }
20
20
21spec :: OpenAPISpec
21spec :: OpenAPISpec
test-compile-fail/cases/WrongResponseVariantLabel.purs+2−2
@@ -5,14 +5,14 @@ import Prelude
5import Data.Variant (Variant)
5import Data.Variant (Variant)
6import Effect.Aff (Aff)
6import Effect.Aff (Aff)
7import Yoga.HTTP.API.Path (Path, Lit)
7import Yoga.HTTP.API.Path (Path, Lit)
8−import Yoga.HTTP.API.Route.Handler (Request)
8+import Yoga.HTTP.API.Route.Handler
9import Yoga.HTTP.API.Route.Method (GET)
9import Yoga.HTTP.API.Route.Method (GET)
10import Yoga.HTTP.API.Route.Response (Response, respondNoHeaders)
10import Yoga.HTTP.API.Route.Response (Response, respondNoHeaders)
11import Yoga.HTTP.API.Route.Route (Route)
11import Yoga.HTTP.API.Route.Route (Route)
12import Yoga.HTTP.API.Route.RouteHandler (Handler, mkHandler)
12import Yoga.HTTP.API.Route.RouteHandler (Handler, mkHandler)
13
13
14-- Route only has "ok" response, no "notFound"
14-- Route only has "ok" response, no "notFound"
15−type MyRoute = Route GET (Path (Lit "health")) (Request {}) (ok :: { body :: String })
15+type MyRoute = Route GET (Path (Lit "health")) {} (ok :: { body :: String })
16
16
17test :: Handler MyRoute
17test :: Handler MyRoute
18test = mkHandler \_ ->
18test = mkHandler \_ ->
test/Test/APIRecordTest.purs+4−4
@@ -9,7 +9,7 @@ import Effect (Effect)
9import Effect.Aff (Aff)
9import Effect.Aff (Aff)
10import Type.Proxy (Proxy(..))
10import Type.Proxy (Proxy(..))
11import Yoga.HTTP.API.Path (type (/), type (:))
11import Yoga.HTTP.API.Path (type (/), type (:))
12−import Yoga.HTTP.API.Route (GET, POST, Route, Request, JSON, respondNoHeaders, buildOpenAPISpec, collectOperations, mkHandler, apiHandlers)
12+import Yoga.HTTP.API.Route (GET, POST, Route, JSON, respondNoHeaders, buildOpenAPISpec, collectOperations, mkHandler, apiHandlers)
13import Yoga.JSON (writeJSON)
13import Yoga.JSON (writeJSON)
14import ViTest (ViTest, describe, test)
14import ViTest (ViTest, describe, test)
15import ViTest.Expect (expectToBe)
15import ViTest.Expect (expectToBe)
@@ -24,9 +24,9 @@ expectToEqual expected actual = expectToBe true (expected == actual)
24type User = { id :: Int, name :: String }
24type User = { id :: Int, name :: String }
25
25
26type TestAPI =
26type TestAPI =
27− { getUser :: Route GET ("users" / "id" : Int) (Request {}) (ok :: { body :: User })
27+ { getUser :: Route GET ("users" / "id" : Int) {} (ok :: { body :: User })
28− , listUsers :: Route GET "users" (Request {}) (ok :: { body :: Array User })
28+ , listUsers :: Route GET "users" {} (ok :: { body :: Array User })
29− , createUser :: Route POST "users" (Request { body :: JSON User }) (created :: { body :: User })
29+ , createUser :: Route POST "users" { body :: JSON User } (created :: { body :: User })
30 }
30 }
31
31
32--------------------------------------------------------------------------------
32--------------------------------------------------------------------------------
test/Test/BearerAuthTest.purs+8−8
@@ -6,7 +6,7 @@ import Data.Array as Array
6import Data.Maybe (Maybe(..))
6import Data.Maybe (Maybe(..))
7import Data.String as String
7import Data.String as String
8import Effect (Effect)
8import Effect (Effect)
9−import Yoga.HTTP.API.Route (GET, Route, Request, buildOpenAPISpec)
9+import Yoga.HTTP.API.Route (GET, Route, buildOpenAPISpec)
10import Yoga.HTTP.API.Route.Auth (BearerToken, BasicAuth, ApiKeyHeader, DigestAuth)
10import Yoga.HTTP.API.Route.Auth (BearerToken, BasicAuth, ApiKeyHeader, DigestAuth)
11import Yoga.JSON (writeJSON)
11import Yoga.JSON (writeJSON)
12import Test.OpenAPIValidation (validate)
12import Test.OpenAPIValidation (validate)
@@ -18,25 +18,25 @@ import ViTest.Expect (expectToBe)
18--------------------------------------------------------------------------------
18--------------------------------------------------------------------------------
19
19
20type BearerAuthAPI =
20type BearerAuthAPI =
21− { getProtected :: Route GET "protected" (Request { headers :: { authorization :: BearerToken } }) (ok :: { body :: { message :: String } })
21+ { getProtected :: Route GET "protected" { headers :: { authorization :: BearerToken } } (ok :: { body :: { message :: String } })
22 }
22 }
23
23
24type BasicAuthAPI =
24type BasicAuthAPI =
25− { getProtected :: Route GET "protected" (Request { headers :: { authorization :: BasicAuth } }) (ok :: { body :: { message :: String } })
25+ { getProtected :: Route GET "protected" { headers :: { authorization :: BasicAuth } } (ok :: { body :: { message :: String } })
26 }
26 }
27
27
28type ApiKeyAPI =
28type ApiKeyAPI =
29− { getProtected :: Route GET "protected" (Request { headers :: { apiKey :: ApiKeyHeader } }) (ok :: { body :: { message :: String } })
29+ { getProtected :: Route GET "protected" { headers :: { apiKey :: ApiKeyHeader } } (ok :: { body :: { message :: String } })
30 }
30 }
31
31
32type DigestAuthAPI =
32type DigestAuthAPI =
33− { getProtected :: Route GET "protected" (Request { headers :: { authorization :: DigestAuth } }) (ok :: { body :: { message :: String } })
33+ { getProtected :: Route GET "protected" { headers :: { authorization :: DigestAuth } } (ok :: { body :: { message :: String } })
34 }
34 }
35
35
36type MultiAuthAPI =
36type MultiAuthAPI =
37− { bearerEndpoint :: Route GET "bearer" (Request { headers :: { authorization :: BearerToken } }) (ok :: { body :: { message :: String } })
37+ { bearerEndpoint :: Route GET "bearer" { headers :: { authorization :: BearerToken } } (ok :: { body :: { message :: String } })
38− , basicEndpoint :: Route GET "basic" (Request { headers :: { authorization :: BasicAuth } }) (ok :: { body :: { message :: String } })
38+ , basicEndpoint :: Route GET "basic" { headers :: { authorization :: BasicAuth } } (ok :: { body :: { message :: String } })
39− , apiKeyEndpoint :: Route GET "apikey" (Request { headers :: { xApiKey :: ApiKeyHeader } }) (ok :: { body :: { message :: String } })
39+ , apiKeyEndpoint :: Route GET "apikey" { headers :: { xApiKey :: ApiKeyHeader } } (ok :: { body :: { message :: String } })
40 }
40 }
41
41
42--------------------------------------------------------------------------------
42--------------------------------------------------------------------------------
test/Test/ComprehensiveExample.purs+13−15
@@ -7,7 +7,7 @@ import Data.Maybe (Maybe(..))
7import Effect (Effect)
7import Effect (Effect)
8import Type.Function (type (#))
8import Type.Function (type (#))
9import Yoga.HTTP.API.Path (type (:), type (/), type (:?))
9import Yoga.HTTP.API.Path (type (:), type (/), type (:?))
10−import Yoga.HTTP.API.Route (GET, POST, PUT, DELETE, Route, Request, buildOpenAPISpec)
10+import Yoga.HTTP.API.Route (GET, POST, PUT, DELETE, Route, buildOpenAPISpec)
11import Yoga.HTTP.API.Route.Auth (BearerToken, ApiKeyHeader, BasicAuth)
11import Yoga.HTTP.API.Route.Auth (BearerToken, ApiKeyHeader, BasicAuth)
12import Yoga.HTTP.API.Route.Encoding (JSON, PlainText, XML)
12import Yoga.HTTP.API.Route.Encoding (JSON, PlainText, XML)
13import Yoga.HTTP.API.Route.OpenAPIMetadata (Description, Example, ExampleValue, Examples, Schema)
13import Yoga.HTTP.API.Route.OpenAPIMetadata (Description, Example, ExampleValue, Examples, Schema)
@@ -21,65 +21,63 @@ type ComprehensiveAPI =
21 { -- Simple GET with path parameter and authentication
21 { -- Simple GET with path parameter and authentication
22 getUser ::
22 getUser ::
23 Route GET ("users" / "id" : Int)
23 Route GET ("users" / "id" : Int)
24− (Request { headers :: { authorization :: BearerToken } })
24+ { headers :: { authorization :: BearerToken } }
25 (ok :: { body :: Schema "User" User })
25 (ok :: { body :: Schema "User" User })
26
26
27 , -- List users with query parameters
27 , -- List users with query parameters
28 listUsers ::
28 listUsers ::
29 Route GET ("users" :? { limit :: Int # Example "10", offset :: Int # Example "0" })
29 Route GET ("users" :? { limit :: Int # Example "10", offset :: Int # Example "0" })
30− (Request {})
30+ {}
31 (ok :: { body :: Array User })
31 (ok :: { body :: Array User })
32
32
33 , -- POST with JSON body and schema
33 , -- POST with JSON body and schema
34 createUser ::
34 createUser ::
35 Route POST "users"
35 Route POST "users"
36− (Request { body :: JSON (Schema "CreateUserRequest" CreateUserRequest) })
36+ { body :: JSON (Schema "CreateUserRequest" CreateUserRequest) }
37 (created :: { body :: Schema "User" User })
37 (created :: { body :: Schema "User" User })
38
38
39 , -- PUT with authentication and JSON body
39 , -- PUT with authentication and JSON body
40 updateUser ::
40 updateUser ::
41 Route PUT ("users" / "id" : Int)
41 Route PUT ("users" / "id" : Int)
42− ( Request
43− { headers :: { authorization :: BearerToken }
42+ { headers :: { authorization :: BearerToken }
44− , body :: JSON UpdateUserRequest
43+ , body :: JSON UpdateUserRequest
45− }
44+ }
46− )
47 (ok :: { body :: User })
45 (ok :: { body :: User })
48
46
49 , -- DELETE with authentication
47 , -- DELETE with authentication
50 deleteUser ::
48 deleteUser ::
51 Route DELETE ("users" / "id" : Int)
49 Route DELETE ("users" / "id" : Int)
52− (Request { headers :: { authorization :: BearerToken } })
50+ { headers :: { authorization :: BearerToken } }
53 (noContent :: { body :: {} })
51 (noContent :: { body :: {} })
54
52
55 , -- Multiple content types - XML
53 , -- Multiple content types - XML
56 exportUser ::
54 exportUser ::
57 Route GET ("users" / "id" : Int / "export")
55 Route GET ("users" / "id" : Int / "export")
58− (Request {})
56+ {}
59 (ok :: { body :: XML User })
57 (ok :: { body :: XML User })
60
58
61 , -- Plain text response
59 , -- Plain text response
62 healthCheck ::
60 healthCheck ::
63 Route GET "health"
61 Route GET "health"
64− (Request {})
62+ {}
65 (ok :: { body :: PlainText String })
63 (ok :: { body :: PlainText String })
66
64
67 , -- API Key authentication
65 , -- API Key authentication
68 getStats ::
66 getStats ::
69 Route GET "stats"
67 Route GET "stats"
70− (Request { headers :: { xApiKey :: ApiKeyHeader } })
68+ { headers :: { xApiKey :: ApiKeyHeader } }
71 (ok :: { body :: Stats })
69 (ok :: { body :: Stats })
72
70
73 , -- Basic auth
71 , -- Basic auth
74 login ::
72 login ::
75 Route POST "login"
73 Route POST "login"
76− (Request { headers :: { authorization :: BasicAuth } })
74+ { headers :: { authorization :: BasicAuth } }
77 (ok :: { body :: { token :: String # Description "JWT access token" } })
75 (ok :: { body :: { token :: String # Description "JWT access token" } })
78
76
79 , -- Path with examples
77 , -- Path with examples
80 getUserPosts ::
78 getUserPosts ::
81 Route GET ("users" / "userId" : (Int # Examples (alice :: ExampleValue "1", bob :: ExampleValue "2")) / "posts")
79 Route GET ("users" / "userId" : (Int # Examples (alice :: ExampleValue "1", bob :: ExampleValue "2")) / "posts")
82− (Request {})
80+ {}
83 (ok :: { body :: Array Post })
81 (ok :: { body :: Array Post })
84 }
82 }
85
83
test/Test/ContentTypeTest.purs+16−16
@@ -5,7 +5,7 @@ import Prelude
5import Data.Maybe (Maybe(..))
5import Data.Maybe (Maybe(..))
6import Data.String as String
6import Data.String as String
7import Effect (Effect)
7import Effect (Effect)
8−import Yoga.HTTP.API.Route (GET, POST, PUT, Route, Request, buildOpenAPISpec)
8+import Yoga.HTTP.API.Route (GET, POST, PUT, Route, buildOpenAPISpec)
9import Yoga.HTTP.API.Route.Encoding (JSON, FormData, MultipartFormData, PlainText, XML, CustomContentType)
9import Yoga.HTTP.API.Route.Encoding (JSON, FormData, MultipartFormData, PlainText, XML, CustomContentType)
10import Yoga.JSON (writeJSON)
10import Yoga.JSON (writeJSON)
11import ViTest (ViTest, describe, test)
11import ViTest (ViTest, describe, test)
@@ -21,7 +21,7 @@ testRequestContentTypes :: Effect ViTest
21testRequestContentTypes = describe "Request Content Types" do
21testRequestContentTypes = describe "Request Content Types" do
22 _ <- test "JSON request body generates application/json" do
22 _ <- test "JSON request body generates application/json" do
23 let
23 let
24− spec = buildOpenAPISpec @{ createUser :: Route POST "users" (Request { body :: JSON User }) (ok :: { body :: User }) }
24+ spec = buildOpenAPISpec @{ createUser :: Route POST "users" { body :: JSON User } (ok :: { body :: User }) }
25 { title: "API"
25 { title: "API"
26 , version: "1.0.0"
26 , version: "1.0.0"
27 , description: Nothing
27 , description: Nothing
@@ -34,7 +34,7 @@ testRequestContentTypes = describe "Request Content Types" do
34
34
35 _ <- test "FormData request body generates application/x-www-form-urlencoded" do
35 _ <- test "FormData request body generates application/x-www-form-urlencoded" do
36 let
36 let
37− spec = buildOpenAPISpec @{ createUser :: Route POST "users" (Request { body :: FormData User }) (ok :: { body :: JSON User }) }
37+ spec = buildOpenAPISpec @{ createUser :: Route POST "users" { body :: FormData User } (ok :: { body :: JSON User }) }
38 { title: "API"
38 { title: "API"
39 , version: "1.0.0"
39 , version: "1.0.0"
40 , description: Nothing
40 , description: Nothing
@@ -47,7 +47,7 @@ testRequestContentTypes = describe "Request Content Types" do
47
47
48 _ <- test "MultipartFormData request body generates multipart/form-data" do
48 _ <- test "MultipartFormData request body generates multipart/form-data" do
49 let
49 let
50− spec = buildOpenAPISpec @{ uploadFile :: Route POST "upload" (Request { body :: MultipartFormData FileUpload }) (ok :: { body :: { success :: Boolean } }) }
50+ spec = buildOpenAPISpec @{ uploadFile :: Route POST "upload" { body :: MultipartFormData FileUpload } (ok :: { body :: { success :: Boolean } }) }
51 { title: "API"
51 { title: "API"
52 , version: "1.0.0"
52 , version: "1.0.0"
53 , description: Nothing
53 , description: Nothing
@@ -59,7 +59,7 @@ testRequestContentTypes = describe "Request Content Types" do
59
59
60 _ <- test "PlainText request body generates text/plain" do
60 _ <- test "PlainText request body generates text/plain" do
61 let
61 let
62− spec = buildOpenAPISpec @{ echo :: Route POST "echo" (Request { body :: PlainText String }) (ok :: { body :: PlainText String }) }
62+ spec = buildOpenAPISpec @{ echo :: Route POST "echo" { body :: PlainText String } (ok :: { body :: PlainText String }) }
63 { title: "API"
63 { title: "API"
64 , version: "1.0.0"
64 , version: "1.0.0"
65 , description: Nothing
65 , description: Nothing
@@ -71,7 +71,7 @@ testRequestContentTypes = describe "Request Content Types" do
71
71
72 _ <- test "XML request body generates application/xml" do
72 _ <- test "XML request body generates application/xml" do
73 let
73 let
74− spec = buildOpenAPISpec @{ updateDoc :: Route PUT "document" (Request { body :: XML XmlDocument }) (ok :: { body :: XML XmlDocument }) }
74+ spec = buildOpenAPISpec @{ updateDoc :: Route PUT "document" { body :: XML XmlDocument } (ok :: { body :: XML XmlDocument }) }
75 { title: "API"
75 { title: "API"
76 , version: "1.0.0"
76 , version: "1.0.0"
77 , description: Nothing
77 , description: Nothing
@@ -83,7 +83,7 @@ testRequestContentTypes = describe "Request Content Types" do
83
83
84 test "CustomContentType request body generates custom MIME type" do
84 test "CustomContentType request body generates custom MIME type" do
85 let
85 let
86− spec = buildOpenAPISpec @{ customEndpoint :: Route POST "custom" (Request { body :: CustomContentType "application/vnd.api+json" User }) (ok :: { body :: User }) }
86+ spec = buildOpenAPISpec @{ customEndpoint :: Route POST "custom" { body :: CustomContentType "application/vnd.api+json" User } (ok :: { body :: User }) }
87 { title: "API"
87 { title: "API"
88 , version: "1.0.0"
88 , version: "1.0.0"
89 , description: Nothing
89 , description: Nothing
@@ -97,7 +97,7 @@ testResponseContentTypes :: Effect ViTest
97testResponseContentTypes = describe "Response Content Types" do
97testResponseContentTypes = describe "Response Content Types" do
98 _ <- test "JSON response body generates application/json" do
98 _ <- test "JSON response body generates application/json" do
99 let
99 let
100− spec = buildOpenAPISpec @{ getUser :: Route GET "users" (Request {}) (ok :: { body :: JSON User }) }
100+ spec = buildOpenAPISpec @{ getUser :: Route GET "users" {} (ok :: { body :: JSON User }) }
101 { title: "API"
101 { title: "API"
102 , version: "1.0.0"
102 , version: "1.0.0"
103 , description: Nothing
103 , description: Nothing
@@ -109,7 +109,7 @@ testResponseContentTypes = describe "Response Content Types" do
109
109
110 _ <- test "PlainText response body generates text/plain" do
110 _ <- test "PlainText response body generates text/plain" do
111 let
111 let
112− spec = buildOpenAPISpec @{ getText :: Route GET "text" (Request {}) (ok :: { body :: PlainText String }) }
112+ spec = buildOpenAPISpec @{ getText :: Route GET "text" {} (ok :: { body :: PlainText String }) }
113 { title: "API"
113 { title: "API"
114 , version: "1.0.0"
114 , version: "1.0.0"
115 , description: Nothing
115 , description: Nothing
@@ -121,7 +121,7 @@ testResponseContentTypes = describe "Response Content Types" do
121
121
122 _ <- test "XML response body generates application/xml" do
122 _ <- test "XML response body generates application/xml" do
123 let
123 let
124− spec = buildOpenAPISpec @{ getDoc :: Route GET "document" (Request {}) (ok :: { body :: XML XmlDocument }) }
124+ spec = buildOpenAPISpec @{ getDoc :: Route GET "document" {} (ok :: { body :: XML XmlDocument }) }
125 { title: "API"
125 { title: "API"
126 , version: "1.0.0"
126 , version: "1.0.0"
127 , description: Nothing
127 , description: Nothing
@@ -133,7 +133,7 @@ testResponseContentTypes = describe "Response Content Types" do
133
133
134 _ <- test "CustomContentType response body generates custom MIME type" do
134 _ <- test "CustomContentType response body generates custom MIME type" do
135 let
135 let
136− spec = buildOpenAPISpec @{ customGet :: Route GET "custom" (Request {}) (ok :: { body :: CustomContentType "application/vnd.api+json" User }) }
136+ spec = buildOpenAPISpec @{ customGet :: Route GET "custom" {} (ok :: { body :: CustomContentType "application/vnd.api+json" User }) }
137 { title: "API"
137 { title: "API"
138 , version: "1.0.0"
138 , version: "1.0.0"
139 , description: Nothing
139 , description: Nothing
@@ -145,7 +145,7 @@ testResponseContentTypes = describe "Response Content Types" do
145
145
146 test "Unwrapped response body defaults to application/json for backward compatibility" do
146 test "Unwrapped response body defaults to application/json for backward compatibility" do
147 let
147 let
148− spec = buildOpenAPISpec @{ getUser :: Route GET "users" (Request {}) (ok :: { body :: User }) }
148+ spec = buildOpenAPISpec @{ getUser :: Route GET "users" {} (ok :: { body :: User }) }
149 { title: "API"
149 { title: "API"
150 , version: "1.0.0"
150 , version: "1.0.0"
151 , description: Nothing
151 , description: Nothing
@@ -161,10 +161,10 @@ testMixedContentTypes = describe "Mixed Content Types in API" do
161 let
161 let
162 spec = buildOpenAPISpec
162 spec = buildOpenAPISpec
163 @
163 @
164− { createUser :: Route POST "users" (Request { body :: JSON User }) (ok :: { body :: JSON User })
164+ { createUser :: Route POST "users" { body :: JSON User } (ok :: { body :: JSON User })
165− , uploadFile :: Route POST "upload" (Request { body :: MultipartFormData FileUpload }) (ok :: { body :: { success :: Boolean } })
165+ , uploadFile :: Route POST "upload" { body :: MultipartFormData FileUpload } (ok :: { body :: { success :: Boolean } })
166− , echo :: Route POST "echo" (Request { body :: PlainText String }) (ok :: { body :: PlainText String })
166+ , echo :: Route POST "echo" { body :: PlainText String } (ok :: { body :: PlainText String })
167− , getDoc :: Route GET "document" (Request {}) (ok :: { body :: XML XmlDocument })
167+ , getDoc :: Route GET "document" {} (ok :: { body :: XML XmlDocument })
168 }
168 }
169 { title: "Multi-Content API"
169 { title: "Multi-Content API"
170 , version: "1.0.0"
170 , version: "1.0.0"
test/Test/CookieAuthTest.purs+4−4
@@ -5,7 +5,7 @@ import Prelude
5import Data.Maybe (Maybe(..))
5import Data.Maybe (Maybe(..))
6import Data.String as String
6import Data.String as String
7import Effect (Effect)
7import Effect (Effect)
8−import Yoga.HTTP.API.Route (GET, Route, Request, buildOpenAPISpec)
8+import Yoga.HTTP.API.Route (GET, Route, buildOpenAPISpec)
9import Yoga.HTTP.API.Route.Auth (ApiKeyCookie)
9import Yoga.HTTP.API.Route.Auth (ApiKeyCookie)
10import Yoga.JSON (writeJSON)
10import Yoga.JSON (writeJSON)
11import ViTest (ViTest, describe, test)
11import ViTest (ViTest, describe, test)
@@ -16,15 +16,15 @@ import ViTest.Expect (expectToBe)
16--------------------------------------------------------------------------------
16--------------------------------------------------------------------------------
17
17
18type ApiKeyCookieAPI =
18type ApiKeyCookieAPI =
19− { getProtected :: Route GET "protected" (Request { cookies :: { sessionId :: ApiKeyCookie } }) (ok :: { body :: { message :: String } })
19+ { getProtected :: Route GET "protected" { cookies :: { sessionId :: ApiKeyCookie } } (ok :: { body :: { message :: String } })
20 }
20 }
21
21
22type RegularCookieParamsAPI =
22type RegularCookieParamsAPI =
23− { getData :: Route GET "data" (Request { cookies :: { preference :: String, theme :: String } }) (ok :: { body :: { data :: String } })
23+ { getData :: Route GET "data" { cookies :: { preference :: String, theme :: String } } (ok :: { body :: { data :: String } })
24 }
24 }
25
25
26type MixedCookieAPI =
26type MixedCookieAPI =
27− { getResource :: Route GET "resource" (Request { cookies :: { sessionId :: ApiKeyCookie, userId :: String } }) (ok :: { body :: { resource :: String } })
27+ { getResource :: Route GET "resource" { cookies :: { sessionId :: ApiKeyCookie, userId :: String } } (ok :: { body :: { resource :: String } })
28 }
28 }
29
29
30--------------------------------------------------------------------------------
30--------------------------------------------------------------------------------
test/Test/ExamplesTest.purs+6−6
@@ -8,7 +8,7 @@ import Effect (Effect)
8import Type.Function (type (#))
8import Type.Function (type (#))
9import Type.Proxy (Proxy(..))
9import Type.Proxy (Proxy(..))
10import Yoga.HTTP.API.Path (type (/), type (:))
10import Yoga.HTTP.API.Path (type (/), type (:))
11−import Yoga.HTTP.API.Route (GET, POST, Route, Request, buildOpenAPISpec)
11+import Yoga.HTTP.API.Route (GET, POST, Route, buildOpenAPISpec)
12import Yoga.HTTP.API.Route.Encoding (JSON)
12import Yoga.HTTP.API.Route.Encoding (JSON)
13import Yoga.HTTP.API.Route.OpenAPIMetadata (Example, Examples, ExampleValue, ExampleWithSummary, ExampleObject, example, examples)
13import Yoga.HTTP.API.Route.OpenAPIMetadata (Example, Examples, ExampleValue, ExampleWithSummary, ExampleObject, example, examples)
14import Yoga.JSON (writeJSON)
14import Yoga.JSON (writeJSON)
@@ -36,7 +36,7 @@ testExamplesMetadataExtraction = describe "Examples Metadata - Type-level extrac
36 expectToBe true (isJust result)
36 expectToBe true (isJust result)
37
37
38type TestAPIWithPathExamples =
38type TestAPIWithPathExamples =
39− { getUser :: Route GET ("users" / "userId" : (Int # Examples (basic :: ExampleValue "123", premium :: ExampleWithSummary "456" "Premium user"))) (Request {}) (ok :: { body :: { id :: Int, name :: String } })
39+ { getUser :: Route GET ("users" / "userId" : (Int # Examples (basic :: ExampleValue "123", premium :: ExampleWithSummary "456" "Premium user"))) {} (ok :: { body :: { id :: Int, name :: String } })
40 }
40 }
41
41
42testExamplesInParameters :: Effect ViTest
42testExamplesInParameters :: Effect ViTest
@@ -59,7 +59,7 @@ type User =
59 }
59 }
60
60
61type TestAPIWithRequestBodyExamples =
61type TestAPIWithRequestBodyExamples =
62− { createUser :: Route POST "users" (Request { body :: JSON User }) (ok :: { body :: { id :: Int } })
62+ { createUser :: Route POST "users" { body :: JSON User } (ok :: { body :: { id :: Int } })
63 }
63 }
64
64
65testExamplesInRequestBody :: Effect ViTest
65testExamplesInRequestBody :: Effect ViTest
@@ -77,7 +77,7 @@ testExamplesInRequestBody = describe "Examples in Request Body" do
77 expectToBe true (String.contains (String.Pattern "users") json)
77 expectToBe true (String.contains (String.Pattern "users") json)
78
78
79type TestAPIWithComplexExamples =
79type TestAPIWithComplexExamples =
80− { getItem :: Route GET ("items" / "itemId" : (Int # Examples (basic :: ExampleWithSummary "42" "A basic item", special :: ExampleObject "999" "Special item" "A very special item" ""))) (Request {}) (ok :: { body :: { id :: Int } })
80+ { getItem :: Route GET ("items" / "itemId" : (Int # Examples (basic :: ExampleWithSummary "42" "A basic item", special :: ExampleObject "999" "Special item" "A very special item" ""))) {} (ok :: { body :: { id :: Int } })
81 }
81 }
82
82
83testExamplesWithSummary :: Effect ViTest
83testExamplesWithSummary :: Effect ViTest
@@ -111,7 +111,7 @@ testExamplesBackwardCompatibility = describe "Backward Compatibility - Single Ex
111 expectToBe true (isJust exsResult)
111 expectToBe true (isJust exsResult)
112
112
113type TestAPIWithQueryExamples =
113type TestAPIWithQueryExamples =
114− { searchItems :: Route GET "items" (Request { query :: { limit :: Int # Examples (small :: ExampleValue "10", large :: ExampleValue "100") } }) (ok :: { body :: { items :: Array String } })
114+ { searchItems :: Route GET "items" { query :: { limit :: Int # Examples (small :: ExampleValue "10", large :: ExampleValue "100") } } (ok :: { body :: { items :: Array String } })
115 }
115 }
116
116
117testExamplesInQueryParams :: Effect ViTest
117testExamplesInQueryParams :: Effect ViTest
@@ -129,7 +129,7 @@ testExamplesInQueryParams = describe "Examples in Query Parameters" do
129 expectToBe true (String.contains (String.Pattern "items") json)
129 expectToBe true (String.contains (String.Pattern "items") json)
130
130
131type TestAPIWithExternalExample =
131type TestAPIWithExternalExample =
132− { getResource :: Route GET ("resource" / "id" : (String # Examples (inline :: ExampleObject "abc123" "Inline example" "An example with inline value" "", external :: ExampleObject "" "External example" "An example from external URL" "https://example.com/resource.json"))) (Request {}) (ok :: { body :: { data :: String } })
132+ { getResource :: Route GET ("resource" / "id" : (String # Examples (inline :: ExampleObject "abc123" "Inline example" "An example with inline value" "", external :: ExampleObject "" "External example" "An example from external URL" "https://example.com/resource.json"))) {} (ok :: { body :: { data :: String } })
133 }
133 }
134
134
135testComplexExampleObject :: Effect ViTest
135testComplexExampleObject :: Effect ViTest
test/Test/OpenAPIInfoTest.purs+2−2
@@ -5,13 +5,13 @@ import Prelude
5import Data.Maybe (Maybe(..))
5import Data.Maybe (Maybe(..))
6import Data.String as String
6import Data.String as String
7import Effect (Effect)
7import Effect (Effect)
8−import Yoga.HTTP.API.Route (GET, Route, Request, buildOpenAPISpec)
8+import Yoga.HTTP.API.Route (GET, Route, buildOpenAPISpec)
9import Yoga.JSON (writeJSON)
9import Yoga.JSON (writeJSON)
10import ViTest (ViTest, describe, test)
10import ViTest (ViTest, describe, test)
11import ViTest.Expect (expectToBe)
11import ViTest.Expect (expectToBe)
12
12
13type SimpleAPI =
13type SimpleAPI =
14− { getRoot :: Route GET "" (Request {}) (ok :: { body :: { message :: String } })
14+ { getRoot :: Route GET "" {} (ok :: { body :: { message :: String } })
15 }
15 }
16
16
17testInfoDescription :: Effect ViTest
17testInfoDescription :: Effect ViTest
test/Test/SchemaComponentTest.purs+4−4
@@ -6,7 +6,7 @@ import Data.Maybe (Maybe(..))
6import Data.String as String
6import Data.String as String
7import Effect (Effect)
7import Effect (Effect)
8import Yoga.HTTP.API.Path (type (:), type (/))
8import Yoga.HTTP.API.Path (type (:), type (/))
9−import Yoga.HTTP.API.Route (GET, POST, Route, Request, JSON, Schema, buildOpenAPISpec)
9+import Yoga.HTTP.API.Route (GET, POST, Route, JSON, Schema, buildOpenAPISpec)
10import Yoga.JSON (writeJSON)
10import Yoga.JSON (writeJSON)
11import ViTest (ViTest, describe, test)
11import ViTest (ViTest, describe, test)
12import ViTest.Expect (expectToBe)
12import ViTest.Expect (expectToBe)
@@ -17,13 +17,13 @@ type Post = { id :: Int, title :: String, authorId :: Int }
17type SchemaAPI =
17type SchemaAPI =
18 { getUser ::
18 { getUser ::
19 Route GET ("users" / "id" : Int)
19 Route GET ("users" / "id" : Int)
20− (Request {})
20+ {}
21 (ok :: { body :: Schema "User" User })
21 (ok :: { body :: Schema "User" User })
22 , createUser ::
22 , createUser ::
23 Route POST "users"
23 Route POST "users"
24− (Request { body :: JSON (Schema "User" User) })
24+ { body :: JSON (Schema "User" User) }
25 (created :: { body :: Schema "User" User })
25 (created :: { body :: Schema "User" User })
26− , listPosts :: Route GET "posts" (Request {}) (ok :: { body :: Array (Schema "Post" Post) })
26+ , listPosts :: Route GET "posts" {} (ok :: { body :: Array (Schema "Post" Post) })
27 }
27 }
28
28
29testSchemaComponents :: Effect ViTest
29testSchemaComponents :: Effect ViTest
test/Test/VariantResponseTest.purs+7−7
@@ -10,7 +10,7 @@ import Effect.Aff (Aff)
10import Type.Proxy (Proxy(..))
10import Type.Proxy (Proxy(..))
11import Yoga.HTTP.API.Route.StatusCode (StatusCode(..))
11import Yoga.HTTP.API.Route.StatusCode (StatusCode(..))
12import Yoga.HTTP.API.Path (Root)
12import Yoga.HTTP.API.Path (Root)
13−import Yoga.HTTP.API.Route (GET, POST, PUT, Route, Request, Response(..), respondNoHeaders, respondWith, toOpenAPI, statusCodeFor, statusCodeToString)
13+import Yoga.HTTP.API.Route (GET, POST, PUT, Route, Response(..), respondNoHeaders, respondWith, toOpenAPI, statusCodeFor, statusCodeToString)
14import Yoga.HTTP.API.Route.Response (respond) as Response
14import Yoga.HTTP.API.Route.Response (respond) as Response
15import ViTest (ViTest, describe, test)
15import ViTest (ViTest, describe, test)
16import ViTest.Expect (expectToBe)
16import ViTest.Expect (expectToBe)
@@ -25,14 +25,14 @@ expectToEqual expected actual = expectToBe true (expected == actual)
25
25
26-- Simple variant route with ok and notFound responses
26-- Simple variant route with ok and notFound responses
27type SimpleVariantRoute = Route GET Root
27type SimpleVariantRoute = Route GET Root
28− (Request {})
28+ {}
29 ( ok :: { body :: String }
29 ( ok :: { body :: String }
30 , notFound :: { body :: String }
30 , notFound :: { body :: String }
31 )
31 )
32
32
33-- Variant route with multiple status codes
33-- Variant route with multiple status codes
34type MultiStatusRoute = Route POST Root
34type MultiStatusRoute = Route POST Root
35− (Request { headers :: { authorization :: String } })
35+ { headers :: { authorization :: String } }
36 ( created :: { headers :: { "Location" :: String }, body :: User }
36 ( created :: { headers :: { "Location" :: String }, body :: User }
37 , badRequest :: { body :: ErrorMessage }
37 , badRequest :: { body :: ErrorMessage }
38 , unauthorized :: { body :: ErrorMessage }
38 , unauthorized :: { body :: ErrorMessage }
@@ -40,7 +40,7 @@ type MultiStatusRoute = Route POST Root
40
40
41-- Variant route with many response types
41-- Variant route with many response types
42type ComplexVariantRoute = Route PUT Root
42type ComplexVariantRoute = Route PUT Root
43− (Request {})
43+ {}
44 ( ok :: { body :: User }
44 ( ok :: { body :: User }
45 , created :: { headers :: { "Location" :: String }, body :: User }
45 , created :: { headers :: { "Location" :: String }, body :: User }
46 , badRequest :: { body :: ErrorMessage }
46 , badRequest :: { body :: ErrorMessage }
@@ -242,7 +242,7 @@ testSimpleVariantOpenAPI = describe "OpenAPI Generation - Simple Variant" $ do
242 let
242 let
243 result = toOpenAPI
243 result = toOpenAPI
244 @( Route GET Root
244 @( Route GET Root
245− (Request {})
245+ {}
246 ( ok :: { body :: String }
246 ( ok :: { body :: String }
247 , notFound :: { body :: String }
247 , notFound :: { body :: String }
248 )
248 )
@@ -265,7 +265,7 @@ testComplexVariantOpenAPI = describe "OpenAPI Generation - Complex Variant" $ do
265 let
265 let
266 result = toOpenAPI
266 result = toOpenAPI
267 @( Route POST Root
267 @( Route POST Root
268− (Request { headers :: { authorization :: String } })
268+ { headers :: { authorization :: String } }
269 ( created :: { headers :: { "Location" :: String }, body :: User }
269 ( created :: { headers :: { "Location" :: String }, body :: User }
270 , badRequest :: { body :: ErrorMessage }
270 , badRequest :: { body :: ErrorMessage }
271 , unauthorized :: { body :: ErrorMessage }
271 , unauthorized :: { body :: ErrorMessage }
@@ -299,7 +299,7 @@ testVariantWithHeaders = describe "OpenAPI Generation - Variant with Response He
299 let
299 let
300 result = toOpenAPI
300 result = toOpenAPI
301 @( Route POST Root
301 @( Route POST Root
302− (Request {})
302+ {}
303 ( created :: { headers :: { "Location" :: String, "X-Request-Id" :: String }, body :: User }
303 ( created :: { headers :: { "Location" :: String, "X-Request-Id" :: String }, body :: User }
304 )
304 )
305 )
305 )