기존 API 호출
레거시 문서
출처: 문서
본문
레거시 문서
이 섹션은 레거시 플러그인 문서의 일부예요. 이 페이지의 프론트엔드 코드 예시는 이전 프론트엔드 시스템 API(@backstage/core-plugin-api의 discoveryApiRef, fetchApiRef)를 사용해요. 같은 API는 @backstage/frontend-plugin-api를 통해 새 프론트엔드 시스템에서도 사용할 수 있어요. 직접 요청 vs 프록시 vs 백엔드 플러그인을 언제 사용할지에 대한 일반적인 안내는 두 시스템 모두에 유효해요.
이 문서는 Backstage 프론트엔드 플러그인이 이미 존재하는 서비스 API와 통신할 때 가질 수 있는 다양한 옵션을 설명해요. 아래 각 섹션은 가능한 선택지와 그것이 어울리는 상황을 설명해요.
이 예시들에서는 가상의 FrobsCo API에서 데이터를 요청할 거예요.
요청 직접 발행
가장 기본적인 선택지는 fetch나 axios 같은 지원 라이브러리를 사용해 플러그인 프론트엔드 코드에서 FrobsCo API로 직접 요청을 발행하는 것이에요.
예시:
plugins/my-awesome-plugin/src/components/AwesomeUsersTable.tsx
import { useAsync, useMountEffect } from '@react-hookz/web';function AwesomeUsersTable() { const [{ status, result, error }, { execute }] = useAsync(async () => { const response = await fetch('https://api.frobsco.com/v1/list'); return response.json(); }); useMountEffect(execute); ...}
Spotify 내부적으로 이것은 그다지 흔한 선택지가 아니었어요. 서드파티 API가 때때로 이렇게 접근됐어요. 소수의 내부 API만이 브라우저에서 직접 유용한 방식으로 자신을 노출하는 수고를 겪었고, 그래도 공개 인터넷이 아니라 이미 회사 VPN에 있는 사용자만 지원하는 경우가 많았어요.
다음 경우에 사용할 수 있어요.
- API가 이미 정확히 필요한 것을 수행/노출하는 경우.
- API의 요청/응답 패턴이 Backstage 프론트엔드 플러그인의 실제 사용 요구와 일치하는 경우. 예를 들어 최종 사용 사례가 Backstage에 작은 요약을 보여 주는 것인데 사용 가능한 유일한 API 엔드포인트가 다량의 중복 정보가 있는 30메가바이트 blob을 주는 것이라면 최종 사용자 경험이 나빠질 거예요. 특히 모바일에서요. 많은 개별 정보를 보여 주고 싶은 경우도 마찬가지예요. 셀마다 API 요청이 하나 필요한 큰 테이블을 보여 주는 것이 흔한 사용 사례라면 브라우저가 빠르게 과부하될 수 있으므로 대신 다른 곳에서 집계를 수행하는 것을 고려하고 싶을 거예요.
- API가 필요로 하는 최고 요청 속도에서 대화형 요청/응답 시간을 유지할 수 있는 경우. 데이터가 도착하기를 오래 기다리게 하면 최종 사용자 경험이 저하될 거예요.
- API 엔드포인트가 높은 가용성을 가진 경우. 브라우저에는 로드 밸런싱, 서비스 발견, 재시도, 헬스 체크, 서킷 브레이킹 등과 같은 내장 시설이 없어요. 엔드포인트가 가끔이라도 짧은 시간(예: 배포 중) 다운되면 최종 사용자가 빠르게 알아차릴 거예요.
- API가 HTTPS(HTTP뿐 아니라)로 노출되고 CORS를 제대로 처리하는 경우. 이것들은 사용자의 브라우저가 보안상 이유로 강제하는 요구 사항이며, 그렇지 않으면 요청이 거부될 거예요.
- 네트워크 조건 측면에서 API 엔드포인트가 최종 사용자가 쉽게 도달할 수 있는 경우. 최종 사용자가 경계 밖에 있다면 특히 관련이 있을 수 있어요.
- 요청이 시크릿 전달을 요구하지 않는 경우. 이 제한은 프론트엔드가 협상하고 적절히 사용할 수 있는 OAuth 토큰에는 적용되지 않아요.
Backstage 프록시 사용
Backstage에는 백엔드용 선택적 프록시 플러그인이 있으며, 이를 사용해 다운스트림 API에 프록시 라우트를 쉽게 추가할 수 있어요.
예시:
# In app-config.yamlproxy: '/frobs': http://api.frobsco.com/v1
plugins/frobs-aggregator/src/components/FrobsAggregator.tsx
import { useApi, discoveryApiRef, fetchApiRef,} from '@backstage/core-plugin-api';import { useAsync, useMountEffect } from '@react-hookz/web';function FrobsAggregator() { const fetchApi = useApi(fetchApiRef); const discoveryApi = useApi(discoveryApiRef); const [{ status, result, error }, { execute }] = useAsync(async () => { const baseUrl = await discoveryApi.getBaseUrl('proxy'); const response = await fetchApi.fetch(`${baseUrl}/frobs`); return response.json(); }); useMountEffect(execute); // ...}
프록시는 http-proxy-middleware 패키지가 구동해요. 구성 옵션의 전체 설명은 Proxying을 참고하세요.
Spotify 내부적으로 프록시 옵션은 플러그인 제작자에게 압도적으로 가장 인기 있는 선택지였어요. DNS 기반 서비스 발견이 마련되어 있고 평범한 HTTP를 노출하기 쉽게 만드는 마이크로서비스 프레임워크가 있었기 때문에, 몇 줄의 Backstage 구성을 추가하기만 하면 사용자의 웹 브라우저에서도 쉽고 견고하게 도달할 수 있다는 이점을 얻을 수 있었어요.
직접 요청 대신 이것을 사용할 수 있는 경우는 다음과 같아요.
- API 자체가 제공하지 않아서 HTTPS 종료 및/또는 CORS 처리를 수행해야 하는 경우.
- 요청에 단순한 정적 시크릿을 주입해야 하는 경우. 예를 들어 요청 헤더에 추가되는 Authorization 헤더.
- 재시도, 장애 조치, 헬스 체크, 라우팅, 요청 로깅, 재작성 등 다른 프록시 시설을 활용하고 싶은 경우.
- 이미 경계를 통해 Backstage 백엔드 자체를 노출하고 있고, Backstage 구성만으로 인그레스를 관리하며 하나의 진입점만 다루는 것이 실용적이라고 생각하는 경우.
Backstage 백엔드 플러그인 만들기
Backstage 프론트엔드와 마찬가지로 Backstage 백엔드에도 플러그인 시스템이 있어요. 위에서 언급한 프록시도 실제로 그런 플러그인 중 하나예요. FrobsCo API에 대한 직접 접근보다 더 복잡한 통합이 필요하거나 상태를 유지해야 한다면 그런 플러그인을 만들고 싶을 수 있어요.
예를 들어 frobs-aggregator라는 새 백엔드 플러그인을 만들었다고 가정하면, 이렇게 새 라우트를 추가할 수 있어요.
plugins/frobs-aggregator-backend/src/router.ts
import Router from 'express-promise-router';export async function createRouter() { const router = Router(); router.use(express.json()); router.get('/summary', async (req, res) => { const agg = await Promise.all([ fetch('https://api.frobsco.com/v1/list'), fetch('http://flerps.partnercompany.com:8080/flerp-batch'), database.currentThunk(), ]).then(async ([frobs, flerps, thunk]) => { return computeAggregate(await frobs.json(), await flerps.json(), thunk); }); res.status(200).json(agg); });}
그런 다음 프론트엔드 플러그인에서 이렇게 데이터를 가져올 수 있어요.
plugins/frobs-aggregator/src/components/FrobsAggregator.tsx
import { useApi, discoveryApiRef, fetchApiRef,} from '@backstage/core-plugin-api';import { useAsync, useMountEffect } from '@react-hookz/web';function FrobsAggregator() { const fetchApi = useApi(fetchApiRef); const discoveryApi = useApi(discoveryApiRef); const [{ status, result, error }, { execute }] = useAsync(async () => { const baseUrl = await discoveryApi.getBaseUrl('frobs-aggregator'); const response = await fetchApi.fetch(`${baseUrl}/summary`); return response.json(); }); useMountEffect(execute); // ...}
더 자세한 예시는 데이터베이스에 일부 상태를 저장하고 프론트엔드 플러그인이 사용할 API를 표면화하는 user-settings 플러그인 백엔드를 참고하세요.
Spotify 내부적으로 이것은 여러 이유로 꽤 인기 있는 선택지였어요. 일반적으로 백엔드는 느린 API나 요청/응답 형태나 속도가 프론트엔드가 직접 사용하기에 적합하지 않은 API를 위한 캐싱 및 데이터 가공 계층으로 사용됐어요. 예를 들어 이것은 대규모 목록이나 테이블에서 기본 서비스가 공급하는 더 큰 목록의 흩어진 데이터를 많이 해석하려 할 때 프론트엔드에서 효율적인 일괄 쿼리를 발행하는 것을 가능하게 했어요.
위의 대신 이것을 사용할 수 있는 경우는 다음과 같아요.
- 프록시가 처리하는 것 이상의 복잡한 모델 변환이나 프로토콜 변환을 수행해야 하는 경우.
- 프론트엔드 대신 백엔드에서 집계나 요약을 수행하고 싶은 경우.
- 느리거나 덜 신뢰할 수 있는 API의 일괄 처리나 캐싱을 활성화하고 싶은 경우.
- 플러그인에서 상태를 유지해야 하는 경우. 아마도 백엔드의 내장 데이터베이스 지원을 사용해서요.
- 작업을 수행하기 위해 시크릿을 주입하거나 다른 방식으로 API의 다른 부분이나 다른 서비스와 협상해야 하는 경우.
- API를 대신한 작업에 대해 최종 사용자 인증/인가를 시행하고 싶거나, 세션 처리를 하거나, 비슷한 것들을 하고 싶은 경우.
목적을 위해 완전히 별도의 백엔드를 만들지, 기존 것을 적응시키는 Backstage 백엔드 플러그인을 만들지 결정할 때 균형을 잡아야 할 부분이 있어요. 일반적인 조언을 드리기는 어렵지만 질문이 있으면 Discord로 연락 주시면 안내를 드릴 수 있을지도 몰라요.