Openstatus www.openstatus.dev

fix: deprecated regions api (#1446)

* fix: api depreacted regions monitor schema (#1442)

* fix: openapi schema

authored by

Maximilian Kaske and committed by
GitHub
e3834a0d 2c6d7d73

+93 -12
+28
apps/server/src/routes/v1/monitors/post.test.ts
··· 1 1 import { expect, test } from "bun:test"; 2 2 3 3 import { app } from "@/index"; 4 + import { createErrorSchema } from "@/libs/errors"; 4 5 import { MonitorSchema } from "./schema"; 5 6 6 7 test("create a valid monitor", async () => { ··· 91 92 92 93 expect(res.status).toBe(401); 93 94 }); 95 + 96 + test("create a monitor with deprecated regions should return 400", async () => { 97 + const res = await app.request("/v1/monitor", { 98 + method: "POST", 99 + headers: { 100 + "x-openstatus-key": "1", 101 + "content-type": "application/json", 102 + }, 103 + body: JSON.stringify({ 104 + regions: ["ams", "jnb", "hkg", "waw"], 105 + name: "Testing Deprecated Regions", 106 + description: "Testing Deprecated Regions", 107 + url: "https://www.openstatus.dev", 108 + method: "GET", 109 + active: true, 110 + }), 111 + }); 112 + 113 + const json = await res.json(); 114 + const errorSchema = createErrorSchema("BAD_REQUEST").safeParse(json); 115 + 116 + expect(res.status).toBe(400); 117 + expect(errorSchema.success).toBe(true); 118 + expect(errorSchema.data?.message).toMatch( 119 + "Deprecated regions are not allowed: hkg, waw", 120 + ); 121 + });
+65 -12
apps/server/src/routes/v1/monitors/schema.ts
··· 6 6 monitorPeriodicitySchema, 7 7 monitorRegions, 8 8 } from "@openstatus/db/src/schema/constants"; 9 + import { regionDict } from "@openstatus/utils"; 9 10 import { ZodError } from "zod"; 10 11 11 12 const statusAssertion = z ··· 94 95 regions: z 95 96 .preprocess( 96 97 (val) => { 97 - try { 98 - if (Array.isArray(val)) return val; 99 - if (String(val).length > 0) { 100 - return String(val).split(","); 101 - } 102 - return []; 103 - } catch (e) { 98 + let regions: Array<unknown> = []; 99 + if (!val) return regions; 100 + if (Array.isArray(val)) { 101 + regions = val; 102 + } 103 + if (String(val).length > 0) { 104 + regions = String(val).split(","); 105 + } 106 + 107 + const deprecatedRegions = regions.filter((r) => { 108 + const deprecated = 109 + regionDict[r as keyof typeof regionDict].deprecated; 110 + if (deprecated) return true; 111 + return false; 112 + }); 113 + 114 + if (deprecatedRegions.length > 0) { 104 115 throw new ZodError([ 105 116 { 106 117 code: "custom", 107 - path: ["headers"], 108 - message: e instanceof Error ? e.message : "Invalid value", 118 + path: ["regions"], 119 + message: `Deprecated regions are not allowed: ${deprecatedRegions.join( 120 + ", ", 121 + )}`, 109 122 }, 110 123 ]); 111 124 } 125 + 126 + return regions; 112 127 }, 113 128 z.array(z.enum(monitorRegions)), 114 129 ) ··· 343 358 description: "Whether the monitor is public", 344 359 default: false, 345 360 }), 346 - regions: z.array(z.enum(monitorRegions)).openapi({ 347 - description: "Regions to run the request in", 348 - }), 361 + regions: z 362 + .preprocess( 363 + (val) => { 364 + let regions: Array<unknown> = []; 365 + if (!val) return regions; 366 + 367 + if (Array.isArray(val)) { 368 + regions = val; 369 + } 370 + if (String(val).length > 0) { 371 + regions = String(val).split(","); 372 + } 373 + 374 + const deprecatedRegions = regions.filter((r) => { 375 + const deprecated = 376 + regionDict[r as keyof typeof regionDict].deprecated; 377 + if (deprecated) return true; 378 + return false; 379 + }); 380 + 381 + if (deprecatedRegions.length > 0) { 382 + throw new ZodError([ 383 + { 384 + code: "custom", 385 + path: ["regions"], 386 + message: `Deprecated regions are not allowed: ${deprecatedRegions.join( 387 + ", ", 388 + )}`, 389 + }, 390 + ]); 391 + } 392 + 393 + return regions; 394 + }, 395 + z.array(z.enum(monitorRegions)), 396 + ) 397 + .default([]) 398 + .openapi({ 399 + example: ["ams"], 400 + description: "Where we should monitor it", 401 + }), 349 402 openTelemetry: z 350 403 .object({ 351 404 endpoint: z