Skip to content

Commit dfd975b

Browse files
committed
update resource endpoints for Tapir
1 parent bf72509 commit dfd975b

File tree

5 files changed

+57
-123
lines changed

5 files changed

+57
-123
lines changed

build.sbt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ ThisBuild / organization := "app.softnetwork"
3131

3232
name := "resource"
3333

34-
ThisBuild / version := "0.2.1"
34+
ThisBuild / version := "0.2.2"
3535

3636
ThisBuild / scalaVersion := "2.12.15"
3737

core/src/main/scala/app/softnetwork/resource/service/ResourceServiceEndpoints.scala

Lines changed: 54 additions & 117 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,18 @@ package app.softnetwork.resource.service
33
import akka.http.scaladsl.server.Route
44
import akka.stream.scaladsl.{FileIO, Source}
55
import akka.util.ByteString
6-
import app.softnetwork.api.server.ApiEndpoint
6+
import app.softnetwork.api.server.{ApiEndpoint, ApiErrors}
77
import app.softnetwork.resource.config.ResourceSettings
88
import app.softnetwork.resource.handlers.GenericResourceHandler
99
import app.softnetwork.resource.message.ResourceMessages._
1010
import app.softnetwork.resource.spi.{ResourceProvider, SimpleResource}
1111
import app.softnetwork.session.service.SessionEndpoints
12-
import org.json4s.Formats
12+
import com.softwaremill.session.{
13+
GetSessionTransport,
14+
SetSessionTransport,
15+
TapirCsrfCheckMode,
16+
TapirSessionContinuity
17+
}
1318
import org.softnetwork.session.model.Session
1419
import sttp.capabilities.akka.AkkaStreams
1520
import sttp.model.headers.CookieValueWithMeta
@@ -28,50 +33,46 @@ trait ResourceServiceEndpoints extends LoadResourceService with ApiEndpoint {
2833

2934
import app.softnetwork.serialization._
3035

31-
implicit def formats: Formats = commonFormats
32-
3336
def sessionEndpoints: SessionEndpoints
3437

38+
def sc: TapirSessionContinuity[Session] = sessionEndpoints.sc
39+
40+
def st: SetSessionTransport = sessionEndpoints.st
41+
42+
def gt: GetSessionTransport = sessionEndpoints.gt
43+
44+
def checkMode: TapirCsrfCheckMode[Session] = sessionEndpoints.checkMode
45+
46+
def error(e: ResourceError): ApiErrors.ErrorInfo =
47+
e match {
48+
case ResourceNotFound => ApiErrors.NotFound(ResourceNotFound)
49+
case _ => ApiErrors.BadRequest(e.message)
50+
}
51+
3552
def rootEndpoint: PartialServerEndpoint[
36-
(Seq[Option[String]], Method, Option[String], Option[String]),
53+
(Seq[Option[String]], Option[String], Method, Option[String]),
3754
((Seq[Option[String]], Option[CookieValueWithMeta]), Session),
3855
Unit,
39-
ResourceError,
56+
ApiErrors.ErrorInfo,
4057
(Seq[Option[String]], Option[CookieValueWithMeta]),
4158
Any,
4259
Future
43-
] =
44-
sessionEndpoints.antiCsrfWithRequiredSession.endpoint
60+
] = {
61+
val partial =
62+
sessionEndpoints.antiCsrfWithRequiredSession(sc, gt, checkMode)
63+
partial.endpoint
4564
.in(ResourceSettings.ResourcePath)
46-
.out(sessionEndpoints.antiCsrfWithRequiredSession.securityOutput)
47-
.errorOut(
48-
oneOf[ResourceError](
49-
oneOfVariant[ResourceNotFound.type](
50-
statusCode(StatusCode.NotFound)
51-
.and(emptyOutputAs(ResourceNotFound).description("Resource not found"))
52-
),
53-
oneOfVariant[UnauthorizedError.type](
54-
statusCode(StatusCode.Unauthorized)
55-
.and(emptyOutputAs(UnauthorizedError).description("Unauthorized"))
56-
)
57-
)
58-
)
65+
.out(partial.securityOutput)
66+
.errorOut(errors)
5967
.serverSecurityLogic { inputs =>
60-
sessionEndpoints.antiCsrfWithRequiredSession.securityLogic(new FutureMonad())(inputs).map {
61-
case Left(_) => Left(UnauthorizedError)
68+
partial.securityLogic(new FutureMonad())(inputs).map {
69+
case Left(_) => Left(ApiErrors.Unauthorized("Unauthorized"))
6270
case Right(r) => Right((r._1, r._2))
6371
}
6472
}
73+
}
6574

66-
val libraryEndpoint: Full[
67-
(Seq[Option[String]], Method, Option[String], Option[String]),
68-
((Seq[Option[String]], Option[CookieValueWithMeta]), Session),
69-
List[String],
70-
ResourceError,
71-
(Seq[Option[String]], Option[CookieValueWithMeta], List[SimpleResource]),
72-
Any,
73-
Future
74-
] =
75+
val libraryEndpoint: ServerEndpoint[Any with AkkaStreams, Future] =
7576
rootEndpoint.get
7677
.in("library")
7778
.in(paths)
@@ -86,40 +87,24 @@ trait ResourceServiceEndpoints extends LoadResourceService with ApiEndpoint {
8687
def loadResourceBusinessLogic(
8788
principal: ((Seq[Option[String]], Option[CookieValueWithMeta]), Session)
8889
): List[String] => Either[
89-
ResourceError,
90+
ApiErrors.ErrorInfo,
9091
(Seq[Option[String]], Option[CookieValueWithMeta], Source[ByteString, Any])
9192
] =
9293
segments =>
9394
loadResource(segments) match {
9495
case Some((path, _)) => Right((principal._1._1, principal._1._2, FileIO.fromPath(path)))
95-
case _ => Left(ResourceNotFound)
96+
case _ => Left(error(ResourceNotFound))
9697
}
9798

98-
val getResourceEndpoint: Full[
99-
(Seq[Option[String]], Method, Option[String], Option[String]),
100-
((Seq[Option[String]], Option[CookieValueWithMeta]), Session),
101-
List[String],
102-
ResourceError,
103-
(Seq[Option[String]], Option[CookieValueWithMeta], Source[ByteString, Any]),
104-
Any with AkkaStreams,
105-
Future
106-
] =
99+
val getResourceEndpoint: ServerEndpoint[Any with AkkaStreams, Future] =
107100
rootEndpoint.get
108101
.in(paths)
109102
.out(streamBinaryBody(AkkaStreams)(CodecFormat.OctetStream()))
110103
.serverLogic(principal =>
111104
segments => Future.successful(loadResourceBusinessLogic(principal)(segments))
112105
)
113106

114-
val getImageEndpoint: Full[
115-
(Seq[Option[String]], Method, Option[String], Option[String]),
116-
((Seq[Option[String]], Option[CookieValueWithMeta]), Session),
117-
List[String],
118-
ResourceError,
119-
(Seq[Option[String]], Option[CookieValueWithMeta], Source[ByteString, Any]),
120-
Any with AkkaStreams,
121-
Future
122-
] =
107+
val getImageEndpoint: ServerEndpoint[Any with AkkaStreams, Future] =
123108
rootEndpoint.get
124109
.in("images")
125110
.in(paths)
@@ -131,12 +116,12 @@ trait ResourceServiceEndpoints extends LoadResourceService with ApiEndpoint {
131116
)
132117

133118
val uploadResourceEndpoint: PartialServerEndpoint[
134-
(Seq[Option[String]], Method, Option[String], Option[String]),
119+
(Seq[Option[String]], Option[String], Method, Option[String]),
135120
((Seq[Option[String]], Option[CookieValueWithMeta]), Session),
136121
(List[String], UploadResource),
137-
ResourceError,
122+
ApiErrors.ErrorInfo,
138123
(Seq[Option[String]], Option[CookieValueWithMeta], ResourceResult),
139-
Any,
124+
Any with AkkaStreams,
140125
Future
141126
] =
142127
rootEndpoint
@@ -155,47 +140,31 @@ trait ResourceServiceEndpoints extends LoadResourceService with ApiEndpoint {
155140
)
156141
)
157142

158-
val addResourceEndpoint: Full[
159-
(Seq[Option[String]], Method, Option[String], Option[String]),
160-
((Seq[Option[String]], Option[CookieValueWithMeta]), Session),
161-
(List[String], UploadResource),
162-
ResourceError,
163-
(Seq[Option[String]], Option[CookieValueWithMeta], ResourceResult),
164-
Any,
165-
Future
166-
] =
143+
val addResourceEndpoint: ServerEndpoint[Any with AkkaStreams, Future] =
167144
uploadResourceEndpoint.post
168145
.description("Add a resource")
169146
.serverLogic(principal => { case (segments, upload) =>
170147
uploadResource(principal._2, segments, upload.bytes, update = false) map {
171-
case Left(l) => Left(l)
148+
case Left(l) => Left(error(l))
172149
case Right(r) => Right((principal._1._1, principal._1._2, r))
173150
}
174151
})
175152

176-
val updateResourceEndpoint: Full[
177-
(Seq[Option[String]], Method, Option[String], Option[String]),
178-
((Seq[Option[String]], Option[CookieValueWithMeta]), Session),
179-
(List[String], UploadResource),
180-
ResourceError,
181-
(Seq[Option[String]], Option[CookieValueWithMeta], ResourceResult),
182-
Any,
183-
Future
184-
] =
153+
val updateResourceEndpoint: ServerEndpoint[Any with AkkaStreams, Future] =
185154
uploadResourceEndpoint.put
186155
.description("Update the resource")
187156
.serverLogic(principal => { case (segments, upload) =>
188157
uploadResource(principal._2, segments, upload.bytes, update = true) map {
189-
case Left(l) => Left(l)
158+
case Left(l) => Left(error(l))
190159
case Right(r) => Right((principal._1._1, principal._1._2, r))
191160
}
192161
})
193162

194163
val uploadImageEndpoint: PartialServerEndpoint[
195-
(Seq[Option[String]], Method, Option[String], Option[String]),
164+
(Seq[Option[String]], Option[String], Method, Option[String]),
196165
((Seq[Option[String]], Option[CookieValueWithMeta]), Session),
197166
(List[String], UploadImage),
198-
ResourceError,
167+
ApiErrors.ErrorInfo,
199168
(Seq[Option[String]], Option[CookieValueWithMeta], ResourceResult),
200169
Any,
201170
Future
@@ -217,38 +186,22 @@ trait ResourceServiceEndpoints extends LoadResourceService with ApiEndpoint {
217186
)
218187
)
219188

220-
val addImageEndpoint: Full[
221-
(Seq[Option[String]], Method, Option[String], Option[String]),
222-
((Seq[Option[String]], Option[CookieValueWithMeta]), Session),
223-
(List[String], UploadImage),
224-
ResourceError,
225-
(Seq[Option[String]], Option[CookieValueWithMeta], ResourceResult),
226-
Any,
227-
Future
228-
] =
189+
val addImageEndpoint: ServerEndpoint[Any with AkkaStreams, Future] =
229190
uploadImageEndpoint.post
230191
.description("Add an image")
231192
.serverLogic(principal => { case (segments, upload) =>
232193
uploadResource(principal._2, segments, upload.bytes, update = false) map {
233-
case Left(l) => Left(l)
194+
case Left(l) => Left(error(l))
234195
case Right(r) => Right((principal._1._1, principal._1._2, r))
235196
}
236197
})
237198

238-
val updateImageEndpoint: Full[
239-
(Seq[Option[String]], Method, Option[String], Option[String]),
240-
((Seq[Option[String]], Option[CookieValueWithMeta]), Session),
241-
(List[String], UploadImage),
242-
ResourceError,
243-
(Seq[Option[String]], Option[CookieValueWithMeta], ResourceResult),
244-
Any,
245-
Future
246-
] =
199+
val updateImageEndpoint: ServerEndpoint[Any with AkkaStreams, Future] =
247200
uploadImageEndpoint.put
248201
.description("Update the image")
249202
.serverLogic(principal => { case (segments, upload) =>
250203
uploadResource(principal._2, segments, upload.bytes, update = true) map {
251-
case Left(l) => Left(l)
204+
case Left(l) => Left(error(l))
252205
case Right(r) => Right((principal._1._1, principal._1._2, r))
253206
}
254207
})
@@ -264,43 +217,27 @@ trait ResourceServiceEndpoints extends LoadResourceService with ApiEndpoint {
264217
}
265218
}
266219

267-
val deleteResourceEndpoint: Full[
268-
(Seq[Option[String]], Method, Option[String], Option[String]),
269-
((Seq[Option[String]], Option[CookieValueWithMeta]), Session),
270-
List[String],
271-
ResourceError,
272-
(Seq[Option[String]], Option[CookieValueWithMeta]),
273-
Any,
274-
Future
275-
] =
220+
val deleteResourceEndpoint: ServerEndpoint[Any with AkkaStreams, Future] =
276221
rootEndpoint
277222
.in(paths)
278223
.delete
279224
.serverLogic(principal =>
280225
segments =>
281226
deleteResourceBusinessLogic(principal._2, segments) map {
282-
case Left(l) => Left(l)
227+
case Left(l) => Left(error(l))
283228
case Right(_) => Right((principal._1._1, principal._1._2))
284229
}
285230
)
286231

287-
val deleteImageEndpoint: Full[
288-
(Seq[Option[String]], Method, Option[String], Option[String]),
289-
((Seq[Option[String]], Option[CookieValueWithMeta]), Session),
290-
List[String],
291-
ResourceError,
292-
(Seq[Option[String]], Option[CookieValueWithMeta]),
293-
Any,
294-
Future
295-
] =
232+
val deleteImageEndpoint: ServerEndpoint[Any with AkkaStreams, Future] =
296233
rootEndpoint
297234
.in("images")
298235
.in(paths)
299236
.delete
300237
.serverLogic(principal =>
301238
segments =>
302239
deleteResourceBusinessLogic(principal._2, segments) map {
303-
case Left(l) => Left(l)
240+
case Left(l) => Left(error(l))
304241
case Right(_) => Right((principal._1._1, principal._1._2))
305242
}
306243
)

project/src/main/scala/app/softnetwork/sbt/build/Versions.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ package app.softnetwork.sbt.build
22

33
object Versions {
44

5-
val genericPersistence = "0.3.1.2"
5+
val genericPersistence = "0.3.2.2"
66

77
val scalatest = "3.1.1"
88
}

testkit/src/main/scala/app/softnetwork/resource/scalatest/ResourceToLocalFileSystemRouteTestKit.scala

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
11
package app.softnetwork.resource.scalatest
22

33
import akka.actor.testkit.typed.scaladsl.TestProbe
4-
import akka.actor.typed.ActorSystem
54
import akka.http.scaladsl.model.headers.RawHeader
65
import akka.http.scaladsl.model.{ContentTypes, Multipart, StatusCodes}
7-
import akka.http.scaladsl.server.Route
86
import app.softnetwork.api.server.ApiRoutes
97
import app.softnetwork.api.server.config.ServerSettings.RootPath
108
import app.softnetwork.persistence.environment
@@ -16,8 +14,6 @@ import app.softnetwork.resource.message.ResourceEvents.{
1614
ResourceUpdatedEvent
1715
}
1816
import app.softnetwork.resource.model.Resource
19-
import app.softnetwork.resource.service.{LocalFileSystemResourceService, ResourceService}
20-
import app.softnetwork.session.scalatest.SessionServiceRoute
2117
import org.scalatest.Suite
2218

2319
import java.net.URLEncoder

testkit/src/test/scala/app/softnetwork/resource/service/ResourceServiceSpec.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ trait ResourceServiceSpec extends AnyWordSpecLike with ResourceToLocalFileSystem
3131

3232
override def beforeAll(): Unit = {
3333
super.beforeAll()
34+
routes
3435
val dir = new Directory(new File(rootDir))
3536
dir.deleteRecursively()
3637
}

0 commit comments

Comments
 (0)