Serving Web Resources

This guide provides a simple example of how to serve arbitrary web resources like .html files.

To use proto files from artifacts in your schema, you need to adjust your maven build definition:

Java
<includeDependenciesInDescriptorSet>true</includeDependenciesInDescriptorSet>
Scala

For sbt builds, this works out-of-the-box with loading proto files from artifacts.

Next, import HttpBody and build your Kalix service to return that:

Java
syntax = "proto3";
package com.example;

import "google/protobuf/empty.proto";
import "google/api/annotations.proto";
import "google/api/httpbody.proto";   (1)
import "kalix/annotations.proto";

message File {
  string file = 1;
}

message FileInDir {
  string file = 1;
  string directory = 2;
}

service FileService {
  option (kalix.codegen) = {action: {}};
  option (kalix.service).acl.allow = { principal: ALL };
  rpc IndexHtml(google.protobuf.Empty) returns (google.api.HttpBody) {
    option (google.api.http) = {
      get: "/" (2)
    };
  };

  rpc GetFile(File) returns (google.api.HttpBody) {   (3)
    option (google.api.http) = {   (4)
      get: "/site/{file}" (5)
    };
  };

  rpc GetFileInDir(FileInDir) returns (google.api.HttpBody) {
    option (google.api.http) = {
      get: "/site/{directory}/{file}"   (6)
    };
  };
}
1 Use import to use proto files from dependencies.
2 Serve the index.html under /.
3 Choose google.api.HttpBody as the return type.
4 Enable HTTP endpoints using google.api.http.
5 Serve files in like web/index.js under /site/index.js.
6 Optional: serve files in directories, e.g. web/img/favicon.png under /site/img/favicon.png.
Scala
syntax = "proto3";
package com.example;

import "google/protobuf/empty.proto";
import "google/api/annotations.proto";
import "google/api/httpbody.proto";   (1)
import "kalix/annotations.proto";

message File {
  string file = 1;
}

message FileInDir {
  string file = 1;
  string directory = 2;
}

service FileService {
  option (kalix.codegen) = {action: {}};
  option (kalix.service).acl.allow = { principal: ALL };
  rpc IndexHtml(google.protobuf.Empty) returns (google.api.HttpBody) {
    option (google.api.http) = {
      get: "/" (2)
    };
  };

  rpc GetFile(File) returns (google.api.HttpBody) {   (3)
    option (google.api.http) = {   (4)
      get: "/site/{file}" (5)
    };
  };

  rpc GetFileInDir(FileInDir) returns (google.api.HttpBody) {
    option (google.api.http) = {
      get: "/site/{directory}/{file}"   (6)
    };
  };
}
1 Use import to use proto files from dependencies.
2 Serve the index.html under /.
3 Choose google.api.HttpBody as the return type.
4 Enable HTTP endpoints using google.api.http.
5 Serve files in like web/index.js under /site/index.js.
6 Optional: serve files in directories, e.g. web/img/favicon.png under /site/img/favicon.png.

Use effects().reply effects.reply to serve content (e.g. by loading a file from disk with) a 200 HTTP response:

Java
      InputStream inputStream = getClass().getResourceAsStream(fullPath);
      if(null == inputStream) {
        throw new NoSuchFileException("File " + fullPath + " not found");
      }
      byte[] byteArray = inputStream.readAllBytes();
      String contentType = getContentTypeByFile(file);
      HttpBody response = HttpBody.newBuilder()
              .setContentType(contentType)
              .setData(ByteString.copyFrom(byteArray))
              .build();
      LOG.info("Serving {} with {}", fullPath, contentType);
      Metadata header = Metadata.EMPTY.add("Cache-Control", "no-cache");
      return effects().reply(response, header);
Scala
      val byteArray = getClass().getResourceAsStream(fullPath).readAllBytes()
      val contentType = contentTypeByFile(file)
      log.info(s"Serving $fullPath with $contentType")
      val header = Metadata.empty.add("Cache-Control", "no-cache")
      effects.reply(new HttpBody(contentType, ByteString.copyFrom(byteArray)), header)

The example also shows how to return additional HTTP headers.

Use effects().ignore effects.ignore to serve a 404 HTTP response:

Java
      return effects().ignore();
Scala
        effects.ignore

Use effects().error effects.error to serve a 500 HTTP response:

Java
      return effects().error("500: Not able to serve {}" + fullPath);
Scala
        effects.error(s"Not able to serve $file")