From 8f1ffae6379c74a2268a9d52da8e630783fd21a3 Mon Sep 17 00:00:00 2001 From: vlnst Date: Wed, 7 Oct 2026 03:37:33 +0300 Subject: [PATCH] fix: return 404 for nonexistent question with api scraper --- src/routes/question.go | 7 ++++++- src/scraper/api.go | 6 ++++++ src/scraper/api_test.go | 31 +++++++++++++++++++++++++++++++ 3 files changed, 43 insertions(+), 1 deletion(-) create mode 100644 src/scraper/api_test.go diff --git a/src/routes/question.go b/src/routes/question.go index cba0dcc..a959d6e 100644 --- a/src/routes/question.go +++ b/src/routes/question.go @@ -4,6 +4,7 @@ import ( "anonymousoverflow/config" "anonymousoverflow/src/scraper" "anonymousoverflow/src/utils" + "errors" "fmt" "os" "regexp" @@ -41,7 +42,11 @@ func ViewQuestion(c *gin.Context) { newFilteredQuestion, answers, err := questionScraper.GetQuestion(params) if err != nil { - c.HTML(500, "home.html", gin.H{ + status := 500 + if errors.Is(err, scraper.ErrQuestionNotFound) { + status = 404 + } + c.HTML(status, "home.html", gin.H{ "errorMessage": err, "version": config.Version, }) diff --git a/src/scraper/api.go b/src/scraper/api.go index bf79821..9f89770 100644 --- a/src/scraper/api.go +++ b/src/scraper/api.go @@ -4,6 +4,7 @@ import ( "anonymousoverflow/src/types" "anonymousoverflow/src/utils" "encoding/json" + "errors" "fmt" "html/template" "net/http" @@ -92,6 +93,8 @@ type ApiScraper struct{ ApiKey string } const API_URL = "https://api.stackexchange.com/2.3" +var ErrQuestionNotFound = errors.New("Question not found") + func (s ApiScraper) GetQuestion(params ViewQuestionInputs) (types.FilteredQuestion, []types.FilteredAnswer, error) { client := resty.New() if s.ApiKey != "" { @@ -150,6 +153,9 @@ func getQuestionContent(client *resty.Client, params ViewQuestionInputs) (types. if err := json.Unmarshal(resp.Body(), &questionsResp); err != nil { return types.FilteredQuestion{}, err } + if len(questionsResp.Results) == 0 { + return types.FilteredQuestion{}, ErrQuestionNotFound + } question := questionsResp.Results[0] questionBody := template.HTML(utils.ProcessHTMLBody(question.Body)) diff --git a/src/scraper/api_test.go b/src/scraper/api_test.go new file mode 100644 index 0000000..d946e60 --- /dev/null +++ b/src/scraper/api_test.go @@ -0,0 +1,31 @@ +package scraper + +import ( + "errors" + "io" + "net/http" + "strings" + "testing" + + "github.com/go-resty/resty/v2" +) + +type roundTripperFunc func(*http.Request) (*http.Response, error) + +func (f roundTripperFunc) RoundTrip(r *http.Request) (*http.Response, error) { return f(r) } + +func TestGetQuestionContentNotFound(t *testing.T) { + client := resty.New().SetTransport(roundTripperFunc(func(r *http.Request) (*http.Response, error) { + return &http.Response{ + StatusCode: http.StatusOK, + Header: http.Header{"Content-Type": {"application/json"}}, + Body: io.NopCloser(strings.NewReader(`{"items":[]}`)), + Request: r, + }, nil + })) + + _, err := getQuestionContent(client, ViewQuestionInputs{QuestionID: "2120178", Sub: "stackoverflow"}) + if !errors.Is(err, ErrQuestionNotFound) { + t.Fatalf("expected ErrQuestionNotFound, got %v", err) + } +}