Create plugins

Warning

This section is under rewrite. The following content is deprecated

When everything has failed and you absolutely need a feature in Otoroshi to make your use case work, there is a solution. Plugins is the feature in Otoroshi that allow you to code how Otoroshi should behave when receiving, validating and routing an http request. With request plugin, you can change request / response headers and request / response body the way you want, provide your own apikey, etc.

Plugin types

there are many plugin types explained here

Code and signatures

for more information about APIs you can use

Plugin examples

A lot of plugins comes with otoroshi, you can find them on github

Writing a plugin from Otoroshi UI

Log into Otoroshi and go to Settings (cog icon) / Plugins. Here you can create multiple request transformer scripts and associate it with service descriptor later.

when you write for instance a transformer in the Otoroshi UI, do the following

import akka.stream.Materializer
import env.Env
import models.{ApiKey, PrivateAppsUser, ServiceDescriptor}
import otoroshi.script._
import play.api.Logger
import play.api.mvc.{Result, Results}
import scala.util._
import scala.concurrent.{ExecutionContext, Future}

class MyTransformer extends RequestTransformer {

  val logger = Logger("my-transformer")

  // implements the methods you want
}

// WARN: do not forget this line to provide a working instance of your transformer to Otoroshi
new MyTransformer()

You can use the compile button to check if the script compiles, or code the transformer in your IDE (see next point).

Then go to a service descriptor, scroll to the bottom of the page, and select your transformer in the list

Providing a transformer from Java classpath

You can write your own transformer using your favorite IDE. Just create an SBT project with the following dependencies. It can be quite handy to manage the source code like any other piece of code, and it avoid the compilation time for the script at Otoroshi startup.

lazy val root = (project in file(".")).
  settings(
    inThisBuild(List(
      organization := "com.example",
      scalaVersion := "2.12.7",
      version      := "0.1.0-SNAPSHOT"
    )),
    name := "request-transformer-example",
    libraryDependencies += "fr.maif" %% "otoroshi" % "1.x.x"
  )
Warning

you MUST provide plugins that lies in the otoroshi_plugins package or in a sub-package of otoroshi_plugins. If you do not, your plugin will not be found by otoroshi. for example

package otoroshi_plugins.com.my.company.myplugin

also you don’t have to instantiate your plugin at the end of the file like in the Otoroshi UI

When your code is ready, create a jar file

sbt package

and add the jar file to the Otoroshi classpath

java -cp "/path/to/transformer.jar:$/path/to/otoroshi.jar" play.core.server.ProdServerStart

then, in your service descriptor, you can chose your transformer in the list. If you want to do it from the API, you have to defined the transformerRef using cp: prefix like

{
  "transformerRef": "cp:otoroshi_plugins.my.class.package.MyTransformer"
}

Getting custom configuration from the Otoroshi config. file

Let say you need to provide custom configuration values for a script, then you can customize a configuration file of Otoroshi

include "application.conf"

otoroshi {
  scripts {
    enabled = true
  }
}

my-transformer {
  env = "prod"
  maxRequestBodySize = 2048
  maxResponseBodySize = 2048
}

then start Otoroshi like

java -Dconfig.file=/path/to/custom.conf -jar otoroshi.jar

then, in your transformer, you can write something like

package otoroshi_plugins.com.example.otoroshi

import akka.stream.Materializer
import akka.stream.scaladsl._
import akka.util.ByteString
import env.Env
import models.{ApiKey, PrivateAppsUser, ServiceDescriptor}
import otoroshi.script._
import play.api.Logger
import play.api.mvc.{Result, Results}
import scala.util._
import scala.concurrent.{ExecutionContext, Future}

class BodyLengthLimiter extends RequestTransformer {

  override def def transformResponseWithCtx(ctx: TransformerResponseContext)(implicit env: Env, ec: ExecutionContext, mat: Materializer): Source[ByteString, _] = {
    val max = env.configuration.getOptional[Long]("my-transformer.maxResponseBodySize").getOrElse(Long.MaxValue)
    ctx.body.limitWeighted(max)(_.size)
  }

  override def transformRequestWithCtx(ctx: TransformerRequestContext)(implicit env: Env, ec: ExecutionContext, mat: Materializer): Source[ByteString, _] = {
    val max = env.configuration.getOptional[Long]("my-transformer.maxRequestBodySize").getOrElse(Long.MaxValue)
    ctx.body.limitWeighted(max)(_.size)
  }
}

Using a library that is not embedded in Otoroshi

Just use the classpath option when running Otoroshi

java -cp "/path/to/library.jar:$/path/to/otoroshi.jar" play.core.server.ProdServerStart

Be carefull as your library can conflict with other libraries used by Otoroshi and affect its stability

Enabling plugins

plugins can be enabled per service from the service settings page or globally from the danger zone in the plugins section.

Full example

a full external plugin example can be found here