softwaremill / livestub   0.2.1

GitHub

The HTTP server stub you always wanted!

Scala versions: 2.13

livestub

Build Status Docker Pulls Docker Image Size (latest by date) Scala Steward badge Maven Central

With livestub you can easly setup http server that behaves exactly as you would like it to. That makes livestub a perfect solution for faking arbitrary services which might be very useful in development/testing.

Usage

launch

  • coursier

    coursier launch com.softwaremill.sttp.livestub:livestub-app_2.13:0.2.1 -- -p 7070

  • docker

    docker run -p 7070:7070 softwaremill/sttp.livestub

  • code

import sttp.livestub.app.LiveStubServer
import sttp.livestub.app.LiveStubServer.Config
LiveStubServer.resource(Config(port = 7070))

stub

curl -X POST 'localhost:7070/__set' \
-d '{"when":{"method":"GET", "url":"animals/1/status"}, "then": {"statusCode":200, "body":{"status": "happy"} }}'

invoke

curl 'localhost:7070/animals/1/status'
{"status":"happy"}

swagger

Swagger is available under /__admin/docs

advanced stubbing

Livestub supports wildcard http methods as well as wildcard path parameters.

wildcard method:

curl -X POST 'localhost:7070/__set' \
-d '{"when":{"method":"*", "url":"dogs"}, "then": {"statusCode":200, "body":{"status": "OK"} }}'

wildcard path param:

curl -X POST 'localhost:7070/__set' \
-d '{"when":{"method":"GET", "url":"dogs/*/status"}, "then": {"statusCode":200, "body":{"status": "happy"} }}'

multiwildcard path param: (this one catches all routes which originate from /dogs)

curl -X POST 'localhost:7070/__set' \
-d '{"when":{"method":"GET", "url":"dogs/**"}, "then": {"statusCode":200, "body":{"status": "cheerful"} }}'

wildcard query param: (this one catches all the query parameters for /dogs, example: /dogs?id=1&breed=bulldog)

curl -X POST 'localhost:7070/__set' \
-d '{"when":{"method":"GET", "url":"dogs?*"}, "then": {"statusCode":200, "body":{"status": "cheerful"} }}'

additional methods

clear stubbed routes

curl -X POST 'localhost:7070/__clear'

show stubbed routes

curl 'localhost:7070/__routes'

set many responses which will be cycled through

curl -X POST 'localhost:7070/__set_many' \
-d '{"when":{"method":"GET", "url":"animals/1/status"}, "then": [
    {"statusCode":200, "body":{"status": "happy"} },
    {"statusCode":200, "body":{"status": "unhappy"} }
  ]
}'

stubbing from code - sdk

libraryDependencies += "com.softwaremill.sttp.livestub" % "livestub-sdk" % "0.2.1"

Given a bunch of imports

import sttp.client3.asynchttpclient.cats.AsyncHttpClientCatsBackend
import sttp.client3.SttpBackend
import sttp.livestub.sdk._
import sttp.livestub.api._
import sttp.client3.{Response => _, _}
import sttp.model._
import io.circe.Json

you can stub an arbitrary request:

AsyncHttpClientCatsBackend[IO]().flatMap { backend: SttpBackend[IO, Any] =>
  val livestub = new LiveStubSdk[IO](uri"http://mock:7070", backend)
  livestub
    .when(RequestStubIn(MethodStub.Wildcard, "/user/*/status"))
    .thenRespond(Response.emptyBody(StatusCode.Ok, List(Header("X-App", "123"))))
}

stub given sttp request:

AsyncHttpClientCatsBackend[IO]().flatMap { backend: SttpBackend[IO, Any] =>
  val request = basicRequest
    .body(Map("name" -> "John", "surname" -> "doe"))
    .post(uri"https://httpbin.org/post?signup=123")

  val livestub = new LiveStubSdk[IO](uri"http://mock:7070", backend)
  livestub.when(request).thenRespond(Response(Some(Json.fromString("OK")), StatusCode.Ok))
}

or stub given tapir endpoint:

import sttp.tapir._

AsyncHttpClientCatsBackend[IO]().flatMap { backend: SttpBackend[IO, Any] =>
  val myEndpoint = endpoint.get.in("/status").out(stringBody)

  val livestub = new LiveStubSdk[IO](uri"http://mock:7070", backend)
  livestub.when(myEndpoint)
          .thenRespond(Response.emptyBody(StatusCode.Ok, List(Header("X-App", "123"))))
}

OpenApi integration

OpenApi specification can be provided to bootstrap livestub server with auto generated endpoints. For each given path a request-response stub will be generated matching particular url. Both path parameters and required query parameters will be replaced by wildcard matches. That means that neither optional query parameters, request body nor headers are going to be checked when matching stubbed endpoint.

Response structure will follow openapi schema. Response data will be created based on openapi respective example parameters if provided, otherwise random data will be used(whenever it is possible).

For endpoints, which are defined in openapi specification but for which responses couldn't be generated empty response body will be returned.

Usage: --openapi-spec <path_to_file>

In addition, seed value for random data generator can be passed via: --seed 1234

Development

Documentation is generated during every release from docs-sources directory. It can be manually regenerated when needed by calling sbt docs/mdoc.

To release new version use sbt release.