From 837a42116fcca911ac1ddf5ecd799cae26b7ddad Mon Sep 17 00:00:00 2001 From: Reshma Ramaiah Date: Tue, 30 Dec 2025 14:49:55 -0500 Subject: [PATCH 1/8] Fetch dev tree from GitHub --- .gitignore | 4 +- web/src/main/go/internal/constants.go | 4 ++ web/src/main/go/internal/utils.go | 63 ++++++++++++++++++- .../public/assets/news.md.Bh7u_kab.js | 1 - .../static/assets/news.md.Bh7u_kab.js | 1 - 5 files changed, 67 insertions(+), 6 deletions(-) delete mode 100644 web/src/main/javascript/public/assets/news.md.Bh7u_kab.js delete mode 100644 web/src/main/resources/static/assets/news.md.Bh7u_kab.js diff --git a/.gitignore b/.gitignore index 1f6cf5ae..cfce715e 100644 --- a/.gitignore +++ b/.gitignore @@ -11,4 +11,6 @@ logback.xml *.DS_Store web/src/main/javascript/public/ web/src/main/resources/static -web/src/main/go/docs \ No newline at end of file +web/src/main/go/docs +trees/oncotree_development.json.etag +web/src/main/javascript/public/assets \ No newline at end of file diff --git a/web/src/main/go/internal/constants.go b/web/src/main/go/internal/constants.go index 5e3b05af..9d9a676a 100644 --- a/web/src/main/go/internal/constants.go +++ b/web/src/main/go/internal/constants.go @@ -19,6 +19,10 @@ func init() { TSV_FILES_PATH = filepath.Join(TREE_FILES_PATH, "tsv") } +const ( + DEV_TREE_GITHUB_RAW_URL = "https://raw.githubusercontent.com/cBioPortal/oncotree/master/trees/oncotree_development.json" +) + const ( LEGACY_TREE_IDENTIFIER = "oncotree_legacy_1.1" CANDIDATE_TREE_IDENTIFIER = "oncotree_candidate_release" diff --git a/web/src/main/go/internal/utils.go b/web/src/main/go/internal/utils.go index 79284074..13616549 100644 --- a/web/src/main/go/internal/utils.go +++ b/web/src/main/go/internal/utils.go @@ -14,6 +14,7 @@ import ( "strconv" "strings" "time" + "net/http" ) func ReadTreeFromFile(name string) (Tree, error) { @@ -194,11 +195,67 @@ func GetSortedMappingFilesWithDate() ([]MappingFile, error) { return mappingFiles, nil } +func (file *DatedFile) GetDatedFilenameWithoutExtension() string { + name := strings.Replace(file.Name, ".txt", "", 1) + return strings.Replace(name, ".json", "", 1) +} + func GetTreeFilepath(name string) string { + env := os.Getenv("ENV") + + if name == DEV_TREE_IDENTIFIER+".json" && env == "production" { + devTreePath := filepath.Join(TREE_FILES_PATH, DEV_TREE_IDENTIFIER+".json") + _ = fetchDevTreeIfChanged(devTreePath) + } + return filepath.Join(TREE_FILES_PATH, name) } -func (file *DatedFile) GetDatedFilenameWithoutExtension() string { - name := strings.Replace(file.Name, ".txt", "", 1) - return strings.Replace(name, ".json", "", 1) +func fetchDevTreeIfChanged(devTreePath string) error { + etagPath := devTreePath + ".etag" + + req, err := http.NewRequest("GET", DEV_TREE_GITHUB_RAW_URL, nil) + if err != nil { + return err + } + + // Include If-None-Match header if we have a saved ETag + if etag, err := os.ReadFile(etagPath); err == nil { + req.Header.Set("If-None-Match", string(etag)) + } + + resp, err := http.DefaultClient.Do(req) + if err != nil { + return err + } + defer resp.Body.Close() + + switch resp.StatusCode { + case http.StatusNotModified: + return nil // already up-to-date + + case http.StatusOK: + tmp := devTreePath + ".tmp" + out, err := os.Create(tmp) + if err != nil { + return err + } + defer out.Close() + + if _, err := io.Copy(out, resp.Body); err != nil { + return err + } + + if err := os.Rename(tmp, devTreePath); err != nil { + return err + } + + if etag := resp.Header.Get("ETag"); etag != "" { + _ = os.WriteFile(etagPath, []byte(etag), 0644) + } + return nil + + default: + return fmt.Errorf("unexpected status from GitHub: %s", resp.Status) + } } diff --git a/web/src/main/javascript/public/assets/news.md.Bh7u_kab.js b/web/src/main/javascript/public/assets/news.md.Bh7u_kab.js deleted file mode 100644 index 7d9a5551..00000000 --- a/web/src/main/javascript/public/assets/news.md.Bh7u_kab.js +++ /dev/null @@ -1 +0,0 @@ -import{_ as l,c as a,o as r,a3 as i,j as e,a as o}from"./chunks/framework.CyEiTwkJ.js";const y=JSON.parse('{"title":"News","description":"","frontmatter":{},"headers":[],"relativePath":"news.md","filePath":"news.md"}'),t={name:"news.md"},n=i('

News

October 9, 2025

April 8, 2025

November 2, 2021

November 4, 2020

October 1, 2020

April 1, 2020

February 6, 2020

February 1, 2020

December 1, 2019

August 1, 2019

May 2, 2019

May 1, 2019

March 26, 2019

March 14, 2019

March 1, 2019

February 1, 2019

November 1, 2018

September 1, 2018

August 1, 2018

July 1, 2018

June 15, 2018

June 1, 2018

May 1, 2018

April 23, 2018

',48),s=e("ul",null,[e("li",null,[e("strong",null,"New Web API Version Available"),e("ul",null,[e("li",null,[o("A new version (v1.0.0) of the OncoTree Web API is available. It can be explored here: "),e("a",{href:"http://oncotree.mskcc.org/swagger-ui.html",target:"_blank",rel:"noreferrer"},"http://oncotree.mskcc.org/swagger-ui.html"),o(),e("br"),o(" The previous version is still available, but is scheduled to be discontinued May 31, 2018 You can continue to access the previous version (v0.0.1) in its original location summarized here: ~~"),e("a",{href:"http://oncotree.mskcc.org/oncotree/swagger-ui.html~~",target:"_blank",rel:"noreferrer"},"http://oncotree.mskcc.org/oncotree/swagger-ui.html~~")])])]),e("li",null,[e("strong",null,"Details and Migration Guidance"),e("ul",null,[e("li",null,[o("The base URL for accessing all API functionality is being simplified from ~~"),e("a",{href:"http://oncotree.mskcc.org/oncotree/~~",target:"_blank",rel:"noreferrer"},"http://oncotree.mskcc.org/oncotree/~~"),o(" to "),e("a",{href:"http://oncotree.mskcc.org/",target:"_blank",rel:"noreferrer"},"http://oncotree.mskcc.org/")]),e("li",null,[e("span",{class:"oi oi-warning text-danger","aria-hidden":"true"}),o(" The /api/tumor_types.txt endpoint is now deprecated. It is scheduled for deletion as part of the next API version release.")]),e("li",null,[o("Most endpoint paths in the API remain the same and provide the same services. Exceptions are: "),e("ul",null,[e("li",null,'/api/tumorTypes used to accept a query parameter ("flat") which controlled the output format for receiving a tree representation or a flat representation of the full set of TumorTypes. Now this endpoint always returns a flat list of all TumorTypes and a new endpoint path (/api/tumorTypes/tree) is used to retrieve a tree representation of the OncoTree. Previous requests which included "flat=false" should be adjusted to use the /api/tumorTypes/tree endpoint. Otherwise "flat=true" should be dropped from the request.'),e("li",null,'/api/tumorTypes used to accept a query parameter ("deprecated") which is no longer recognized. This parameter should be dropped from requests. Deprecated OncoTree codes can instead be found in the history attribute of the response.'),e("li",null,"the POST request endpoint (/api/tumorTypes/search) which accepted a list of TumorType queries has been deprecated and is no longer available through the swagger-ui interface. The GET request endpoint /api/tumorTypes/search/{type}/{query} remains available as before. If you previously submitted an array of query requests, you should iterate through the array and call the GET request endpoint to make one query per request.")])]),e("li",null,[o("The output format (schema) of many endpoints has been simplified. You will need to adjust your result handling accordingly. Changes include: "),e("ul",null,[e("li",null,'responses no longer include a "meta" element with associated code and error messages. Instead HTTP status codes are set appropriately and error messages are supplied in message bodies. Responses also no longer contain a "data" element. Objects representing the API output are directly returned instead.'),e("li",null,"MainType values are no longer modeled as objects. Each MainType value is now represented as a simple string. The /api/mainTypes endpoint now returns an array of strings rather than an object mapping MainType names to MainType objects."),e("li",{"UMLS:":"","[CL497188,C1510796],NCI:":"","[C123384,C40361]":""},'TumorType values no longer contain elements "id", "deprecated", "links", "NCI", "UMLS". A new element ("externalReferences") has been added which contains a JSON object mapping external authority names to arrays of associated identifiers. Such as "externalReferences":')])]),e("li",null,'Argument validation has been strengthened for several parameters, such as "type" and "levels" in the /api/tumorTypes/search/{type}/{query} endpoint. Now improper arguments cause an a HTTP status response indicating error, with a description of the problem in the body.'),e("li",null,[o("Some requests which fail to find matching entities now return NOT_FOUND HTTP status code 404 rather than an empty result. Examples: "),e("a",{href:"http://oncotree.mskcc.org/api/tumorTypes/search/code/TEST_UNDEFINED_CODE",target:"_blank",rel:"noreferrer"},"http://oncotree.mskcc.org/api/tumorTypes/search/code/TEST_UNDEFINED_CODE"),o(" or "),e("a",{href:"http://oncotree.mskcc.org/api/crosswalk?vocabularyId=ICDO&conceptId=C15",target:"_blank",rel:"noreferrer"},"http://oncotree.mskcc.org/api/crosswalk?vocabularyId=ICDO&conceptId=C15")])])])],-1),c=i('

April 1, 2018

March 1, 2018

February 7, 2018

February 1, 2018

',8),u=[n,s,c];function d(m,h,p,T,L,b){return r(),a("div",null,u)}const M=l(t,[["render",d]]);export{y as __pageData,M as default}; diff --git a/web/src/main/resources/static/assets/news.md.Bh7u_kab.js b/web/src/main/resources/static/assets/news.md.Bh7u_kab.js deleted file mode 100644 index 7d9a5551..00000000 --- a/web/src/main/resources/static/assets/news.md.Bh7u_kab.js +++ /dev/null @@ -1 +0,0 @@ -import{_ as l,c as a,o as r,a3 as i,j as e,a as o}from"./chunks/framework.CyEiTwkJ.js";const y=JSON.parse('{"title":"News","description":"","frontmatter":{},"headers":[],"relativePath":"news.md","filePath":"news.md"}'),t={name:"news.md"},n=i('

News

October 9, 2025

April 8, 2025

November 2, 2021

November 4, 2020

October 1, 2020

April 1, 2020

February 6, 2020

February 1, 2020

December 1, 2019

August 1, 2019

May 2, 2019

May 1, 2019

March 26, 2019

March 14, 2019

March 1, 2019

February 1, 2019

November 1, 2018

September 1, 2018

August 1, 2018

July 1, 2018

June 15, 2018

June 1, 2018

May 1, 2018

April 23, 2018

',48),s=e("ul",null,[e("li",null,[e("strong",null,"New Web API Version Available"),e("ul",null,[e("li",null,[o("A new version (v1.0.0) of the OncoTree Web API is available. It can be explored here: "),e("a",{href:"http://oncotree.mskcc.org/swagger-ui.html",target:"_blank",rel:"noreferrer"},"http://oncotree.mskcc.org/swagger-ui.html"),o(),e("br"),o(" The previous version is still available, but is scheduled to be discontinued May 31, 2018 You can continue to access the previous version (v0.0.1) in its original location summarized here: ~~"),e("a",{href:"http://oncotree.mskcc.org/oncotree/swagger-ui.html~~",target:"_blank",rel:"noreferrer"},"http://oncotree.mskcc.org/oncotree/swagger-ui.html~~")])])]),e("li",null,[e("strong",null,"Details and Migration Guidance"),e("ul",null,[e("li",null,[o("The base URL for accessing all API functionality is being simplified from ~~"),e("a",{href:"http://oncotree.mskcc.org/oncotree/~~",target:"_blank",rel:"noreferrer"},"http://oncotree.mskcc.org/oncotree/~~"),o(" to "),e("a",{href:"http://oncotree.mskcc.org/",target:"_blank",rel:"noreferrer"},"http://oncotree.mskcc.org/")]),e("li",null,[e("span",{class:"oi oi-warning text-danger","aria-hidden":"true"}),o(" The /api/tumor_types.txt endpoint is now deprecated. It is scheduled for deletion as part of the next API version release.")]),e("li",null,[o("Most endpoint paths in the API remain the same and provide the same services. Exceptions are: "),e("ul",null,[e("li",null,'/api/tumorTypes used to accept a query parameter ("flat") which controlled the output format for receiving a tree representation or a flat representation of the full set of TumorTypes. Now this endpoint always returns a flat list of all TumorTypes and a new endpoint path (/api/tumorTypes/tree) is used to retrieve a tree representation of the OncoTree. Previous requests which included "flat=false" should be adjusted to use the /api/tumorTypes/tree endpoint. Otherwise "flat=true" should be dropped from the request.'),e("li",null,'/api/tumorTypes used to accept a query parameter ("deprecated") which is no longer recognized. This parameter should be dropped from requests. Deprecated OncoTree codes can instead be found in the history attribute of the response.'),e("li",null,"the POST request endpoint (/api/tumorTypes/search) which accepted a list of TumorType queries has been deprecated and is no longer available through the swagger-ui interface. The GET request endpoint /api/tumorTypes/search/{type}/{query} remains available as before. If you previously submitted an array of query requests, you should iterate through the array and call the GET request endpoint to make one query per request.")])]),e("li",null,[o("The output format (schema) of many endpoints has been simplified. You will need to adjust your result handling accordingly. Changes include: "),e("ul",null,[e("li",null,'responses no longer include a "meta" element with associated code and error messages. Instead HTTP status codes are set appropriately and error messages are supplied in message bodies. Responses also no longer contain a "data" element. Objects representing the API output are directly returned instead.'),e("li",null,"MainType values are no longer modeled as objects. Each MainType value is now represented as a simple string. The /api/mainTypes endpoint now returns an array of strings rather than an object mapping MainType names to MainType objects."),e("li",{"UMLS:":"","[CL497188,C1510796],NCI:":"","[C123384,C40361]":""},'TumorType values no longer contain elements "id", "deprecated", "links", "NCI", "UMLS". A new element ("externalReferences") has been added which contains a JSON object mapping external authority names to arrays of associated identifiers. Such as "externalReferences":')])]),e("li",null,'Argument validation has been strengthened for several parameters, such as "type" and "levels" in the /api/tumorTypes/search/{type}/{query} endpoint. Now improper arguments cause an a HTTP status response indicating error, with a description of the problem in the body.'),e("li",null,[o("Some requests which fail to find matching entities now return NOT_FOUND HTTP status code 404 rather than an empty result. Examples: "),e("a",{href:"http://oncotree.mskcc.org/api/tumorTypes/search/code/TEST_UNDEFINED_CODE",target:"_blank",rel:"noreferrer"},"http://oncotree.mskcc.org/api/tumorTypes/search/code/TEST_UNDEFINED_CODE"),o(" or "),e("a",{href:"http://oncotree.mskcc.org/api/crosswalk?vocabularyId=ICDO&conceptId=C15",target:"_blank",rel:"noreferrer"},"http://oncotree.mskcc.org/api/crosswalk?vocabularyId=ICDO&conceptId=C15")])])])],-1),c=i('

April 1, 2018

March 1, 2018

February 7, 2018

February 1, 2018

',8),u=[n,s,c];function d(m,h,p,T,L,b){return r(),a("div",null,u)}const M=l(t,[["render",d]]);export{y as __pageData,M as default}; From 17376e357ba98487101b9ba4d1413137ab206dc2 Mon Sep 17 00:00:00 2001 From: Reshma Ramaiah Date: Tue, 30 Dec 2025 15:39:22 -0500 Subject: [PATCH 2/8] add env variable to dockerfile --- Dockerfile | 1 + 1 file changed, 1 insertion(+) diff --git a/Dockerfile b/Dockerfile index 3df2df68..05e4c124 100644 --- a/Dockerfile +++ b/Dockerfile @@ -31,4 +31,5 @@ ENV STATIC_DIR=/root/backend/frontend/static EXPOSE 8080 ENV GIN_MODE=release +ENV APP_ENV=production CMD ["./main"] \ No newline at end of file From 54eb8b5f57d23139c50ca0307448e06585abc0ed Mon Sep 17 00:00:00 2001 From: Reshma Ramaiah Date: Tue, 30 Dec 2025 15:43:42 -0500 Subject: [PATCH 3/8] correct env variable to utils --- web/src/main/go/internal/utils.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/web/src/main/go/internal/utils.go b/web/src/main/go/internal/utils.go index 13616549..ccb6c14f 100644 --- a/web/src/main/go/internal/utils.go +++ b/web/src/main/go/internal/utils.go @@ -201,9 +201,9 @@ func (file *DatedFile) GetDatedFilenameWithoutExtension() string { } func GetTreeFilepath(name string) string { - env := os.Getenv("ENV") + appEnv := os.Getenv("APP_ENV") - if name == DEV_TREE_IDENTIFIER+".json" && env == "production" { + if name == DEV_TREE_IDENTIFIER+".json" && appEnv == "production" { devTreePath := filepath.Join(TREE_FILES_PATH, DEV_TREE_IDENTIFIER+".json") _ = fetchDevTreeIfChanged(devTreePath) } From f68c2ba7346b2066224a5280bc8d8248e76be050 Mon Sep 17 00:00:00 2001 From: Reshma Ramaiah Date: Mon, 5 Jan 2026 10:44:19 -0500 Subject: [PATCH 4/8] review changes --- web/src/main/go/internal/utils.go | 54 ++++++++++++++++++++----------- 1 file changed, 35 insertions(+), 19 deletions(-) diff --git a/web/src/main/go/internal/utils.go b/web/src/main/go/internal/utils.go index ccb6c14f..3bc9dd27 100644 --- a/web/src/main/go/internal/utils.go +++ b/web/src/main/go/internal/utils.go @@ -6,6 +6,7 @@ import ( "errors" "fmt" "io" + "net/http" "os" "path/filepath" "regexp" @@ -14,10 +15,13 @@ import ( "strconv" "strings" "time" - "net/http" ) func ReadTreeFromFile(name string) (Tree, error) { + if err := maybeUpdateDevTree(name); err != nil { + return nil, err + } + treeBytes, err := os.ReadFile(GetTreeFilepath(name)) if err != nil { return nil, fmt.Errorf("error reading file '%v': %v", name, err) @@ -32,6 +36,17 @@ func ReadTreeFromFile(name string) (Tree, error) { return tree, nil } +func maybeUpdateDevTree(name string) error { + appEnv := os.Getenv("APP_ENV") + + if name == DEV_TREE_IDENTIFIER+".json" && appEnv == "production" { + devTreePath := filepath.Join(TREE_FILES_PATH, name) + return fetchDevTreeIfChanged(devTreePath) + } + + return nil +} + var filenameWithDateRegex = regexp.MustCompile(`^oncotree_(\d{4})_(\d{2})_(\d{2})(?:\.(json|txt))?$`) type DatedFile struct { @@ -195,31 +210,30 @@ func GetSortedMappingFilesWithDate() ([]MappingFile, error) { return mappingFiles, nil } +func GetTreeFilepath(name string) string { + return filepath.Join(TREE_FILES_PATH, name) +} + func (file *DatedFile) GetDatedFilenameWithoutExtension() string { name := strings.Replace(file.Name, ".txt", "", 1) return strings.Replace(name, ".json", "", 1) } -func GetTreeFilepath(name string) string { - appEnv := os.Getenv("APP_ENV") - - if name == DEV_TREE_IDENTIFIER+".json" && appEnv == "production" { - devTreePath := filepath.Join(TREE_FILES_PATH, DEV_TREE_IDENTIFIER+".json") - _ = fetchDevTreeIfChanged(devTreePath) +func fetchDevTreeIfChanged(devTreePath string) error { + cacheDir := filepath.Join(TREE_FILES_PATH, "..", "cache") + if err := os.MkdirAll(cacheDir, 0755); err != nil { + return fmt.Errorf("failed to create cache dir: %w", err) } - return filepath.Join(TREE_FILES_PATH, name) -} - -func fetchDevTreeIfChanged(devTreePath string) error { - etagPath := devTreePath + ".etag" + base := filepath.Base(devTreePath) + tmpPath := filepath.Join(cacheDir, base+".tmp") + etagPath := filepath.Join(cacheDir, base+".etag") - req, err := http.NewRequest("GET", DEV_TREE_GITHUB_RAW_URL, nil) + req, err := http.NewRequest(http.MethodGet, DEV_TREE_GITHUB_RAW_URL, nil) if err != nil { return err } - // Include If-None-Match header if we have a saved ETag if etag, err := os.ReadFile(etagPath); err == nil { req.Header.Set("If-None-Match", string(etag)) } @@ -232,11 +246,10 @@ func fetchDevTreeIfChanged(devTreePath string) error { switch resp.StatusCode { case http.StatusNotModified: - return nil // already up-to-date + return nil case http.StatusOK: - tmp := devTreePath + ".tmp" - out, err := os.Create(tmp) + out, err := os.Create(tmpPath) if err != nil { return err } @@ -246,13 +259,16 @@ func fetchDevTreeIfChanged(devTreePath string) error { return err } - if err := os.Rename(tmp, devTreePath); err != nil { + if err := os.Rename(tmpPath, devTreePath); err != nil { return err } if etag := resp.Header.Get("ETag"); etag != "" { - _ = os.WriteFile(etagPath, []byte(etag), 0644) + if err := os.WriteFile(etagPath, []byte(etag), 0644); err != nil { + return fmt.Errorf("failed to write etag: %w", err) + } } + return nil default: From 6d4ddf46a9513b0d37a01fe7e31d0b1d136fe008 Mon Sep 17 00:00:00 2001 From: Reshma Ramaiah Date: Tue, 6 Jan 2026 14:46:27 -0500 Subject: [PATCH 5/8] review changes 2 --- web/src/main/go/internal/utils.go | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/web/src/main/go/internal/utils.go b/web/src/main/go/internal/utils.go index 3bc9dd27..653ee634 100644 --- a/web/src/main/go/internal/utils.go +++ b/web/src/main/go/internal/utils.go @@ -18,8 +18,12 @@ import ( ) func ReadTreeFromFile(name string) (Tree, error) { - if err := maybeUpdateDevTree(name); err != nil { - return nil, err + appEnv := os.Getenv("APP_ENV") + if name == DEV_TREE_IDENTIFIER+".json" && appEnv == "production" { + devTreePath := filepath.Join(TREE_FILES_PATH, name) + if err := fetchDevTreeIfChanged(devTreePath); err != nil { + return nil, err + } } treeBytes, err := os.ReadFile(GetTreeFilepath(name)) @@ -36,17 +40,6 @@ func ReadTreeFromFile(name string) (Tree, error) { return tree, nil } -func maybeUpdateDevTree(name string) error { - appEnv := os.Getenv("APP_ENV") - - if name == DEV_TREE_IDENTIFIER+".json" && appEnv == "production" { - devTreePath := filepath.Join(TREE_FILES_PATH, name) - return fetchDevTreeIfChanged(devTreePath) - } - - return nil -} - var filenameWithDateRegex = regexp.MustCompile(`^oncotree_(\d{4})_(\d{2})_(\d{2})(?:\.(json|txt))?$`) type DatedFile struct { From d58a852eb8deedfbf2b21afc805da35e21451432 Mon Sep 17 00:00:00 2001 From: Reshma Ramaiah Date: Wed, 7 Jan 2026 10:15:40 -0500 Subject: [PATCH 6/8] fix tree api --- web/src/main/go/cmd/server/main.go | 3 ++- web/src/main/go/internal/utils.go | 12 ++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/web/src/main/go/cmd/server/main.go b/web/src/main/go/cmd/server/main.go index 70b5a7d2..bfc7cb76 100644 --- a/web/src/main/go/cmd/server/main.go +++ b/web/src/main/go/cmd/server/main.go @@ -298,12 +298,13 @@ func tumorTypesTreeHandler(c *gin.Context) { treeFile := fmt.Sprintf("%s.json", resolvedVersion) - raw, err := os.ReadFile(filepath.Join(TreeDir, treeFile)) + raw, err := internal.ReadTreeRaw(treeFile) if err != nil { c.Error(fmt.Errorf("Failed to read raw tree file '%s': %w", treeFile, err)) c.String(http.StatusServiceUnavailable, "Required data source unavailable") return } + c.Data(http.StatusOK, "application/json", raw) } diff --git a/web/src/main/go/internal/utils.go b/web/src/main/go/internal/utils.go index 653ee634..69ac242e 100644 --- a/web/src/main/go/internal/utils.go +++ b/web/src/main/go/internal/utils.go @@ -268,3 +268,15 @@ func fetchDevTreeIfChanged(devTreePath string) error { return fmt.Errorf("unexpected status from GitHub: %s", resp.Status) } } + +func ReadTreeRaw(name string) ([]byte, error) { + appEnv := os.Getenv("APP_ENV") + if name == DEV_TREE_IDENTIFIER+".json" && appEnv == "production" { + devTreePath := filepath.Join(TREE_FILES_PATH, name) + if err := fetchDevTreeIfChanged(devTreePath); err != nil { + return nil, err + } + } + + return os.ReadFile(GetTreeFilepath(name)) +} From e8fcb07d311e356099a78a8ca01ddeec110118f9 Mon Sep 17 00:00:00 2001 From: Reshma Ramaiah Date: Wed, 7 Jan 2026 11:17:53 -0500 Subject: [PATCH 7/8] review changes 3 --- web/src/main/go/internal/utils.go | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/web/src/main/go/internal/utils.go b/web/src/main/go/internal/utils.go index 69ac242e..45ada57b 100644 --- a/web/src/main/go/internal/utils.go +++ b/web/src/main/go/internal/utils.go @@ -18,17 +18,9 @@ import ( ) func ReadTreeFromFile(name string) (Tree, error) { - appEnv := os.Getenv("APP_ENV") - if name == DEV_TREE_IDENTIFIER+".json" && appEnv == "production" { - devTreePath := filepath.Join(TREE_FILES_PATH, name) - if err := fetchDevTreeIfChanged(devTreePath); err != nil { - return nil, err - } - } - - treeBytes, err := os.ReadFile(GetTreeFilepath(name)) + treeBytes, err := ReadTreeRaw(name) if err != nil { - return nil, fmt.Errorf("error reading file '%v': %v", name, err) + return nil, fmt.Errorf("failed to read tree '%s': %w", name, err) } var tree Tree From c1ee02619865758a6aa510f648b0b6c6ecfcf937 Mon Sep 17 00:00:00 2001 From: Reshma Ramaiah Date: Wed, 7 Jan 2026 11:18:56 -0500 Subject: [PATCH 8/8] review changes 3 --- web/src/main/go/internal/utils.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/src/main/go/internal/utils.go b/web/src/main/go/internal/utils.go index 45ada57b..12c3192c 100644 --- a/web/src/main/go/internal/utils.go +++ b/web/src/main/go/internal/utils.go @@ -20,7 +20,7 @@ import ( func ReadTreeFromFile(name string) (Tree, error) { treeBytes, err := ReadTreeRaw(name) if err != nil { - return nil, fmt.Errorf("failed to read tree '%s': %w", name, err) + return nil, fmt.Errorf("error reading file '%v': %v", name, err) } var tree Tree