This is a follow-up of my post on serving a general metadata json.
Solving this problem in Crystal provides a few subtle problems that Ruby doesn’t experience:
- Crystal is compiled, so the full source code isn’t available at runtime.
- Crystal is type-safe, so nils must be handled gracefully.
In this application the build details are rendered via docker build wrapper script identically to the script in my previous entry. In contrast, I don’t funnel the build details through a config object intermediary here.
Here’s what I came up with to render a /ping.json
endpoint in a
Lucky action.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
# src/lib/build.cr
class Build
DETAILS_FILE = "build_details.json"
def self.details
instance = @@instance ||= new
instance.details
end
getter build_timestamp : String
getter git_revision : String
getter version : String
def initialize
if File.exists? DETAILS_FILE
raw_file = File.read DETAILS_FILE
else
raw_file = "{}"
end
parsed_details = JSON.parse raw_file
@build_timestamp = parsed_details["build_timestamp"]?.try(&.as_s?) || Time.utc.to_s
@git_revision = parsed_details["git_revision"]?.try(&.as_s?) || "000000000"
@version = parsed_details["version"]?.try(&.as_s?) || "development"
end
def details : Hash(String, String)
{
"build_timestamp" => @build_timestamp,
"git_revision" => @git_revision,
"version" => @version,
"crystal_version" => Crystal::VERSION
}
end
end
1
2
3
4
5
6
7
8
9
10
class Home::Ping < BrowserAction
get "/ping" do
response = Hash(String, String).new
response["ok"] = "true"
response.merge! Build.details
json response
end
end