Clarification around the concept of Path, Mount Point and Prefix in http4s - scala

I'm trying to clarify some concept that confuse me slightly around http4s path.
Quoting the documentation,
Path info
Path matching is done on the request’s pathInfo. Path info is the request’s URI’s path after the following:
the mount point of the service
the prefix, if the service is composed with a Router
the prefix, if the service is rewritten with TranslateUri
Matching on request.pathInfo instead of request.uri.path allows multiple services to be composed without rewriting all the path matchers.
I would like to clarify the notion of mount point and prefix.
Can some give an example of a mount point definition vs a prefix ?
Can a service have both a mount point and prefix that are not the same ?
I suspect that the mount point in this example is /hello?
HttpRoutes.of[IO] {
case GET -> Root / "hello" => Ok("hello")
}
When writing the below code, we are defining 2 prefixes / and /api, but are they also consider mount point ?
val services = tweetService <+> helloWorldService
val httpApp = Router("/" -> helloWorldService, "/api" -> services).orNotFound
Because quoting the documentation, we have:
We start from a BlazeServerBuilder, and then mount the
helloWorldService under the base path of / and the remainder of the
services under the base path of /api
For the second prefix /api, what is the Root of the helloWorldService in
case GET -> Root / "hello"
is it /api, as in Root = /api ?
What is the mount point of the helloWorldService in that circumstance and what is the prefix ?

Related

Is it possible to use Ambassador prefix_regex and regex_rewrite at the same route mapping?

I'm trying to use Ambassador prefix_regex and regex_rewrite.
I want both this routes prefixes:
/my/route/<something>
/api/v1/my/route/<something>
will be mapped to:
/my/route/<something>
This is what I was trying to use:
apiVersion: ambassador/v2
kind: Mapping
prefix_regex: true
prefix: (/api/v1)?/my/route
regex_rewrite:
pattern: "/api/v1/my/route/(.*)"
substitution: "/my/route/\\1"
Using the regex_rewrite with regular prefix works as expected
Using prefix_regex with regular rewrite works as expected
but together I receive 404 from the envoy.
Any ideas?
I'm using Ambassador 1.7.0 version
Resolved by adding /.* at the end of the prefix.
prefix: (/api/v1)?/my/route/.*
It looks like prefix_regex adds automatically $ at the end of the prefix, which means we need to specify the full path of the mapping and not just the prefix.

WireMockServer change mapping directory at runtime

We have test suites defined where different suites require different stubs. The stubs are recorded individually and stored in different folders e.g.
/parent
+ stub1
+ mappings
+ __files
+ stub2
+ mappings
+ __files
...
While starting the wiremock server we specify the mapping directory something like :
WireMockServer wireMockServer = new WireMockServer(
WireMockConfiguration.wireMockConfig()
.usingFilesUnderDirectory(rootPath));
wireMockServer.start();
How can the instance be reset and register a different mapping folder at runtime ?
This is not supported actually.
You will need to stop/restart WireMock to update the folders.
Why do you need to change the mappings folder path at runtime? if you give more context I can help you :)
Regards

Camel Restlet - Context Path Ambiquity

I have Spring Boot Camel application where rest apis are exposed using camel-restlet
Sample route
#Component
public class AppRoute extends RouteBuilder{
public void configure(CamelContext context){
from("restlet:employee?restletMethods=GET").log("${body}");
}
}
The App runs perfect ( spring-boot:run ). but am unable to locate under which path the API is exposed. Log has no information.
Every API i hit returns 404. Log shows the route has been started. Under which path is it running. And how do I change it?
Note: Please dont suggest any XML based configuration. Anything that I can put under #Configuration would be perfect
I would go with the Rest DSL which is supported by the camel-restlet component like this
restConfiguration().component("restlet").port(8080);
rest("/rest")
.get("employee")
.route().log("${body}")
.endRest();
And this route will listen to the following url
http://localhost:8080/rest/employee
EDIT:
I guess you could do something like without using the Rest DSL
String host = InetAddress.getLocalHost().getHostName();
from("restlet:http://" + host + contextPath + "/employee?restletMethods=GET").log("${body}")
The port and context path are configurable with the following properties
camel.component.restlet.port=8686
server.servlet.context-path=/my-path
The context path can be injected in the routeBuilder with
#Value("${server.servlet.context-path}")
private String contextPath;
According to the documentation, the format of the URI in a restlet endpoint definition should be the following:
restlet:restletUrl[?options]
Where restletUrl should have the following format:
protocol://hostname[:port][/resourcePattern]
So in your case you could define the URI in the following way:
from("restlet:http://localhost/employee?restletMethods=GET")
This should make the endpoint available under the following URL:
http://localhost/employee
Which you can test e.g. in a web browser.
Use the first of the three configuration methods described here:
https://restlet.com/open-source/documentation/javadocs/2.0/jee/ext/org/restlet/ext/servlet/ServerServlet.html
You should be able to customize it using the Component:
https://restlet.com/open-source/documentation/javadocs/2.0/jee/api/org/restlet/Component.html?is-external=true
See in particular setServers() methods (or XML equivalent) to change the hostname and port.

Static resource reload with akka-http

In short: is it possible to reload static resources using akka-http?
A bit more:
I have Scala project.
I'm using App object to launch my Main
class.
I'm using getFromResourceDirectory to locate my resource
folder.
What I would like to have is to hot-swap my static resources during development.
For example, I have index.html or application.js, which I change and I want to see changes after I refresh my browser without restarting my server. What is the best practise of doing such thing?
I know that Play! allows that, but don't want to base my project on Play! only because of that.
Two options:
Easiest: use the getFromDirectory directive instead when running locally and point it to the path where your files you want to 'hotload' are, it serves them directly from the file system, so every time you change a file and load it through Akka HTTP it will be the latest version.
getFromResourceDirectory loads files from the classpath, the resources are available because SBT copies them into the class directory under target every time you build (copyResources). You could configure sbt using unmanagedClasspath to make it include the static resource directory in the classpath. If you want to package the resources in the artifact when running package however this would require some more sbt-trixery (if you just put src/resources in unmanagedClasspath it will depend on classpath ordering if the copied ones or the modified ones are used).
I couldn't get it to work by adding to unmanagedClasspath so I instead used getFromDirectory. You can use getFromDirectory as a fallback if getFromResourceDirectory fails like this.
val route =
pathSingleSlash {
getFromResource("static/index.html") ~
getFromFile("../website/static/index.html")
} ~
getFromResourceDirectory("static") ~
getFromDirectory("../website/static")
First it tries to look up the file in the static resource directory and if that fails, then checks if ../website/static has the file.
The below code try to find the file in the directory "staticContentDir". If the file is found, it is sent it back to the client. If it is not found, it tries by fetching the file from the directory "site" in the classpath.
The user url is: http://server:port/site/path/to/file.ext
/site/ comes from "staticPath"
val staticContentDir = calculateStaticPath()
val staticPath = "site"
val routes = pathPrefix(staticPath) {
entity(as[HttpRequest]) { requestData =>
val fullPath = requestData.uri.path
encodeResponse {
if (Files.exists(staticContentDir.resolve(fullPath.toString().replaceFirst(s"/$staticPath/", "")))) {
getFromBrowseableDirectory(staticContentDir.toString)
} else {
getFromResourceDirectory("site")
}
}
}
}
I hope it is clear.

Camel Http4 2.12.2: "httpClientConfigurer" cannot be inferred from endpointUri

I'm using scala akka-camel with http4 component (2.12.2 version).
I'm creating a Camel producer with endpoint:
def endpointUri = "https4://host-path" +
"?bridgeEndpoint=true" +
"&httpClientConfigurer=#configurer" +
"&clientConnectionManager=#manager"
where configurer is an HttpClientConfigurer registered in Camel context registry (the same principle applies to manager).
When I'm sending a CamelMessage to that endpoint I can see at akka logs this:
DEBUG o.a.c.component.http4.HttpComponent - Creating endpoint uri https4://host-path?bridgeEndpoint=true&httpClientConfigurer=#configurer&clientConnectionManager=#manager
DEBUG o.a.camel.util.IntrospectionSupport - Configured property: clientConnectionManager on bean: Endpoint["https4://host-path?bridgeEndpoint=true&httpClientConfigurer=#configurer&clientConnectionManager=#manager"] with value: org.apache.http.impl.conn.PoolingClientConnectionManager#3da3d36f
DEBUG o.a.camel.util.IntrospectionSupport - Configured property: bridgeEndpoint on bean: Endpoint["https4://host-path?bridgeEndpoint=true&httpClientConfigurer=#configurer&clientConnectionManager=#manager"] with value: true
INFO o.a.c.component.http4.HttpComponent - Registering SSL scheme https on port 443
INFO o.a.c.component.http4.HttpComponent - Registering SSL scheme https4 on port 443
So httpClientConfigurer is not configured and I don't know why it's ignoring this parameter. I've been looking for any related issue at Apache Camel issue tracker but I have found nothing similar.
Any idea?
Thanks in advance.
Finally, it's resolved. I haven't used the none of clientConnectionManager or httpClientConfigurer. I've used SSLContextParams and a trait called TlsConfigurer that is meant to be mixed-in with a Producer.
I want to use different X509 certificates, so, as Camel suggests:
Important: Only one instance of org.apache.camel.util.jsse.SSLContextParameters is supported per HttpComponent. If you need to use 2 or more different instances, you need to define a new HttpComponent per instance you need.
Therefore, TlsConfigurer configure method must be able to get a http4 component instance from camel context and then apply the SSLContextParams and add the modified instance as a new component to camel context.
This is how it looks:
import org.apache.camel.component.http4.HttpComponent
import org.apache.camel.util.jsse._
trait TlsConfigurer {
self: {val camel: akka.camel.Camel} =>
def configure(
componentName: String,
keyStorePath:String,
trustStorePath:String,
password: String) {
val ksp = new KeyStoreParameters
ksp.setResource(keystorePath)
ksp.setPassword(password)
val kmp = new KeyManagersParameters
kmp.setKeyStore(ksp)
kmp.setKeyPassword(password)
val scp = new SSLContextParameters
scp.setKeyManagers(kmp)
val httpComponent =
camel.context.getComponent("http4",classOf[HttpComponent])
httpComponent.setSslContextParameters(scp)
camel.context.addComponent(componentName, httpComponent)
}
}
This way I can create two different end-points: http-client1://... and http-client2://... and manage their certificates in a separate way.
httpClientConfigurer is not set to the HttpEndpoint by using IntrospectionSupport, so you don't see the debug log.
I think we about to find out the configurer is called when you add some log in the customer configurer.