Port SDK
The Port Backstage plugin is designed with flexibility in mind, allowing you to fully customize how data is presented in your Backstage instance. Since the Port SDK returns standard JavaScript objects, you have complete control over the presentation layer.
The 4 Pillars of the Port SDK
- Data model: Integrations are mapped (using JQ) to Blueprints, which are similar to tables in a database.
- Scorecards: Scorecards are JSON rules that are executed on the data model and return a score.
- Actions: Actions are JSON defined UI forms that execute your prebuilt workflows or call your internal APIs. supports REST API, Github actions, CircleCI and more.
- Automations: Automations are workflows (CI, REST API and more...) that are executed upon data model changes or time-based events.
Understanding the Data Structure
When you fetch data using the Port SDK, you receive plain JavaScript objects that you can manipulate and render however you prefer.
For example the following code fetches an entity from Port of type SERVICE_BLUEPRINT_ID
with the identifier SERVICE_NAME
:
// Example of data returned from Port SDK
const { data: entityData } = useEntityQuery(SERVICE_NAME, SERVICE_BLUEPRINT_ID);
The data structure returned from the Port SDK hook
const examplePortEntity: PortEntity = {
identifier: "backend-service-001",
title: "Backend Service API",
team: ["backend-team", "platform-team"],
icon: "api",
blueprint: "microservice-blueprint",
properties: {
language: "typescript",
version: "1.2.0",
deploymentRegion: "us-east-1",
isPublic: false,
},
relations: {
"depends-on": ["database-001", "cache-service"],
"maintained-by": "backend-team",
"monitored-by": null,
},
scorecards: {
"security-checks": {
rules: [
{
identifier: "dependency-scan",
status: "SUCCESS",
level: "critical",
ruleResults: [
{
result: true,
condition: {
property: "vulnerabilities",
operator: "=",
value: 0,
},
},
],
},
{
identifier: "authentication-check",
status: "FAILURE",
level: "high",
ruleResults: [
{
result: false,
condition: {
property: "auth-method",
operator: "contains",
value: "oauth2",
},
},
],
},
],
level: "critical",
},
"performance-checks": {
rules: [
{
identifier: "response-time",
status: "SUCCESS",
level: "medium",
ruleResults: [
{
result: true,
condition: {
property: "avg-response-time",
operator: "<",
value: 200,
},
},
],
},
],
level: "medium",
},
},
};
Creating Custom Components
You can create your own components to display Port data in ways that match your organization's needs:
import { useEntityQuery } from "@port-labs/backstage-plugin-framework";
const CustomEntityCard = () => {
const { data: entity, loading } = useEntityQuery("entity-id", "blueprint-id");
if (loading) return <LoadingComponent />;
return (
<YourCustomCard>
{/* Render entity data however you want */}
<Title>{entity.title}</Title>
<StatusBadge status={entity.properties.status} />
{/* Add your custom styling and components */}
</YourCustomCard>
);
};
Customization Examples
1. Custom Scorecard Visualization
Instead of using the default scorecard view, you can create your own visualization:
const CustomScorecard = () => {
const { scorecard } = usePortScorecard("scorecard-id");
return (
<CustomChart
score={scorecard.score}
rules={scorecard.rules}
// Add your custom styling and logic
/>
);
};
2. Custom Entity List
Create your own layout for displaying multiple entities:
const CustomEntityList = () => {
const { entities } = usePortEntities();
return (
<CustomGrid>
{entities.map((entity) => (
<CustomCard
key={entity.id}
title={entity.title}
metrics={entity.properties.metrics}
// Add your custom styling and components
/>
))}
</CustomGrid>
);
};
Integration with Existing Components
You can easily integrate Port data with your existing Backstage components:
import { Table } from "@backstage/core-components";
const PortDataTable = () => {
const { entities } = usePortEntities();
const columns = [
{ title: "Name", field: "title" },
{ title: "Owner", field: "properties.owner" },
// Add more columns as needed
];
return (
<Table
data={entities}
columns={columns}
// Use existing Backstage table features
/>
);
};
Best Practices
-
Data Transformation
- Create utility functions to transform Port data into your preferred format
- Keep transformation logic separate from presentation components
-
Component Reusability
- Build reusable components that can handle different types of Port entities
- Use TypeScript interfaces to ensure type safety
-
Performance
- Implement proper loading states
- Consider pagination for large data sets
- Use memoization when appropriate
-
Error Handling
- Add proper error boundaries
- Provide meaningful feedback to users when data loading fails
Available Hooks
The Port frontend plugin provides several hooks to help you access and manipulate data:
useEntityQuery
: Fetch a single entity. API Reference: Get an EntityuseSearchQuery
: Search for entities with a given query. API Reference: Search EntitiesuseActionRun
: Executes an action. API Reference: Execute a Self-Service ActionuseActionsQuery
: Fetch available actions. API Reference: List Actions- And more...