diff --git a/.changeset/great-goats-talk.md b/.changeset/great-goats-talk.md
new file mode 100644
index 0000000000..92a1cd59ee
--- /dev/null
+++ b/.changeset/great-goats-talk.md
@@ -0,0 +1,5 @@
+---
+'@backstage/plugin-api-docs': minor
+---
+
+Adds a new tRPC API definition widget which users can utilize to integrate their tRPC API definitions into Backstage.
diff --git a/.changeset/many-pans-unite.md b/.changeset/many-pans-unite.md
new file mode 100644
index 0000000000..59c068cec1
--- /dev/null
+++ b/.changeset/many-pans-unite.md
@@ -0,0 +1,5 @@
+---
+'@backstage/catalog-model': minor
+---
+
+Adds the tRPC API type to the catalog.
diff --git a/package.json b/package.json
index 912dd53b8a..e08ca3adfd 100644
--- a/package.json
+++ b/package.json
@@ -27,6 +27,7 @@
"create-plugin": "echo \"use 'yarn new' instead\"",
"release": "node scripts/prepare-release.js && changeset version && yarn prettier --write '{packages,plugins}/*/{package.json,CHANGELOG.md}' '.changeset/*.json' && yarn install --no-immutable",
"prettier:check": "prettier --check .",
+ "prettier:fix": "prettier --write .",
"storybook": "yarn ./storybook run start",
"snyk:test": "npx snyk test --yarn-workspaces --strict-out-of-sync=false",
"snyk:test:package": "yarn snyk:test --include",
diff --git a/packages/catalog-model/examples/all-apis.yaml b/packages/catalog-model/examples/all-apis.yaml
index e23f1b3656..472897bfac 100644
--- a/packages/catalog-model/examples/all-apis.yaml
+++ b/packages/catalog-model/examples/all-apis.yaml
@@ -6,6 +6,7 @@ metadata:
spec:
targets:
- ./apis/hello-world-api.yaml
+ - ./apis/hello-world-trpc-api.yaml
- ./apis/petstore-api.yaml
- ./apis/spotify-api.yaml
- ./apis/streetlights-api.yaml
diff --git a/packages/catalog-model/examples/apis/hello-world-trpc-api.yaml b/packages/catalog-model/examples/apis/hello-world-trpc-api.yaml
new file mode 100644
index 0000000000..f5807537b3
--- /dev/null
+++ b/packages/catalog-model/examples/apis/hello-world-trpc-api.yaml
@@ -0,0 +1,25 @@
+apiVersion: backstage.io/v1alpha1
+kind: API
+metadata:
+ name: hello-world-trpc
+ description: Hello World example for tRPC
+spec:
+ type: trpc
+ lifecycle: experimental
+ owner: team-c
+ definition: |
+ import { z } from 'zod';
+ import { publicProcedure, router } from '../trpc';
+
+ export const apiRouter = router({
+ version: publicProcedure.query(() => {
+ return { version: '0.42.0' };
+ }),
+ hello: publicProcedure
+ .input(z.object({ username: z.string().nullish() }).nullish())
+ .query(({ input, ctx }) => {
+ return {
+ text: `hello ${input?.username ?? ctx.user?.name ?? 'world'}`,
+ };
+ }),
+ });
diff --git a/packages/catalog-model/src/schema/kinds/API.v1alpha1.schema.json b/packages/catalog-model/src/schema/kinds/API.v1alpha1.schema.json
index fae1225764..3d5af710e0 100644
--- a/packages/catalog-model/src/schema/kinds/API.v1alpha1.schema.json
+++ b/packages/catalog-model/src/schema/kinds/API.v1alpha1.schema.json
@@ -46,7 +46,7 @@
"type": {
"type": "string",
"description": "The type of the API definition.",
- "examples": ["openapi", "asyncapi", "graphql", "grpc"],
+ "examples": ["openapi", "asyncapi", "graphql", "grpc", "trpc"],
"minLength": 1
},
"lifecycle": {
diff --git a/plugins/api-docs/api-report.md b/plugins/api-docs/api-report.md
index 0872d97355..a4f61872f2 100644
--- a/plugins/api-docs/api-report.md
+++ b/plugins/api-docs/api-report.md
@@ -173,4 +173,14 @@ export const ProvidedApisCard: (props: {
export const ProvidingComponentsCard: (props: {
variant?: InfoCardVariants;
}) => JSX.Element;
+
+// @public (undocumented)
+export const TrpcApiDefinitionWidget: (
+ props: TrpcApiDefinitionWidgetProps,
+) => JSX.Element;
+
+// @public (undocumented)
+export type TrpcApiDefinitionWidgetProps = {
+ definition: string;
+};
```
diff --git a/plugins/api-docs/dev/index.tsx b/plugins/api-docs/dev/index.tsx
index 9975e91e98..995aa9c2fb 100644
--- a/plugins/api-docs/dev/index.tsx
+++ b/plugins/api-docs/dev/index.tsx
@@ -32,6 +32,7 @@ import graphqlApiEntity from './graphql-example-api.yaml';
import invalidLanguageApiEntity from './invalid-language-example-api.yaml';
import openapiApiEntity from './openapi-example-api.yaml';
import otherApiEntity from './other-example-api.yaml';
+import trpcApiEntity from './trpc-example-api.yaml';
const mockEntities = [
openapiApiEntity,
@@ -39,6 +40,7 @@ const mockEntities = [
graphqlApiEntity,
invalidLanguageApiEntity,
otherApiEntity,
+ trpcApiEntity,
] as unknown as Entity[];
createDevApp()
@@ -137,4 +139,17 @@ createDevApp()
),
})
+ .addPage({
+ title: 'tRPC',
+ element: (
+
+
+
+
+
+
+
+
+ ),
+ })
.render();
diff --git a/plugins/api-docs/dev/trpc-example-api.yaml b/plugins/api-docs/dev/trpc-example-api.yaml
new file mode 100644
index 0000000000..f5807537b3
--- /dev/null
+++ b/plugins/api-docs/dev/trpc-example-api.yaml
@@ -0,0 +1,25 @@
+apiVersion: backstage.io/v1alpha1
+kind: API
+metadata:
+ name: hello-world-trpc
+ description: Hello World example for tRPC
+spec:
+ type: trpc
+ lifecycle: experimental
+ owner: team-c
+ definition: |
+ import { z } from 'zod';
+ import { publicProcedure, router } from '../trpc';
+
+ export const apiRouter = router({
+ version: publicProcedure.query(() => {
+ return { version: '0.42.0' };
+ }),
+ hello: publicProcedure
+ .input(z.object({ username: z.string().nullish() }).nullish())
+ .query(({ input, ctx }) => {
+ return {
+ text: `hello ${input?.username ?? ctx.user?.name ?? 'world'}`,
+ };
+ }),
+ });
diff --git a/plugins/api-docs/src/components/ApiDefinitionCard/ApiDefinitionWidget.tsx b/plugins/api-docs/src/components/ApiDefinitionCard/ApiDefinitionWidget.tsx
index 03a56eaa78..8d7d7a7729 100644
--- a/plugins/api-docs/src/components/ApiDefinitionCard/ApiDefinitionWidget.tsx
+++ b/plugins/api-docs/src/components/ApiDefinitionCard/ApiDefinitionWidget.tsx
@@ -18,6 +18,7 @@ import { AsyncApiDefinitionWidget } from '../AsyncApiDefinitionWidget';
import { GraphQlDefinitionWidget } from '../GraphQlDefinitionWidget';
import { OpenApiDefinitionWidget } from '../OpenApiDefinitionWidget';
import { GrpcApiDefinitionWidget } from '../GrpcApiDefinitionWidget';
+import { TrpcApiDefinitionWidget } from '../TrpcDefinitionWidget';
/** @public */
export type ApiDefinitionWidget = {
@@ -61,5 +62,12 @@ export function defaultDefinitionWidgets(): ApiDefinitionWidget[] {
),
},
+ {
+ type: 'trpc',
+ title: 'tRPC',
+ component: definition => (
+
+ ),
+ },
];
}
diff --git a/plugins/api-docs/src/components/TrpcDefinitionWidget/TrpcApiDefinitionWidget.test.tsx b/plugins/api-docs/src/components/TrpcDefinitionWidget/TrpcApiDefinitionWidget.test.tsx
new file mode 100644
index 0000000000..d7e6951e2e
--- /dev/null
+++ b/plugins/api-docs/src/components/TrpcDefinitionWidget/TrpcApiDefinitionWidget.test.tsx
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2020 The Backstage Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { renderInTestApp } from '@backstage/test-utils';
+import React from 'react';
+import { TrpcApiDefinitionWidget } from './TrpcApiDefinitionWidget';
+
+describe('', () => {
+ it('renders plain text', async () => {
+ const { getAllByText } = await renderInTestApp(
+ ,
+ );
+
+ expect(
+ getAllByText((_text, element) => element?.textContent === 'Hello World')
+ .length,
+ ).toBeGreaterThan(0);
+ });
+});
diff --git a/plugins/api-docs/src/components/TrpcDefinitionWidget/TrpcApiDefinitionWidget.tsx b/plugins/api-docs/src/components/TrpcDefinitionWidget/TrpcApiDefinitionWidget.tsx
new file mode 100644
index 0000000000..af73335dbd
--- /dev/null
+++ b/plugins/api-docs/src/components/TrpcDefinitionWidget/TrpcApiDefinitionWidget.tsx
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2023 The Backstage Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import React from 'react';
+import { CodeSnippet } from '@backstage/core-components';
+import { useTheme } from '@material-ui/core/styles';
+import { BackstageTheme } from '@backstage/theme';
+
+/** @public */
+export type TrpcApiDefinitionWidgetProps = {
+ definition: string;
+};
+
+/** @public */
+export const TrpcApiDefinitionWidget = (
+ props: TrpcApiDefinitionWidgetProps,
+) => {
+ const { definition } = props;
+ const theme = useTheme();
+ return (
+
+ );
+};
diff --git a/plugins/api-docs/src/components/TrpcDefinitionWidget/index.ts b/plugins/api-docs/src/components/TrpcDefinitionWidget/index.ts
new file mode 100644
index 0000000000..604adb06f3
--- /dev/null
+++ b/plugins/api-docs/src/components/TrpcDefinitionWidget/index.ts
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2023 The Backstage Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+export {
+ TrpcApiDefinitionWidget,
+ type TrpcApiDefinitionWidgetProps,
+} from './TrpcApiDefinitionWidget';
diff --git a/plugins/api-docs/src/components/index.ts b/plugins/api-docs/src/components/index.ts
index ea40076af4..7e7b206c54 100644
--- a/plugins/api-docs/src/components/index.ts
+++ b/plugins/api-docs/src/components/index.ts
@@ -22,3 +22,4 @@ export * from './ComponentsCards';
export * from './GraphQlDefinitionWidget';
export * from './OpenApiDefinitionWidget';
export * from './PlainApiDefinitionWidget';
+export * from './TrpcDefinitionWidget';