Skip to content

Commit 147200a

Browse files
committed
feat(api): fw-7456 add CORS support for JSON API endpoints
Add Access-Control-Allow-Origin and Access-Control-Allow-Credentials headers to all JSON API responses, and handle OPTIONS preflight requests with 204 No Content. This ensures cross-origin requests from browsers work consistently regardless of CDN cache state.
1 parent c8b6205 commit 147200a

3 files changed

Lines changed: 45 additions & 7 deletions

File tree

src/jsons/health.nim

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,10 @@ proc createJsonApiHealthRouter*(cfg: Config) =
1111
router jsonapi_health:
1212
get "/api/health":
1313
cond cfg.enableJsonApi
14-
let headers = {"Content-Type": "application/json; charset=utf-8"}
14+
let origin = corsOrigin()
15+
let headers = {
16+
"Content-Type": "application/json; charset=utf-8",
17+
"Access-Control-Allow-Origin": origin,
18+
"Access-Control-Allow-Credentials": "true"
19+
}
1520
resp Http200, headers, """{"message": "OK"}"""

src/nitter.nim

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# SPDX-License-Identifier: AGPL-3.0-only
2-
import asyncdispatch, strformat, logging
2+
import asyncdispatch, strformat, logging, re
33
from net import Port
44
from htmlgen import a
55
from os import getEnv
@@ -71,6 +71,17 @@ settings:
7171
reusePort = true
7272

7373
routes:
74+
# CORS preflight handler for API routes
75+
options re"/api/.*":
76+
let origin = if request.headers.hasKey("Origin"): request.headers["Origin"] else: "*"
77+
resp Http204, {
78+
"Access-Control-Allow-Origin": origin,
79+
"Access-Control-Allow-Methods": "GET, POST, OPTIONS",
80+
"Access-Control-Allow-Headers": "Content-Type, Authorization, DNT",
81+
"Access-Control-Allow-Credentials": "true",
82+
"Access-Control-Max-Age": "300"
83+
}, ""
84+
7485
get "/":
7586
resp renderMain(renderSearch(), request, cfg, themePrefs())
7687

src/routes/router_utils.nim

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -43,25 +43,47 @@ template getCursor*(req: Request): string =
4343
proc getNames*(name: string): seq[string] =
4444
name.strip(chars={'/'}).split(",").filterIt(it.len > 0)
4545

46+
template corsOrigin*(): string {.dirty.} =
47+
if request.headers.hasKey("Origin"): request.headers["Origin"] else: "*"
48+
4649
template respJson*(node: JsonNode) =
47-
resp $node, "application/json"
50+
let origin = corsOrigin()
51+
resp Http200, {
52+
"Content-Type": "application/json",
53+
"Access-Control-Allow-Origin": origin,
54+
"Access-Control-Allow-Credentials": "true"
55+
}, $node
4856

4957
template respJsonSuccess*(data: JsonNode) =
58+
let origin = corsOrigin()
5059
let successResponse = %*{
5160
"code": 0,
5261
"data": data
5362
}
54-
resp $successResponse, "application/json"
63+
resp Http200, {
64+
"Content-Type": "application/json",
65+
"Access-Control-Allow-Origin": origin,
66+
"Access-Control-Allow-Credentials": "true"
67+
}, $successResponse
5568

5669
template respJsonError*(message: string, errorType: string = "", httpCode: HttpCode = Http200) =
70+
let origin = corsOrigin()
5771
var errorResponse = %*{
5872
"code": -1,
5973
"error": message
6074
}
6175
if errorType.len > 0:
6276
errorResponse["error_type"] = %errorType
63-
resp httpCode, $errorResponse, "application/json"
77+
resp httpCode, {
78+
"Content-Type": "application/json",
79+
"Access-Control-Allow-Origin": origin,
80+
"Access-Control-Allow-Credentials": "true"
81+
}, $errorResponse
6482

6583
template respJsonNull*() =
66-
let nullResponse = newJNull()
67-
resp $nullResponse, "application/json"
84+
let origin = corsOrigin()
85+
resp Http200, {
86+
"Content-Type": "application/json",
87+
"Access-Control-Allow-Origin": origin,
88+
"Access-Control-Allow-Credentials": "true"
89+
}, $newJNull()

0 commit comments

Comments
 (0)