API Reference
Common API Use Cases
- When the facts are infrequently updated, or they are sporadic in nature you can use the Facts API to submit them when they change (event based). This can help reduce the amount of calls that soundcheck is making to fetch certain facts.
- When check rules are hard to set up, or you already have a system that calculates them you can submit the result straight to the Check Results API.
- When you want to prevent releasing a component that is not meeting your standards. You can set up your CI/CD pipeline to rerun checks and get entity certification level before allowing release.
Checks API
Use the Checks API to:
- List all checks
- Get a check by id
- Execute a check against one more entities.
Each API call is discussed in detail below.
NOTE: Your environment may not have checks specified in the app-config.yaml file. Here is a sample configuration with two checks defined. The first is checking a fact collected by the SCM plugin for the existence of a README.md file at the root level of a repository. The second analyzes the metadata returned by the catalog fact collector for the existence of either an internal or external metadata tag.
soundcheck:
checks:
- id: has_required_tags
rule:
any:
- factRef: catalog:default/entity_descriptor
path: $.metadata.tags
operator: contains
value: internal
- factRef: catalog:default/entity_descriptor
path: $.metadata.tags
operator: contains
value: external
passedMessage: |
Tag found, check passed.
failedMessage: |
No `internal` or `external` tag found, check failed.
- id: has_readme
rule:
factRef: scm:default/readme
path: $.exists
operator: equal
value: true
passedMessage: |
README.md was found at repository root, check passed.
failedMessage: |
README.md was not found at repository root, check failed.
The existence of these checks is assumed when executing API calls in the rest of this Checks API section.
Get a List of Checks
The endpoint to get a list of checks is at /api/soundcheck/checks. For a local deployment, the call would look like this:
GET localhost:7007/api/soundcheck/checks
With the above check defined, hitting the /checks endpoint will yield the following output:
{
"checks": [
{
"id": "has_required_tags",
"rule": {
"any": [
{
"factRef": "catalog:default/entity_descriptor",
"operator": "contains",
"value": "internal",
"path": "$.metadata.tags"
},
{
"factRef": "catalog:default/entity_descriptor",
"operator": "contains",
"value": "external",
"path": "$.metadata.tags"
}
]
},
"passedMessage": "Tag found, check passed.\n",
"failedMessage": "No `internal` or `external` tag found, check failed.\n"
},
{
"id": "has_readme",
"rule": {
"factRef": "scm:default/readme",
"operator": "equal",
"value": true,
"path": "$.exists"
},
"passedMessage": "README.md was found at repository root, check passed.\n",
"failedMessage": "README.md was not found at repository root, check failed.\n"
}
]
}
Get a Check by ID
The endpoint to get a single check by ID is at /api/soundcheck/checks/:checkId. For a local deployment, the call would look like this:
GET localhost:7007/api/soundcheck/checks/has_readme
where 'has_readme' above is the check id, which was defined at the beginning of this section.
Executing the call above results in the following output:
{
"check": {
"id": "has_readme",
"rule": {
"factRef": "scm:default/readme",
"operator": "equal",
"value": true,
"path": "$.exists"
},
"passedMessage": "README.md was found at repository root, check passed.\n",
"failedMessage": "README.md was not found at repository root, check failed.\n"
}
}
Trigger a Set of Checks to Execute
This endpoint allows for a set of checks to be executed in soundcheck. To execute a set of checks, POST to:
POST localhost:7007/api/soundcheck/checks/execute
The POST request takes a json request body composed of one of four sets of parameters as follows:
1.) An array of checkIds
and an array of entityRefs
:
{
"entityRefs": ["component:default/queue-proxy", "component:default/searcher"],
"checkIds": ["has_required_tags", "has_readme"]
}
POSTing the above request results in output like the following:
{
"results": [
{
"entityRef": "component:default/queue-proxy",
"timestamp": "2023-02-15T19:33:15.945Z",
"checkId": "has_required_tags",
"state": "failed",
"details": {
"notes": {
"type": "notes",
"data": "No `internal` or `external` tag found, check failed.\n"
}
}
},
{
"entityRef": "component:default/searcher",
"timestamp": "2023-02-15T19:33:15.945Z",
"checkId": "has_required_tags",
"state": "failed",
"details": {
"notes": {
"type": "notes",
"data": "No `internal` or `external` tag found, check failed.\n"
}
}
}
]
}
Note that the response above has no results for the 'has_readme' check, this is because that check does not apply to the given components and thus is not executed.
2.) An array of checkIds
and a filter
:
{
"checkIds": ["has_required_tags", "has_readme"],
"filter": { "metadata.tags": "java" }
}
This will execute the given list of checks against all entities that match the filter, and return an output similar to the following, which has been truncated for brevity:
{
"results": [
{
"entityRef": "component:default/artist-lookup",
"timestamp": "2023-02-15T20:24:40.473Z",
"checkId": "has_required_tags",
"state": "failed",
"details": {
"notes": {
"type": "notes",
"data": "No `internal` or `external` tag found, check failed.\n"
}
}
},
...
]
}
3.) A single check
which is a FactCheckerSchema
and an array of entityRefs
:
{
"check": {
"id": "has_required_tags",
"rule": {
"factRef": "catalog:default/entity_descriptor",
"path": "$.metadata.tags",
"operator": "contains",
"value": "internal"
}
},
"entityRefs": ["component:default/queue-proxy", "component:default/searcher"]
}
This will execute the supplied check against the given list of entities, and return a results output like the following, where each entry describes the entity and the result of the check:
{
"results": [
{
"entityRef": "component:default/queue-proxy",
"timestamp": "2023-02-15T20:43:44.990Z",
"checkId": "has_required_tags",
"state": "failed"
},
{
"entityRef": "component:default/searcher",
"timestamp": "2023-02-15T20:43:44.990Z",
"checkId": "has_required_tags",
"state": "failed"
}
]
}
4.) A single check
which is a FactCheckerSchema
and filter
:
{
"check": {
"id": "has_required_tags",
"rule": {
"factRef": "catalog:default/entity_descriptor",
"path": "$.metadata.tags",
"operator": "contains",
"value": "internal"
}
},
"filter": { "metadata.tags": "java" }
}
This will execute the given check against all entities matching the filter, and return an array of results describing the result of the check against all entities which passed the filter:
{
"results": [
{
"entityRef": "component:default/artist-lookup",
"timestamp": "2023-02-15T20:49:11.601Z",
"checkId": "has_required_tags",
"state": "failed"
},
{
"entityRef": "component:default/playback-order",
"timestamp": "2023-02-15T20:49:11.601Z",
"checkId": "has_required_tags",
"state": "failed"
},
{
"entityRef": "component:default/podcast-api",
"timestamp": "2023-02-15T20:49:11.601Z",
"checkId": "has_required_tags",
"state": "failed"
},
{
"entityRef": "template:default/springboot-template",
"timestamp": "2023-02-15T20:49:11.601Z",
"checkId": "has_required_tags",
"state": "failed"
}
]
}
Finally, this request also allows an optional dry-run query parameter which can be set to empty,
true
, or false
.
true
(or empty, ie: '?dryRun' with no value set) indicates that the request is indeed a dry-run, and will execute the checks but will not persist the results.false
indicates a standard request to perform the checks and record the results. This is also the default behavior if thedryRun
parameter is not specified.
Check Results API
Use the Check Results API to submit and retrieve check results to/from Soundcheck.
Submitting Results
Submit check results to Soundcheck.
POST localhost:7007/api/soundcheck/results
Request Body
See Check Results Schema.
Example Request Body
Passed
{
"results": [
{
"entityRef": "component:default/petstore",
"checkId": "tests-run",
"state": "passed"
}
]
}
Failed
{
"results": [
{
"entityRef": "component:default/petstore",
"checkId": "tests-run",
"state": "failed",
"details": {
"notes": {
"data": "Tests were not executed."
}
}
}
]
}
Example Requests
BACKSTAGE_BACKEND=localhost:7007 && \
curl \
-H 'Content-Type: application/json' \
"${BACKSTAGE_BACKEND}/api/soundcheck/results" \
--data @- << EOF
{
"results": [
{
"entityRef": "component:default/petstore",
"checkId": "tests-run",
"state": "passed"
}
]
}
EOF
POST /api/soundcheck/results HTTP/1.1
Host: localhost:7007
Content-Type: application/json
Content-Length: 129
{
"results": [
{
"entityRef": "component:default/petstore",
"checkId": "tests-run",
"state": "passed"
}
]
}
Responses
200 Response
Returns the check results which are either new or resulted in a change of state.
See Check Results Schema.
Example Response Body
{
"results": [
{
"entityRef": "string",
"checkId": "string",
"scope": "string",
"state": "passed",
"details": {
"notes": {
"type": "notes",
"version": 1,
"data": "string"
}
}
}
]
}
400 Response
Body did not match expected schema.
See Error Schema.
Example Response Body
{
"error": {
"name": "string",
"message": "string",
"stack": "string"
},
"request": {
"method": "string",
"url": "string"
},
"response": {
"statusCode": 0
}
}
500 Response
Soundcheck encountered an unexpected condition that prevented it from fulfilling the request.
See Error Schema.
Example Response Body
{
"error": {
"name": "string",
"message": "string",
"stack": "string"
},
"request": {
"method": "string",
"url": "string"
},
"response": {
"statusCode": 0
}
}
Retrieving Results
GET localhost:7007/api/soundcheck/results
Returns check results for a given entity.
Query Parameters
entityRef
Required. A reference to the entity to retrieve check results for.checks
Optional. Filters check results to only those with the provided check ID(s). Accepts multiple values:checks=A,checks=B
Example Requests
BACKSTAGE_BACKEND=localhost:7007 && \
curl \
-H 'Accept: application/json' \
"${BACKSTAGE_BACKEND}/api/soundcheck/results?entityRef=component:default/petstore&checks=tests-run"
GET /api/soundcheck/results?entityRef=component:default/petstore&checks=tests-run HTTP/1.1
Host: localhost:7007
Accept: application/json
Responses
200 Response
See Check Results Schema.
Example Response Body
{
"results": [
{
"entityRef": "component:default/petstore",
"checkId": "tests-run",
"scope": "default",
"state": "failed",
"details": {
"notes": {
"type": "notes",
"version": 1,
"data": "Tests were not executed."
}
}
}
]
}
400 Response
Invalid or missing query parameter(s).
500 Response
Soundcheck encountered an unexpected condition that prevented it from fulfilling the request.
Example Response Body
{
"error": {
"name": "string",
"message": "string",
"stack": "string"
},
"request": {
"method": "string",
"url": "string"
},
"response": {
"statusCode": 0
}
}
Facts API
Use the Facts API to submit facts to Soundcheck.
Submitting Facts
Submit Facts to Soundcheck.
POST localhost:7007/api/soundcheck/facts
Request Body
See Facts Schema.
Example Request Body
{
"facts": [
{
"factRef": "catalog:default/petstore_metadata",
"entityRef": "component:default/petstore",
"data": {
"example": "petstore data"
},
"timestamp": "2023-02-06T19:33:48.590+00:00"
}
],
"cache": {
"duration": {
"hours": 24
}
}
}
Example Requests
BACKSTAGE_BACKEND=localhost:7007 && \
curl \
-H 'Content-Type: application/json' \
"${BACKSTAGE_BACKEND}/api/soundcheck/facts" \
--data @- << EOF
{
"facts": [
{
"factRef": "catalog:default/petstore_metadata",
"entityRef": "component:default/petstore",
"data": {
"example": "petstore data"
},
"timestamp": "2023-02-06T19:33:48.590+00:00"
}
],
"cache": {
"duration": {
"hours": 24
}
}
}
EOF
POST /api/soundcheck/results HTTP/1.1
Host: localhost:7007
Content-Type: application/json
Content-Length: 129
{
"facts": [
{
"factRef": "catalog:default/petstore_metadata",
"entityRef": "component:default/petstore",
"data": {
"example": "petstore data"
},
"timestamp": "2023-02-06T19:33:48.590+00:00"
}
],
"cache": {
"duration": {
"hours": 24
}
}
}
Responses
200 Response
Returns the factsRefs for the submitted facts that are either new or different from the existing facts in the cache.
Example Response Body
{
"factRefs": ["catalog:default/petstore_metadata"]
}
400 Response
Body did not match expected schema.
See Error Schema.
500 Response
Soundcheck encountered an unexpected condition that prevented it from fulfilling the request.q
Track API
Use the Track API to:
- List all tracks
- Get a track by ID
Each API call is discussed in detail below.
Get a List of Tracks
The endpoint to get a list of tracks is at /api/soundcheck/tracks
.
For a local deployment, the call would look like this:
GET localhost:7007/api/soundcheck/tracks
Query Parameters
tracks
Optional. Filters tracks to only those with the provided track ID(s). Accepts multiple values:tracks=A,tracks=B
.entityRef
Optional. A reference to the entity to retrieve applicable tracks for. When this query param is provided, only tracks (and checks) which are applicable to this entity are returned.onlyApplicableChecks
Optional. Used in conjunction with theentityRef
query params, determined whether all checks in a track are included in the response or only checks which are applicable to the given entity.
The response body has tracks
containing all tracks.
{
"tracks": [
...
]
}
Get a Track
The endpoint to get a track is at /api/soundcheck/tracks/:trackId
. Where :trackId
is the ID of the track you would
like to retrieve.
For a local deployment, the call would look like this:
GET localhost:7007/api/soundcheck/tracks/:trackId
Query Parameters
entityRef
Optional. A reference to the entity to validate applicability for. When this query param is provided, the requested track is only returned if it is applicable to the provided entity, otherwise{}
is returned.onlyApplicableChecks
Optional. Used in conjunction with theentityRef
query params, determined whether all checks in the track are included in the response or only checks which are applicable to the given entity.
The response body has track
containing the requested track.
{
"track": {
...
}
}
Aggregations API
Use the Aggregations API to get aggregations from Soundcheck.
Requesting Aggregations
Get an aggregation from Soundcheck
POST localhost:7007/api/soundcheck/aggregations
Request Body
See Aggregation Schema.
Example Aggregation Request Body
{
"type": "individualCheckPassRates",
"filter": {
"numberOfDays": 3,
"entityKinds": {
"included": ["Component"]
},
"entityTypes": {
"included": ["service"]
}
}
}
Example Aggregation Requests
BACKSTAGE_BACKEND=localhost:7007 && \
curl \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer {your authorization token}'\
"${BACKSTAGE_BACKEND}/api/soundcheck/aggregations" \
--data @- << EOF
{
"type": "individualCheckPassRates",
"filter": {
"numberOfDays": 3,
"entityKinds": {
"included": ["Component"]
},
"entityTypes": {
"included": ["service"]
}
}
}
EOF
Aggregation Responses
200 Response
Returns the requested Aggregation.
Example Aggregation Response Body
"individualCheckPassRates": [
{
"id": "alerting-configured",
"snapshotPassRate": 100,
"trendPassRates": [
0,
100,
100
],
"checkName": "Alerting is configured",
"checkDescription": "Components must have an on-call rotation identifier configured in component-info.yaml. This enables consumers of your component to ping an on-call goalie from Backstage in the event of an incident.\nThis check will NOT look to see what level of coverage your rotation provides; you may have a round-the-clock rotation, or a 10am-5pm local time rotation, whatever is most appropriate for your component.\n"
},
...
]
400 Response
If the input did not match the schema.
500 Response
Soundcheck encountered an unexpected condition that prevented it from fulfilling the request.q
Schemas
Check Results Schema
results
An array of check results.
Check Result Schema
entityRef
A reference to the entity that the check result is for.checkId
The unique identifier of the check that the result is for.state
The check results state. One ofpassed
,failed
,warning
, ornot-applicable
.scope
Optional. The scope within which this check was performed. Defaults todefault
.details
Optional. Additional details on the check result. Currently only supportsnotes
.notes
type
: Optional. Type of the check result details, currently only supportsnotes
. Defaults tonotes
.version
: Optional. Version of the check result details, can be any number. Defaults to1
.data
: Markdown providing additional context on the check result (e.g., why it failed).
Facts Schema
facts
An array of facts.cache
A cache config.
Fact Schema
factRef
A unique reference to the fact.entityRef
A reference to the entity this fact is collected against.data
The data collected of the fact's data schema.timestamp
The date/time at which this fact was collected.
Cache Config Schema
- A boolean
true
- Indicates that the fact should be cached forever.false
- Indicates that the fact should not be cached.
- Or an object containing a
duration
fieldduration
Specifies the cache duration. An object with one or more of the following:years
: Optional. The number of years.months
: Optional. The number of months.weeks
: Optional. The number of weeks.days
: Optional. The number of days.hours
: Optional. The number of hours.minutes
: Optional. The number of minutes;seconds
: Optional. The number of seconds.milliseconds
: Optional. The number of milliseconds.
Error Schema
error
name
Name of the error.message
Error message.stack
Stack trace.request
method
HTTP request method.url
URL
response
statusCode
HTTP status code.
Aggregation Schema
type
: The type of aggregation to perform, one of:individualCheckPassRates
overallCheckPassRates
individualEntitiesPassRates
overallEntityPassRates
individualTracksPassRates
overallTrackPassRates
groupsPassRates
filter
: An Aggregation_Filter to limit how the aggregation is calculated.
Aggregation Filter Schema
All fields are optional.
entityRefs
: an InclusionFilter containing those entity references to include/exclude from the aggregation.checkIds
: an InclusionFilter containing those identifiers of the checks to include/exclude from the aggregation.tracks
: an array of Aggregation Track Filters. Only check results from the specified tracks and levels will be included in the aggregation.scope
: Only results with the specified scope will be included in the aggregation.numberOfDays
: A numeric value indicating how many days of history to include in the aggregation.entityKinds
: an InclusionFilter containing the kinds of entities to include/exclude from the aggregation.entityLifecycles
: an InclusionFilter containing the lifecycles of entities to include/exclude from the aggregation.entityTypes
: an InclusionFilter containing the types of entities to include/exclude from the aggregation.checkOwnerFilters
: an InclusionFilter containing group references. Only the results of checks owned/not owned by the given owners will be included in the aggregation.entityOwnerFilters
: an InclusionFilter containing group references. Only entities owned/not owned by the given owners will be included in the aggregation.
Aggregation InclusionFilter Schema
included
: An optional string or array of strings.excluded
: An optional string or array of strings.
Aggregation Track Filter
trackId
: The name of the track. Required.levels
: An array of level ordinals. Optional.