11package app .softnetwork .api .server
22
33import akka .http .scaladsl .model .{HttpResponse , StatusCodes }
4- import akka .http .scaladsl .server .Directives .complete
4+ import akka .http .scaladsl .server .Directives ._
55import akka .http .scaladsl .server .Route
66import app .softnetwork .serialization .commonFormats
77import org .json4s .Formats
8- import sttp .model .StatusCode
8+ import sttp .model .{ HeaderNames , StatusCode , Uri }
99import sttp .tapir .EndpointOutput .OneOf
1010import sttp .tapir .server .PartialServerEndpointWithSecurityOutput
1111import sttp .tapir ._
@@ -21,6 +21,8 @@ object ApiErrors extends SchemaDerivation with TapirJson4s {
2121 val message : String
2222 }
2323
24+ trait ExtendedErrorInfo extends ErrorInfo
25+
2426 /** Represents http 404. */
2527 case class NotFound (message : String ) extends ErrorInfo
2628
@@ -42,6 +44,32 @@ object ApiErrors extends SchemaDerivation with TapirJson4s {
4244 /** Represents http 500. */
4345 case class InternalServerError (message : String ) extends ErrorInfo
4446
47+ /** Represents http 302. */
48+ case class Found (uri : Uri ) extends ErrorInfo {
49+ override val message : String = s " Found $uri"
50+ override def toString : String = uri.toString()
51+ }
52+
53+ object Found {
54+ def apply (uri : String ): Option [Found ] = Uri .parse(uri).toOption.map(Found (_))
55+ }
56+
57+ implicit val foundCodec : Codec [String , Found , CodecFormat .TextPlain ] =
58+ Codec .string.mapDecode(s =>
59+ Uri .parse(s) match {
60+ case Right (r) => DecodeResult .Value (Found (r))
61+ case Left (l) => DecodeResult .Error (s, new IllegalArgumentException (l))
62+ }
63+ )(_.toString())
64+
65+ implicit def leftFoundCodec [T ]: Codec [String , Left [Found , T ], CodecFormat .TextPlain ] =
66+ Codec .string.mapDecode(s =>
67+ Uri .parse(s) match {
68+ case Right (r) => DecodeResult .Value (Left [Found , T ](Found (r)))
69+ case Left (l) => DecodeResult .Error (s, new IllegalArgumentException (l))
70+ }
71+ )(_.left.get.toString())
72+
4573 implicit def apiError2Route (apiError : ErrorInfo )(implicit formats : Formats ): Route =
4674 apiError match {
4775 case r : BadRequest => complete(HttpResponse (StatusCodes .BadRequest , entity = r))
@@ -51,6 +79,7 @@ object ApiErrors extends SchemaDerivation with TapirJson4s {
5179 complete(HttpResponse (StatusCodes .InternalServerError , entity = r))
5280 case r : NotFound => complete(HttpResponse (StatusCodes .NotFound , entity = r))
5381 case r : Unauthorized => complete(HttpResponse (StatusCodes .Unauthorized , entity = r))
82+ case r : Found => redirect(r.toString, StatusCodes .Found )
5483 case r : ErrorMessage => complete(HttpResponse (StatusCodes .OK , entity = r))
5584 }
5685
@@ -80,6 +109,12 @@ object ApiErrors extends SchemaDerivation with TapirJson4s {
80109 .and(jsonBody[ApiErrors .NotFound ].description(" When something not found" ))
81110 )
82111
112+ val foundVariant : EndpointOutput .OneOfVariant [ApiErrors .Found ] =
113+ oneOfVariant(
114+ statusCode(StatusCode .Found )
115+ .and(header[ApiErrors .Found ](HeaderNames .Location ).description(" Redirect address" ))
116+ )
117+
83118 val badRequestVariant : EndpointOutput .OneOfVariant [ApiErrors .BadRequest ] =
84119 oneOfVariant(
85120 statusCode(StatusCode .BadRequest )
@@ -107,6 +142,7 @@ object ApiErrors extends SchemaDerivation with TapirJson4s {
107142 forbiddenVariant,
108143 unauthorizedVariant,
109144 notFoundVariant,
145+ foundVariant,
110146 badRequestVariant,
111147 internalServerErrorVariant,
112148 // default case below.
@@ -139,6 +175,12 @@ object ApiErrors extends SchemaDerivation with TapirJson4s {
139175 ) { case Left (ApiErrors .NotFound (_)) =>
140176 true
141177 },
178+ oneOfVariantValueMatcher(
179+ StatusCode .Found ,
180+ header[Left [ApiErrors .Found , T ]](" Location" ).description(" Redirect address" )
181+ ) { case Left (ApiErrors .Found (_)) =>
182+ true
183+ },
142184 oneOfVariantValueMatcher(
143185 StatusCode .BadRequest ,
144186 jsonBody[Left [ApiErrors .BadRequest , T ]].description(" Bad request" )
@@ -185,6 +227,7 @@ object ApiErrors extends SchemaDerivation with TapirJson4s {
185227 forbiddenVariant,
186228 unauthorizedVariant,
187229 notFoundVariant,
230+ foundVariant,
188231 badRequestVariant,
189232 internalServerErrorVariant,
190233 defaultErrorVariant
0 commit comments