-
Notifications
You must be signed in to change notification settings - Fork 464
Tapir aws #1226
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Tapir aws #1226
Changes from all commits
af64915
83824b3
a2c129d
e444466
bba11db
5bcc9ac
ad8c83f
a2451dd
64922f5
6d43016
7aba8db
d344f9f
fb68ef6
4eb3cc5
b6ae64e
3755542
de40110
b8e56bd
708972f
66f3c88
7ccd267
5fefe75
f574682
cb805ef
485cc45
38eb915
961c447
ab49f54
5d9aa91
61798fc
b63861a
794c18d
cf9b43d
29c840c
38cdb0a
5458707
5a62a2f
bb23032
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,9 +1,12 @@ | ||
| import java.net.URL | ||
| import com.softwaremill.SbtSoftwareMillBrowserTestJS._ | ||
| import com.softwaremill.UpdateVersionInDocs | ||
| import sbt.Reference.display | ||
| import sbt.internal.ProjectMatrix | ||
|
|
||
| import java.net.URL | ||
| import scala.concurrent.duration.DurationInt | ||
| import scala.sys.process.Process | ||
|
|
||
| val scala2_12 = "2.12.13" | ||
| val scala2_13 = "2.13.6" | ||
|
|
||
|
|
@@ -112,6 +115,11 @@ lazy val allAggregates = core.projectRefs ++ | |
| playServer.projectRefs ++ | ||
| vertxServer.projectRefs ++ | ||
| zioServer.projectRefs ++ | ||
| awsLambda.projectRefs ++ | ||
| awsLambdaTests.projectRefs ++ | ||
| awsSam.projectRefs ++ | ||
| awsTerraform.projectRefs ++ | ||
| awsExamples.projectRefs ++ | ||
| http4sClient.projectRefs ++ | ||
| sttpClient.projectRefs ++ | ||
| playClient.projectRefs ++ | ||
|
|
@@ -263,7 +271,7 @@ lazy val tests: ProjectMatrix = (projectMatrix in file("tests")) | |
| "com.beachape" %%% "enumeratum-circe" % Versions.enumeratum, | ||
| "com.softwaremill.common" %%% "tagging" % "2.3.0", | ||
| scalaTest.value, | ||
| "com.softwaremill.macwire" %% "macros" % "2.3.7" % "provided", | ||
| "com.softwaremill.macwire" %% "macros" % "2.3.7", | ||
| "org.typelevel" %%% "cats-effect" % Versions.catsEffect | ||
| ), | ||
| libraryDependencies ++= loggerDependencies | ||
|
|
@@ -283,6 +291,7 @@ lazy val cats: ProjectMatrix = (projectMatrix in file("integrations/cats")) | |
| name := "tapir-cats", | ||
| libraryDependencies ++= Seq( | ||
| "org.typelevel" %%% "cats-core" % "2.6.1", | ||
| "org.typelevel" %%% "cats-effect" % Versions.catsEffect, | ||
| scalaTest.value % Test, | ||
| scalaCheck.value % Test, | ||
| scalaTestPlusScalaCheck.value % Test, | ||
|
|
@@ -397,8 +406,8 @@ lazy val circeJson: ProjectMatrix = (projectMatrix in file("json/circe")) | |
| libraryDependencies ++= Seq( | ||
| "io.circe" %%% "circe-core" % Versions.circe, | ||
| "io.circe" %%% "circe-parser" % Versions.circe, | ||
| scalaTest.value % Test, | ||
| "io.circe" %%% "circe-generic" % Versions.circe % Test | ||
| "io.circe" %%% "circe-generic" % Versions.circe, | ||
| scalaTest.value % Test | ||
| ) | ||
| ) | ||
| .jvmPlatform(scalaVersions = allScalaVersions) | ||
|
|
@@ -775,7 +784,7 @@ lazy val http4sServer: ProjectMatrix = (projectMatrix in file("server/http4s-ser | |
| ) | ||
| ) | ||
| .jvmPlatform(scalaVersions = allScalaVersions) | ||
| .dependsOn(core, serverTests % Test) | ||
| .dependsOn(core, cats, serverTests % Test) | ||
|
adamw marked this conversation as resolved.
|
||
|
|
||
| lazy val sttpStubServer: ProjectMatrix = (projectMatrix in file("server/sttp-stub-server")) | ||
| .settings(commonJvmSettings) | ||
|
|
@@ -874,6 +883,110 @@ lazy val zioServer: ProjectMatrix = (projectMatrix in file("server/zio-http4s-se | |
| .jvmPlatform(scalaVersions = allScalaVersions) | ||
| .dependsOn(zio, http4sServer, serverTests % Test) | ||
|
|
||
| // serverless | ||
|
|
||
| lazy val awsLambda: ProjectMatrix = (projectMatrix in file("serverless/aws/lambda")) | ||
| .settings(commonJvmSettings) | ||
| .settings( | ||
| name := "tapir-aws-lambda", | ||
| libraryDependencies ++= loggerDependencies, | ||
| libraryDependencies ++= Seq( | ||
| "com.softwaremill.sttp.client3" %% "http4s-ce2-backend" % Versions.sttp, | ||
| "org.http4s" %% "http4s-blaze-client" % Versions.http4s | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. probably a follow-up task: I think we are always using this with Java 11+? If so, we might be able to use the
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I wrote it down |
||
| ) | ||
| ) | ||
| .jvmPlatform(scalaVersions = allScalaVersions) | ||
| .dependsOn(core, cats, circeJson, awsSam, sttpStubServer % "test", tests % "test", serverTests) | ||
|
|
||
| // integration tests for lambda interpreter | ||
| // it's a separate project since it needs a fat jar with lambda code which cannot be build from tests sources | ||
| // runs sam local cmd line tool to start AWS Api Gateway with lambda proxy | ||
| lazy val awsLambdaTests: ProjectMatrix = (projectMatrix in file("serverless/aws/lambda-tests")) | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd add a comment detailing what the test is doing and why is it done this way |
||
| .settings(commonJvmSettings) | ||
| .settings( | ||
| name := "tapir-aws-lambda-tests", | ||
| libraryDependencies += "com.amazonaws" % "aws-lambda-java-runtime-interface-client" % Versions.awsLambdaInterface, | ||
| assembly / assemblyJarName := "tapir-aws-lambda-tests.jar", | ||
| assembly / test := {}, // no tests before building jar | ||
| assembly / assemblyMergeStrategy := { | ||
| case PathList("META-INF", "io.netty.versions.properties") => MergeStrategy.first | ||
| case _ @("scala/annotation/nowarn.class" | "scala/annotation/nowarn$.class") => MergeStrategy.first | ||
| case x => (assembly / assemblyMergeStrategy).value(x) | ||
| }, | ||
| Test / test := (Test / test) | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. if you'd like to run it using 2.13 only, I think you could do sth like:
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. did you manage to run the tests on 2.13 only or is this solved some other way? |
||
| .dependsOn((Compile / runMain).toTask(" sttp.tapir.serverless.aws.lambda.tests.LambdaSamTemplate")) | ||
| .dependsOn(assembly) | ||
| .value, | ||
| Test / testOptions ++= { | ||
| val log = sLog.value | ||
| // process uses template.yaml which is generated by `LambdaSamTemplate` called above | ||
| lazy val sam = Process("sam local start-api --warm-containers EAGER").run() | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we might add a comment that this uses the template.yaml which is generated by the application above - if I understand correctly :) |
||
| Seq( | ||
| Tests.Setup(() => { | ||
| val samReady = PollingUtils.poll(60.seconds, 1.second) { | ||
| sam.isAlive() && PollingUtils.urlConnectionAvailable(new URL(s"http://127.0.0.1:3000/health")) | ||
| } | ||
| if (!samReady) { | ||
| sam.destroy() | ||
| val exit = sam.exitValue() | ||
| log.error(s"failed to start sam local within 30 seconds (exit code: $exit") | ||
| } | ||
| }), | ||
| Tests.Cleanup(() => { | ||
| sam.destroy() | ||
| val exit = sam.exitValue() | ||
| log.info(s"stopped sam local (exit code: $exit") | ||
| }) | ||
| ) | ||
| }, | ||
| Test / parallelExecution := false | ||
| ) | ||
| .jvmPlatform(scalaVersions = allScalaVersions) | ||
| .dependsOn(core, cats, circeJson, awsLambda, awsSam, tests) | ||
|
|
||
| lazy val awsSam: ProjectMatrix = (projectMatrix in file("serverless/aws/sam")) | ||
| .settings(commonJvmSettings) | ||
| .settings( | ||
| name := "tapir-aws-sam", | ||
| libraryDependencies ++= Seq( | ||
| "io.circe" %% "circe-yaml" % Versions.circeYaml, | ||
| "io.circe" %% "circe-generic" % Versions.circe | ||
| ) | ||
| ) | ||
| .jvmPlatform(scalaVersions = allScalaVersions) | ||
| .dependsOn(core, tests % Test) | ||
|
|
||
| lazy val awsTerraform: ProjectMatrix = (projectMatrix in file("serverless/aws/terraform")) | ||
| .settings(commonJvmSettings) | ||
| .settings( | ||
| name := "tapir-aws-terraform", | ||
| libraryDependencies ++= Seq( | ||
| "io.circe" %% "circe-yaml" % Versions.circeYaml, | ||
| "io.circe" %% "circe-generic" % Versions.circe, | ||
| "io.circe" %% "circe-literal" % Versions.circe, | ||
| "org.typelevel" %% "jawn-parser" % "1.0.0" | ||
| ) | ||
| ) | ||
| .jvmPlatform(scalaVersions = allScalaVersions) | ||
| .dependsOn(core, tests % Test) | ||
|
|
||
| lazy val awsExamples: ProjectMatrix = (projectMatrix in file("serverless/aws/examples")) | ||
| .settings(commonJvmSettings) | ||
| .settings( | ||
| libraryDependencies += "com.amazonaws" % "aws-lambda-java-runtime-interface-client" % Versions.awsLambdaInterface | ||
| ) | ||
| .settings( | ||
| name := "tapir-aws-examples", | ||
| assembly / assemblyJarName := "tapir-aws-examples.jar", | ||
| assembly / assemblyMergeStrategy := { | ||
| case PathList("META-INF", "io.netty.versions.properties") => MergeStrategy.first | ||
| case _ @("scala/annotation/nowarn.class" | "scala/annotation/nowarn$.class") => MergeStrategy.first | ||
| case x => (assembly / assemblyMergeStrategy).value(x) | ||
| } | ||
| ) | ||
| .jvmPlatform(scalaVersions = allScalaVersions) | ||
| .dependsOn(awsLambda, awsSam, awsTerraform) | ||
|
|
||
| // client | ||
|
|
||
| lazy val clientTests: ProjectMatrix = (projectMatrix in file("client/tests")) | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -136,6 +136,7 @@ Development and maintenance of sttp tapir is sponsored by [SoftwareMill](https:/ | |
| :caption: Server interpreters | ||
|
|
||
| server/akkahttp | ||
| server/aws | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. it's a bit ironic that's a "serverless" interpreter is listed under "server interpreters", but I guess that's the proper place ;) |
||
| server/http4s | ||
| server/finatra | ||
| server/play | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,66 @@ | ||
| # Running behind AWS API Gateway | ||
|
adamw marked this conversation as resolved.
|
||
|
|
||
| [AWS API Gateway](https://docs.aws.amazon.com/apigateway/latest/developerguide/welcome.html) provides a proxy | ||
| integration | ||
| with [AWS Lambda](https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-develop-integrations-lambda.html) | ||
| which allows you to implement API routes using Lambda functions. On the other hand tools | ||
| like [AWS SAM](https://aws.amazon.com/serverless/sam/) and [Terraform](https://www.terraform.io/) provides a | ||
| configuration mechanism for binding AWS Api Gateway routes to Lambda functions and automating cloud deployments. | ||
|
|
||
| This concept of serverless API has been adapted to Tapir in form of three components. | ||
|
|
||
| The first one is `AwsServerInterpreter` which routes AWS API Gateway requests to responses just as any other server | ||
| interpreter does. It should be used in your lambda function code. | ||
|
|
||
| ```scala | ||
| "com.softwaremill.sttp.tapir" %% "tapir-aws-lambda" % "@VERSION@" | ||
| ``` | ||
|
|
||
| The remaining two are `AwsSamInterpreter` which interprets Tapir `Endpoints` into AWS SAM template file | ||
| and `AwsTerraformInterpreter` which interprets `Endpoints` into terraform configuration file. One of them should be used | ||
| to configure your API Gateway. | ||
|
|
||
| ```scala | ||
| "com.softwaremill.sttp.tapir" %% "tapir-aws-sam" % "@VERSION@" | ||
| "com.softwaremill.sttp.tapir" %% "tapir-aws-terraform" % "@VERSION@" | ||
| ``` | ||
|
|
||
| ## Examples | ||
|
|
||
| In | ||
| our [GitHub repository](https://github.com/softwaremill/tapir/tree/master/serverless/aws/examples/src/main/scala/sttp/tapir/serverless/aws/examples) | ||
| you'll find a `LambdaApiExample` handler which uses `AwsServerInterpreter` to route a hello endpoint along | ||
| with `SamTemplateExample` and `TerraformConfigExample` which interpret endpoints to SAM/Terraform configuration. Go | ||
| ahead and clone tapir project and select `project awsExamples` from sbt shell. | ||
|
|
||
| Make sure you | ||
| have [AWS command line tools installed](https://docs.aws.amazon.com/cli/latest/userguide/install-cliv2.html). | ||
|
|
||
| ### SAM | ||
|
|
||
| To try it out using SAM template you don't need an AWS account. | ||
|
|
||
| * install [AWS SAM command line tool](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-command-reference.html) | ||
| * run `assembly` task and `runMain sttp.tapir.serverless.aws.examples.SamTemplateExample` | ||
| * open a terminal and in tapir root directory run `sam local start-api --warm-containers EAGER` | ||
|
|
||
| That will create `template.yaml` and start up AWS Api Gateway locally. Hello endpoint will be available | ||
| under `curl http://127.0.0.1:3000/api/hello`. First invocation will take a while but subsequent ones will be faster | ||
| since the created container will be reused. | ||
|
|
||
| ### Terraform | ||
|
|
||
| To run the example using terraform you will need an AWS account, and an S3 bucket. | ||
|
|
||
| * install [Terraform](https://learn.hashicorp.com/tutorials/terraform/install-cli) | ||
| * run `assembly` task | ||
| * open a terminal in `tapir/serverless/aws/examples/target/jvm-2.13` directory. That's where the fat jar is saved. You | ||
| need to upload it into your s3 bucket. Using command line | ||
| tools: `aws s3 cp tapir-aws-examples.jar s3://{your-bucket}/{your-key}`. | ||
| * Run `runMain sttp.tapir.serverless.aws.examples.TerraformConfigExample {your-aws-region} {your-bucket} {your-key}` | ||
| * open terminal in tapir root directory, run `terraform init` and `terraform apply` | ||
|
|
||
| That will create `api_gateway.tf.json` configuration and deploy Api Gateway and lambda function to AWS. Terraform will | ||
| output the url of the created API Gateway which you can call followed by `/api/hello` path. | ||
|
|
||
| To destroy all the created resources run `terraform destroy`. | ||
Uh oh!
There was an error while loading. Please reload this page.