From 96ca3dd115a0deb957f20baa45ad04a815fcb28d Mon Sep 17 00:00:00 2001 From: Koen Date: Thu, 9 Apr 2026 11:33:33 +0200 Subject: [PATCH 1/8] Don't show a white page when a network or CORS failure occurs --- src/hooks/useSearch.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hooks/useSearch.ts b/src/hooks/useSearch.ts index c771cc9..5c878bd 100644 --- a/src/hooks/useSearch.ts +++ b/src/hooks/useSearch.ts @@ -237,7 +237,7 @@ export default function useSearch( setValidationResults(res); }; - search().catch(setError); + search().catch(err => setError(err + "")); }, [params.prefix, params.asns, validatePrefix, exactMatch]); // when the search form is submitted From 4df638c182b9e094806cf070b276e3180ad31386 Mon Sep 17 00:00:00 2001 From: Koen Date: Fri, 10 Apr 2026 15:29:26 +0200 Subject: [PATCH 2/8] Keep validate prefixes working when bgp-api isn't --- src/hooks/useSearch.ts | 47 +++++++++++++++++++++++++++++------------- 1 file changed, 33 insertions(+), 14 deletions(-) diff --git a/src/hooks/useSearch.ts b/src/hooks/useSearch.ts index 5c878bd..12e9bf1 100644 --- a/src/hooks/useSearch.ts +++ b/src/hooks/useSearch.ts @@ -159,22 +159,41 @@ export default function useSearch( return; } - const search = async () => { - const response = queryPrefix ? - await fetch( - `${ROTO_ENDPOINT}/api/v1/prefix/${queryPrefix}/search` - ) : - await fetch( - `${ROTO_ENDPOINT}/api/v1/asn/${arrayFromCommaSeperated(params.asns).map(parseASN).join()}/search` - ); - - if (response.status !== 200) { - // TODO as soon as we get a JSON error message via https://github.com/NLnetLabs/routinator/issues/925 - // we should display them to the user - return setError(); + const retrieve = async (): Promise => { + try { + const response = queryPrefix ? + await fetch( + `${ROTO_ENDPOINT}/api/v1/prefix/${queryPrefix}/search` + ) : + await fetch( + `${ROTO_ENDPOINT}/api/v1/asn/${arrayFromCommaSeperated(params.asns).map(parseASN).join()}/search` + ); + + if (response.status !== 200) { + // TODO as soon as we get a JSON error message via https://github.com/NLnetLabs/routinator/issues/925 + // we should display them to the user + throw new Error(response.statusText); + } + + const searchResult: Search = await response.json(); + return searchResult; + } catch (err) { + setNotification({message: "bgp-api responded with the following error:\n" + err, level: "error"}); } + const searchResult: Search = { + prefix: queryPrefix || "", + type: "empty-match", + result: { + prefix: queryPrefix || "", + meta: [], + type: "empty-match" + } + }; + return searchResult; + } - const searchResult: Search = await response.json(); + const search = async () => { + const searchResult: Search = await retrieve(); if (searchResult.error_msg) { return setError(searchResult.error_msg); From a1fb24157de35ee046d469569077bb521d9baa99 Mon Sep 17 00:00:00 2001 From: Koen Date: Fri, 10 Apr 2026 15:34:15 +0200 Subject: [PATCH 3/8] Do not attempt prefix validation with broken BGP API --- src/hooks/useSearch.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/hooks/useSearch.ts b/src/hooks/useSearch.ts index 12e9bf1..71768d7 100644 --- a/src/hooks/useSearch.ts +++ b/src/hooks/useSearch.ts @@ -195,6 +195,8 @@ export default function useSearch( const search = async () => { const searchResult: Search = await retrieve(); + const bgpApiError = searchResult.type == 'empty-match'; + if (searchResult.error_msg) { return setError(searchResult.error_msg); } @@ -209,7 +211,7 @@ export default function useSearch( let nextAsns = arrayFromCommaSeperated(params.asns); // fill in the asn provided in the search result - if (validatePrefix) { + if (validatePrefix && !bgpApiError) { const resultAsns = searchResult.result.meta .map((m) => (m.originASNs ? m.originASNs : null)) .find((asns) => asns); From 6d48a7688ebcc8dfbaf538bb76e10619dbf50ba1 Mon Sep 17 00:00:00 2001 From: Koen Date: Fri, 10 Apr 2026 15:56:43 +0200 Subject: [PATCH 4/8] Break ROTO_API_HOST on purpose --- .github/workflows/pages.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pages.yml b/.github/workflows/pages.yml index 806eed8..3d9a691 100644 --- a/.github/workflows/pages.yml +++ b/.github/workflows/pages.yml @@ -16,7 +16,7 @@ jobs: node-version: '20' cache: 'yarn' - run: yarn install --frozen-lockfile - - run: ROTO_API_HOST=https://rest.bgp-api.net ROUTINATOR_API_HOST=https://routinator.nlnetlabs.nl yarn build + - run: ROTO_API_HOST=https://example.org ROUTINATOR_API_HOST=https://routinator.nlnetlabs.nl yarn build - name: Deploy uses: cloudflare/wrangler-action@v3 with: From 6777e3147cf90d1d5df83239a23161cb0f25d234 Mon Sep 17 00:00:00 2001 From: Koen Date: Fri, 10 Apr 2026 16:17:31 +0200 Subject: [PATCH 5/8] Disable validating prefixes with broken bgp-api --- src/components/prefix-check/SearchOptions.tsx | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/components/prefix-check/SearchOptions.tsx b/src/components/prefix-check/SearchOptions.tsx index b136d8b..0c229fc 100644 --- a/src/components/prefix-check/SearchOptions.tsx +++ b/src/components/prefix-check/SearchOptions.tsx @@ -1,5 +1,6 @@ -import React, { JSX } from 'react'; +import React, { JSX, useContext } from 'react'; import Help from '../Help'; +import { StatusContext } from '../../hooks/useStatus'; export interface SearchOptionsProps { validatePrefix: boolean; @@ -18,6 +19,12 @@ export default function SearchOptions({ setAsnString, onSubmit, }: SearchOptionsProps): JSX.Element { + const { roto } = useContext(StatusContext); + + if (!roto) { + setValidatePrefix(false); + } + const disabled = validatePrefix ? '' : 'disabled'; return (
@@ -31,10 +38,11 @@ export default function SearchOptions({

-

+

+ {!roto &&
+ rest.bgp-api.net is unresponsive. Some features may not be available. +
}

ASN Lookup diff --git a/src/style/prefix-check.css b/src/style/prefix-check.css index 1c9387e..3e2927d 100644 --- a/src/style/prefix-check.css +++ b/src/style/prefix-check.css @@ -289,3 +289,12 @@ #prefix-check .matched { border-left: 0.5rem solid var(--success-border); } + +#prefix-check .warning-message { + color: var(--warning); + background-color: var(--warning-bg); + border: 1px solid var(--warning-border); + padding: 0.5rem; + border-radius: var(--radius); + margin: 0.5rem 0; +} \ No newline at end of file From 78d48be5c7a8b3ed52a7f34d63f2a00e7e24407d Mon Sep 17 00:00:00 2001 From: Koen Date: Fri, 10 Apr 2026 16:57:23 +0200 Subject: [PATCH 7/8] Stop sidebar from overflowing --- src/style/prefix-check.css | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/style/prefix-check.css b/src/style/prefix-check.css index 3e2927d..6a358d5 100644 --- a/src/style/prefix-check.css +++ b/src/style/prefix-check.css @@ -297,4 +297,8 @@ padding: 0.5rem; border-radius: var(--radius); margin: 0.5rem 0; +} + +#prefix-check.searched .warning-message { + max-width: 18rem; } \ No newline at end of file From 8f8e905c9ec9ca3e9dddea1d035dd7d43a4f2069 Mon Sep 17 00:00:00 2001 From: Koen Date: Fri, 10 Apr 2026 16:59:31 +0200 Subject: [PATCH 8/8] Change wording --- src/components/prefix-check/SearchOptions.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/prefix-check/SearchOptions.tsx b/src/components/prefix-check/SearchOptions.tsx index 9b35ecf..19b8f49 100644 --- a/src/components/prefix-check/SearchOptions.tsx +++ b/src/components/prefix-check/SearchOptions.tsx @@ -29,7 +29,7 @@ export default function SearchOptions({ return (
{!roto &&
- rest.bgp-api.net is unresponsive. Some features may not be available. + The Roto API is unresponsive. Some features may not be available.
}

ASN Lookup