0

Sorry for the neophyte question, but I'm getting my feet wet on REST APIs just now. I've been extremelly happy using the xsdata library to generate parsers for IEEE IPXACT 1685-2014 data. Now I want to use it to create Python bindings for the TeamCity REST API. My problem is actually finding the schema files for the data.

I've tried pulling the data from the /app/rest/builds endpoint in XML and JSON:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
    <builds count="100" href="/app/rest/builds" nextHref="/app/rest/builds?locator=count:100,start:100">
        <build id="2110255" buildTypeId="Software_..." number="31726" status="SUCCESS" state="finished" branchName="refs/heads/main" defaultBranch="true" href="/app/rest/builds/id:2110255" webUrl="https://teamcity.example.com/buildConfiguration/Software_.../2110255">
            ...
        </build>
    </builds>
{
    "count":100,
    "href":"/app/rest/builds",
    "nextHref":"/app/rest/builds?locator=count:100,
    start:100",
    "build":[
        {
            "id":2109979,
            "buildTypeId":"Software_...",
            "number":"557",
            "status":"SUCCESS",
            "state":"finished",
            "branchName":"refs/heads/main",
            "defaultBranch":true,
            "href":"/app/rest/builds/id:2109979",
            "webUrl":"https://teamcity.example.com/buildConfiguration/Software_.../2109979",
            "finishOnAgentDate":"20250522T154005-0400"
        },
        ...
    ]
}

There's no schema reference in either format. I'm hoping to not have to copy the "schema" of every single item I need:

{
  "build" : [ {
    "agent" : "agent...",
    "metadata" : "datas...",
    "triggered" : "TriggeredBy...",
    "usedByOtherBuilds" : true,
    "settingsHash" : "settingsHash",
    "number" : "54",

    ...

    "properties" : "properties...",
    "statistics" : "properties..."
  } ],
  "count" : 12,
  "prevHref" : "/app/rest/builds?locator=count:50,start:0,state:finished",
  "href" : "/app/rest/builds?locator=buildType:Project_Config&fields=count,href",
  "nextHref" : "/app/rest/builds?locator=count:200,start:250,state:finished"
}

That's not an schema, it's an example.

I tried using the Swagger endpoing (dully marked as deprecated) from teamcity-rest-api

curl --header "Authorization: Bearer <token>" --header "Accept: application/json" https://teamcity.example.com/app/rest/swagger.json -o teamcity.json

Which gave me this data:

{
    "swagger":"2.0",
    "info": {
        "version":"2018.1 (current)",
        "title":"TeamCity REST API"},
        "host":"teamcity.example.com",
        "tags":[
            {"name":"Agent"},
            {"name":"AgentPool"},
            {"name":"AgentType"},
            ...

I then pointed xsdata to it:

xsdata generate --package lib.xsdata_generated ./teamcity.json

Cool! I took a peek at the generated bindings:

@dataclass
class AppRestBuilds:
    class Meta:
        name = "/app/rest/builds"

    get: Optional[Get] = field(
        default=None,
        metadata={
            "type": "Element",
            "required": True,
        },
    )

I created a very trivial script:

from lib.xsdata_generated.xsdata_generated import AppRestBuilds
from xsdata.formats.dataclass.parsers import JsonParser

parser = JsonParser()
order = parser.parse("builds.json", AppRestBuilds)
print(order)

Which immediatelly fails with a xsdata.exceptions.ParserError: Unknown property AppRestBuilds.count error. Looking at the Swagger file:

    "/app/rest/builds": {
      "get": {
        "tags": ["Build"],
        "summary": "Get all builds.",
        "description": "",
        "operationId": "getAllBuilds",
        "produces": ["application/xml", "application/json"],
        "parameters": [
          {
            "name": "locator",
            "in": "query",
            "required": false,
            "type": "string",
            "format": "BuildLocator"
          },
          {
            "name": "fields",
            "in": "query",
            "required": false,
            "type": "string"
          }
        ],
        "responses": {
          "200": {
            "description": "successful operation",
            "examples": { "application/xml": "", "application/json": "" },
            "schema": { "$ref": "#/definitions/builds" }
          }
        }
      }
    }

And

    "builds": {
      "type": "object",
      "properties": {
        "count": {
          "type": "integer",
          "format": "int32",
          "example": 12,
          "xml": { "attribute": true },
          "description": "The current number of Build objects in this list.",
          "x-defined-in-base": true
        },
        "href": {
          "type": "string",
          "example": "/app/rest/builds?locator=buildType:Project_Config&fields=count,href",
          "xml": { "attribute": true },
          "description": "The relative link (without the server URL) used to retrieve this object.",
          "x-defined-in-base": true
        },
        "nextHref": {
          "type": "string",
          "example": "/app/rest/builds?locator=count:200,start:250,state:finished",
          "xml": { "attribute": true },
          "description": "If the list of returned entities exceeds the request `count` value, TeamCity splits it into multiple batches. This property returns the endpoint that allows you to obtain the next batch.",
          "x-defined-in-base": true
        },
        "prevHref": {
          "type": "string",
          "example": "/app/rest/builds?locator=count:50,start:0,state:finished",
          "xml": { "attribute": true },
          "description": "If the list of returned entities exceeds the request `count` value, TeamCity splits it into multiple batches. This property returns the endpoint that allows you to obtain the previous batch.",
          "x-defined-in-base": true
        },
        "build": {
          "type": "array",
          "description": "The list of builds owned by this collection that satisfy the given locator.",
          "items": {
            "xml": { "name": "build" },
            "$ref": "#/definitions/build"
          },
          "x-is-first-container-var": true
        }
      },
      "xml": { "name": "builds" },
      "description": "Represents a paginated list of Build entities.",
      "x-object-type": "PaginatedEntity",
      "x-subpackage": ".build.",
      "x-is-data": true,
      "x-is-list": true,
      "x-is-paginated": true,
      "x-base-entity": "Build"
    },

So, count is clearly there. I don't know if I should be using some particular command-line option, or if xsdata simply doesn't like the schema (I think that's unlikely). I created a xsdata issue about this, but I though I could ask on SO if someone has any pointers or knows how I can get a different schema file/URL I could try using.

Thanks!!

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.