DEV Community

Cover image for ๐Ÿ”Ž Exploring Teamcity API (with Examples!)
Lorna Watson
Lorna Watson

Posted on • Edited on

๐Ÿ”Ž Exploring Teamcity API (with Examples!)

I've been working on a side project 'DevOps API Tool' where I am essentially combining Bitbucket API, Octopus Deploy API and Teamcity API to get the most useful and common 'things' out of it into a simplified couple of webpages. As well as a number of reasons including having more knowledge about their processes, but also to get rid of the noise. I found it super fun and quick to get started using Postman to test the APIs to get all sorts of wonderful data from basic info about a project to detailed test results and so on... The backend project is using Node.js but this post is not specific to that but more an intended general reference guide for using the Teamcity API, I hope you find this useful. โœจ

โ„น For more info visit Teamcity REST API documentation. โ„น

Useful bits ๐Ÿ˜Ž

  • Authenticate your request via bearer token in the header
  • Locators - filter string in URL (more info in the link above ^)
  • Response format - set in the HTTP Accept header for either plain text, JSON or XML. The default format is XML
  • By default the max. list amount response will be 100

$long โญโญโญโญโญ

This is extremely useful to know and it essentially returns all fields from a chosen resource. The official documentation recommends not to use $long for actual requests but more of a check to see what fields you might need.

For example, let's say I want to get a specific build:

My go-to default is a request URL like this:
GET http://teamcity:8111/app/rest/builds/id:308

But now I want to see only the test info from this build, so my first step would be to check for all fields to see what I needed like so:
GET http://teamcity:8111/app/rest/builds?locator=id:308&fields=build($long)

From the response I was able to manually refine down the fields I needed and adjusted the URL:
http://teamcity:8111/app/rest/builds?locator=id:308&fields=build(testOccurrences(count,passed,ignored)) and this response would look like this:

{
    "build": [
        {
            "testOccurrences": {
                "count": 201,
                "passed": 199,
                "ignored": 2
            }
        }
    ]
}
Enter fullscreen mode Exit fullscreen mode

Interestingly... The response is different between /app/rest/builds/id:308 and /app/rest/builds/locator=id:308 where the 1st has more detail. I'm going to look into this more. ๐Ÿค“

Example Requests

Presenting a selection of useful requests - not every single one, and please note for readability purposes (and less page noise) I've reduced some of the responses but tried including the 'main' bits if that makes sense! The following examples assumes the base URL is http://teamcity:8111/app/rest for simplicity.

Builds ๐Ÿ”จ

Get build

GET http://teamcity:8111/app/rest/builds?locator=id:308&fields=count,build(id,buildTypeId,number,status,state,branchName,webUrl)

{
    "count": 1,
    "build": [
        {
            "id": 308,
            "buildTypeId": "projectA_Release",
            "number": "7.5.0.6352",
            "status": "SUCCESS",
            "state": "finished",
            "branchName": "branchA",
            "webUrl": "http://teamcity:8111/viewLog.html?buildId=308&buildTypeId=projectA_Release"
        }
    ]
}
Enter fullscreen mode Exit fullscreen mode

Get build related issues

GET http://teamcity:8111/app/rest/builds/id:308/relatedIssues

{
    "href": "/app/rest/builds/id:308/relatedIssues",
    "issueUsage": [
        {
            "changes": {
                "change": [
                    {
                        "id": 26019,
                        "version": "b300f534a2733530c623d41ddcf59690053e580d",
                        "username": "lorna.watson",
                        "date": "20210210T142232+0000",
                        "href": "/app/rest/changes/id:26019",
                        "webUrl": "http://teamcity:8111/viewModification.html?modId=26019&personal=false"
                    }
                ],
                "count": 1
            },
            "issue": {
                "url": "http://jira:8111/browse/feature-98",
                "id": "feature-98"
            }
        }
    ],
    "count": 1
}
Enter fullscreen mode Exit fullscreen mode

Get build queue

GET http://teamcity:8111/app/rest/buildQueue

{
    "count": 0,
    "href": "/app/rest/buildQueue",
    "build": []
}
Enter fullscreen mode Exit fullscreen mode

Get build types

GET http://teamcity:8111/app/rest/buildTypes?locator=affectedProject:(id:projectA)&fields=buildType(id,name,projectName,projectId,webUrl,steps(count))

{
    "buildType": [
        {
            "id": "projectA_Release",
            "name": "Project A Release",
            "projectName": "Project A",
            "projectId": "projectA",
            "webUrl": "http://teamcity:8111/viewType.html?buildTypeId=projectA_Release",
            "steps": {
                "count": 6
            }
        }
}
Enter fullscreen mode Exit fullscreen mode

Get list of build types in a project with the status of the last finished build for each build configuration

GET http://teamcity:8111/app/rest/buildTypes?locator=affectedProject:(id:projectA)&fields=buildType(id,name,builds($locator(running:false,count:1),build(number,status,statusText,finishDate)))

{
    "buildType": [   
        {
            "id": "projectA_Release",
            "name": "Project A Release",
            "builds": {
                "build": [
                    {
                        "number": "35",
                        "status": "FAILURE",
                        "statusText": "Tests passed: 199, ignored: 2; unable to create or deploy release. Please check the build log for details on the error. (new)",
                        "finishDate": "20210209T102244+0000"
                    }
                ]
            }
        }
    ]
}
Enter fullscreen mode Exit fullscreen mode

Changes ๐ŸŽŽ

Get the list of all changes included into the build

GET http://teamcity:8111/app/rest/changes?locator=build:(id:buildId)

{
    "change": [
        {
            "id": 26,
            "username": "lorna.watson",
            "date": "20210210T142232+0000",
            "webUrl": "http://teamcity:8111/viewModification.html?modId=260191&personal=false"
        },
        {
            "id": 27,
            "username": "lorna.watson",
            "date": "20210210T142219+0000",
            "webUrl": "http://teamcity:8111/viewModification.html?modId=260190&personal=false"
        }
    ],
    "count": 2
}
Enter fullscreen mode Exit fullscreen mode

Get details of an individual change

GET http://teamcity:8111/app/rest/changes/id:changeId

{
    "id": 26, 
    "username": "lorna.watson",
    "date": "20210210T142232+0000",
    "webUrl": "http://teamcity:8111/viewModification.html?modId=260191&personal=false",
    "comment": "Merge branch into master",
    "user": {
        "username": "hello@lorna.dev",
        "name": "Lorna Watson",
        "id": 1,
    },
    "files": {
        "count": 0,
        "file": []
    }
}
Enter fullscreen mode Exit fullscreen mode

Get all changes for a project

GET http://teamcity:8111/app/rest/changes?locator=project:projectA&fields=change(id,username,date,webUrl)

{
    "change": [
        {
            "id": 27,
            "username": "lorna.watson",
            "date": "20210225T142606+0000",
            "webUrl": "http://teamcity:8111/viewModification.html?modId=270391&personal=false"
        },
        {
            "id": 28,
            "username": "bill.smith",
            "date": "20210225T135430+0000",
            "webUrl": "http://teamcity:8111/viewModification.html?modId=270344&personal=false"
        },
        {
            "id": 29,
            "username": "bill.smith",
            "date": "20210225T120351+0000",
            "webUrl": "http://teamcity:8111/viewModification.html?modId=270343&personal=false"
        }
    ],
    "count": 3
}
Enter fullscreen mode Exit fullscreen mode

Projects ๐Ÿงพ

Get list of projects

GET http://teamcity:8111/app/rest/projects

{
    "count": 2,
    "href": "/app/rest/projects",
    "project": [
        {
            "id": "_Root",
            "name": "<Root project>",
            "description": "Contains all other projects",
            "href": "/app/rest/projects/id:_Root",
            "webUrl": "http://teamcity:8111/project.html?projectId=_Root"
        },
        {
            "id": "projectA",
            "name": "Project A",
            "parentProjectId": "_Root",
            "href": "/app/rest/projects/id:projectA",
            "webUrl": "http://teamcity:8111/project.html?projectId=projectA"
        }
    ]
}
Enter fullscreen mode Exit fullscreen mode

Servers โš™

Get server version

GET http://teamcity:8111/app/rest/version

85899
Enter fullscreen mode Exit fullscreen mode

Agents ๐Ÿš”

Get list of agents

GET http://teamcity:8111/app/rest/agents

Get agent details

GET http://teamcity:8111/app/rest/agents/id:5109

Summary

You can really do so much with the well-documented Teamcity API and whilst I've touched base on some parts i.e. project and build requests, you can explore other areas such as: investigations, branches, problems, users, agents and so on. Please see the link at the top of this post for more details. I need to play around more with locators but so far really loving the filtering! I've tried to keep the detail to minimum but also informative, didn't want to blag the whole page with JSON responses ๐Ÿ˜…. I hope this has been useful and clear to follow, thanks!! ๐Ÿ˜‡

Top comments (3)

Collapse
 
whbruce profile image
Henry Bruce

Nice work, very helpful.

Collapse
 
dhaggerfin profile image
David

This was super helpful, especially the part about $long - thank you!

Collapse
 
lornasw93 profile image
Lorna Watson

No worries, glad it was helpful! $long is a game changer