What is the difference between static files and embedded application resources in Ktor? - ktor

I'm reading the ktor documentation on serving static content and it's not clear to me what the difference between files("css") and resources("css") is.

The static method is equivalent to the route method so it just creates a path route in the routing tree.
The files method allows serving all static files from the provided path (directory) from a local filesystem. Relative paths will be resolved using the current working directory.
The resources method does the same as the files method except that it allows serving static files from the classpath.
Here is an example:
// Assume that current working directory is /home/user/project
embeddedServer(Netty, port = 8080) {
routing {
// This route will be resolved if a request path starts with /assets/
static("assets") {
// For the request path /assets/style.css the file /home/user/project/css/style.css will be served
files("./css")
// It's the same as above
files("css")
// For the request path /assets/data.txt the file /absolute/path/to/data.txt will be served
files("/absolute/path/to")
// For the request path /assets/style.css the file <resources>/css/style.css will be served
// where <resources> is the embedded resource directory
resources("css")
}
}
}.start(wait = true)

Related

Save image in folder and retrieve image url in Ktor Web API

I uploaded image and store it in specific folder, and it's working, but I want the images back as image_url, there is no way found in Ktor Web API.
Please help me if anyone has a solution.
Thanks.
To solve your problem you can serve static files:
embeddedServer(Netty, port = 9999, host = "localhost") {
routing {
static("folder_name") { // web path
files("folder_name") // folder from where to serve files
}
}
}.start(wait = true)
Also, you can have a specific route to respond with the contents of a specific image:
routing {
get("/folder_name/image.jpg") {
call.respondFile(File("./folder_name/image.jpg"))
}
}

Static directory with ktor - not under "mysite.com/static/..."

I read through Serving Static Content and am having a brain-block.
I've got a folder /resources/static. It has static stuff in it. Some of that stuff is index.html, favicon.ico, a css folder, a js folder, etc.
I want it to show up as https://example.org/favicon.ico, https://example.org/ (default to index.html), etc.
All the examples in the Docs are for a site that shows up as https://example.org/static/index.html
I'm not getting the difference between "static", "resource", "resources", "files"
routing {
static("static") {
files("css")
files("js")
file("image.png")
file("random.txt", "image.png")
default("index.html")
}
}
static("static") - this is saying that when a client requests [your_host]/static then use the static handler to deal with the request.
Each of the configured handlers will run in order until the first one matches, so if no files match the request under the css directory then the next will run.
files("css") - this tells the static handler to look in a folder called css locally to serve the static content (i.e. client asks for [your_host]/static/style.css will get [app_directory]/css/style.css
file("image.png") - this tells the static handler to return the local file to serve the static content (i.e. client asks for [your_host]/static/* will get [app_directory]/image.png
default("index.html") - this will serve the local file [app_directory]/index.html for any request [your_host]/static/*
resource, resources and defaultResource do the same thing but for resources built in to your app, rather than on the file system.
This MAY have done it.
static("/") {
resources(resourcePackage = "static")
}
defaultResource(resource = "index.html", resourcePackage = "static")

In Ratpack, how can I configure loading configuration from an external file?

I have a Ratpack app written with the Groovy DSL. (Embedded in Java, so not a script.)
I want to load the server's SSL certificates from a config file supplied in the command line options. (The certs will directly embedded in the config, or possibly in a PEM file referenced somewhere in the config.)
For example:
java -jar httpd.jar /etc/app/sslConfig.yml
sslConfig.yml:
---
ssl:
privateKey: file:///etc/app/privateKey.pem
certChain: file:///etc/app/certChain.pem
I seem to have a chicken-and-egg problem using the serverConfig's facilities for reading the config file in order to configure the SslContext later in the serverConfig. The server config isn't created at the point I want to load the SslContext.
To illustrate, the DSL definition I have is something like this:
// SSL Config POJO definition
class SslConfig {
String privateKey
String certChain
SslContext build() { /* ... */ }
}
// ... other declarations here...
Path configPath = Paths.get(args[1]) // get this path from the CLI options
ratpack {
serverConfig {
yaml "/defaultConfig.yaml" // Defaults defined in this resource
yaml configPath // The user-supplied config file
env()
sysProps('genset-server')
require("/ssl", SslConfig) // Map the config to a POJO
ssl sslConfig // HOW DO I GET AN INSTANCE OF that SslConfig POJO HERE?
baseDir BaseDir.find()
}
handlers {
get { // ...
}
}
}
Possibly there is a solution to this (loading the SSL context in a later block?)
Or possibly just a better way to go about the whole thing..?
You could create a separate ConfigDataBuilder to load up a config object to deserialize your ssl config.
Alternatively, you can bind directly to server.ssl. All of the ServerConfig properties bind to the server space within the config.
The solution I am currently using is this, with an addition of a #builder method to SslConfig which returns a SslContextBuilder defined using its other fields.
ratpack {
serverConfig {
// Defaults defined in this resource
yaml RatpackEntryPoint.getResource("/defaultConfig.yaml")
// Optionally load the config path passed via the configFile parameter (if not null)
switch (configPath) {
case ~/.*[.]ya?ml/: yaml configPath; break
case ~/.*[.]json/: json configPath; break
case ~/.*[.]properties/: props configPath; break
}
env()
sysProps('genset-server')
require("/ssl", SslConfig) // Map the config to a POJO
baseDir BaseDir.find()
// This is the important change.
// It apparently needs to come last, because it prevents
// later config directives working without errors
ssl build().getAsConfigObject('/ssl',SslConfig).object.builder().build()
}
handlers {
get { // ...
}
}
}
Essentially this performs an extra build of the ServerConfig in order to redefine the input to the second build, but it works.

How do I serve both web pages and API Routes by using same port address and different Handle pattern

I have simple web application with CRUD operation, I want to serve web pages and API routes using same port address and different Handle pattern. As follows,
fs := http.FileServer(http.Dir("server/webapps/play_maths"))
http.Handle("/", fs)
http.Handle("/api", call API routes)
Following is my API routes
func UserRoutes() *mux.Router {
var router = mux.NewRouter()
router = mux.NewRouter().StrictSlash(true)
router.HandleFunc("/user/create", api.CreateUser)
router.HandleFunc("/user/get/all", api.GetAllUsers)
return router
}
This is supported by the net/http package out-of-the-box. Quoting from http.ServeMux:
Patterns name fixed, rooted paths, like "/favicon.ico", or rooted subtrees, like "/images/" (note the trailing slash). Longer patterns take precedence over shorter ones, so that if there are handlers registered for both "/images/" and "/images/thumbnails/", the latter handler will be called for paths beginning "/images/thumbnails/" and the former will receive requests for any other paths in the "/images/" subtree.
So simply you can register your file handler to path /, and register an API handler to e.g. /api/ path. In this scenario any requests that start with /api/ will be directed to the API handler, and any other requests will be directed to the file handler.
Note that this of course means if there are files that are in the /api/ folder (or more specifically whose request paths start with /api/), they won't be reachable for the above mentioned reason.
I did following changers to my code and now it's running as I expected.
func main() {
//Starting the API server
router := routes.UserRoutes()
http.Handle("/api/", router)
//Starting the FileServer
fs := http.FileServer(http.Dir("server/webapps/play_maths"))
http.Handle("/", fs)
log.Println("Listening...")
log.Fatal(http.ListenAndServe(":3000", nil))
}
Then I change my routes as follows.
func UserRoutes() *mux.Router {
var router = mux.NewRouter()
router = mux.NewRouter().StrictSlash(true)
router.HandleFunc("/api/user/create", api.CreateUser)
router.HandleFunc("/api/user/get/all", api.GetAllUsers)
return router
}

How can you use multiple directories for static files in an aspnet core app?

By default, the wwwroot directory can host static files. However, in some scenarios, it might be ideal to have two directories for static files. (For example, having webpack dump a build into one gitignored directory, and keeping some image files, favicon and such in a not-gitignored directory). Technically, this could be achieved by having two folders within the wwwroot, but it might organizationally preferable to have these folders at the root level. Is there a way to configure an aspnet core app to use two separate directories for static files?
Just register UseStaticFiles twice:
app.UseStaticFiles();
app.UseStaticFiles(new StaticFileOptions
{
FileProvider = new PhysicalFileProvider(
Path.Combine(Directory.GetCurrentDirectory(), "static"))
});
Now files will be found from wwwroot and static folders.
Registering UseStaticFiles twice won't solve it for MapFallbackToFile
An alternative approach.
// Build the different providers you need
var webRootProvider =
new PhysicalFileProvider(builder.Environment.WebRootPath);
var newPathProvider =
new PhysicalFileProvider(
Path.Combine(builder.Environment.ContentRootPath, #"Other"));
// Create the Composite Provider
var compositeProvider =
new CompositeFileProvider(webRootProvider, newPathProvider);
// Replace the default provider with the new one
app.Environment.WebRootFileProvider = compositeProvider;
https://wildermuth.com/2022/04/25/multiple-directories-for-static-files-in-aspnetcore/