diff --git a/docs/releases.md b/docs/releases.md index 5d69ffd8..6e8cfba0 100644 --- a/docs/releases.md +++ b/docs/releases.md @@ -4,6 +4,10 @@ and the [ntfy Android app](https://github.com/binwiederhier/ntfy-android/release ## ntfy server v1.31.0 (UNRELEASED) +**Features:** + +* Preliminary `/v1/health` API endpoint for service monitoring (no ticket) + **Documentation:** * Add HTTP/2 and TLSv1.3 support to nginx docs ([#553](https://github.com/binwiederhier/ntfy/issues/553), thanks to [bt90](https://github.com/bt90)) diff --git a/server/server.go b/server/server.go index 774d6bdf..14ab0070 100644 --- a/server/server.go +++ b/server/server.go @@ -68,6 +68,7 @@ var ( authPathRegex = regexp.MustCompile(`^/[-_A-Za-z0-9]{1,64}(,[-_A-Za-z0-9]{1,64})*/auth$`) publishPathRegex = regexp.MustCompile(`^/[-_A-Za-z0-9]{1,64}/(publish|send|trigger)$`) + healthPath = "/v1/health" webConfigPath = "/config.js" userStatsPath = "/user/stats" matrixPushPath = "/_matrix/push/v1/notify" @@ -296,6 +297,8 @@ func (s *Server) handleInternal(w http.ResponseWriter, r *http.Request, v *visit return s.ensureWebEnabled(s.handleHome)(w, r, v) } else if r.Method == http.MethodHead && r.URL.Path == "/" { return s.ensureWebEnabled(s.handleEmpty)(w, r, v) + } else if r.Method == http.MethodGet && r.URL.Path == healthPath { + return s.handleHealth(w, r, v) } else if r.Method == http.MethodGet && r.URL.Path == webConfigPath { return s.ensureWebEnabled(s.handleWebConfig)(w, r, v) } else if r.Method == http.MethodGet && r.URL.Path == userStatsPath { @@ -366,6 +369,18 @@ func (s *Server) handleTopicAuth(w http.ResponseWriter, _ *http.Request, _ *visi return err } +func (s *Server) handleHealth(w http.ResponseWriter, _ *http.Request, _ *visitor) error { + response := &apiHealthResponse{ + Healthy: true, + } + w.Header().Set("Content-Type", "text/json") + w.Header().Set("Access-Control-Allow-Origin", "*") // CORS, allow cross-origin requests + if err := json.NewEncoder(w).Encode(response); err != nil { + return err + } + return nil +} + func (s *Server) handleWebConfig(w http.ResponseWriter, _ *http.Request, _ *visitor) error { appRoot := "/" if !s.config.WebRootIsApp { diff --git a/server/types.go b/server/types.go index ce57c9b5..d3035ad2 100644 --- a/server/types.go +++ b/server/types.go @@ -213,3 +213,7 @@ func (q *queryFilter) Pass(msg *message) bool { } return true } + +type apiHealthResponse struct { + Healthy bool `json:"healthy"` +}