netbox icon indicating copy to clipboard operation
netbox copied to clipboard

ModuleBay API GET - Missing Properties

Open Jirennor opened this issue 3 weeks ago • 3 comments

NetBox Edition

NetBox Community

NetBox Version

v4.4.7

Python Version

3.10

Steps to Reproduce

  1. Create a new device type.
  2. Create a new module type.
  3. Create a new device.
  4. Add a Module Bays component to the device.
  5. Install a module in the created module bay.
  6. API GET: /api/dcim/module-bays/?device_id=<device_id>

Expected Behavior

Assuming the API spec is correct I would expect that the installed_module property contains a reference to the device and module_bay.

Observed Behavior

The installed_module property does not contain any device or module_bay references. In my case I use the Golang client (which is generated based on the API spec) that validates the returned API result and errors out because no value was given for the required properties device and module_bay.

I also think the same applies to the module property but I don't have a use-case where this value is set so I can't test it.

{
    "count": 1,
    "next": null,
    "previous": null,
    "results": [
        {
            "id": 2913,
            "url": "http://localhost:8585/api/dcim/module-bays/2913/",
            "display_url": "http://localhost:8585/dcim/module-bays/2913/",
            "display": "bay0",
            "device": {
                "id": 5645,
                "url": "http://localhost:8585/api/dcim/devices/5645/",
                "display": "Something-101",
                "name": "Something-101",
                "description": ""
            },
            "module": null,
            "name": "bay0",
            "installed_module": {
                "id": 291,
                "url": "http://localhost:8585/api/dcim/modules/291/",
                "display": "bay0: SomeModule01 (291)",
                "serial": "",
                "description": ""
            },
            "label": "",
            "position": "",
            "description": "",
            "tags": [],
            "custom_fields": {},
            "created": "2025-12-08T16:45:10.445185Z",
            "last_updated": "2025-12-08T16:45:10.445200Z"
        }
    ]
}

Jirennor avatar Dec 08 '25 17:12 Jirennor

I'm working on OpenApi generator for Crystal Lang (a typed compiled language, like Go).

Here an example of what's wrong with the current behavior :

From Netbox API schema (4.2.7) :

BriefPlatform:
  type: object
  description: Adds support for custom fields and tags.
  properties:
    id:
      type: integer
      readOnly: true
    url:
      type: string
      format: uri
      readOnly: true
    display:
      type: string
      readOnly: true
    name:
      type: string
      title: Nom
      maxLength: 100
    slug:
      type: string
      maxLength: 100
      pattern: ^[-a-zA-Z0-9_]+$
    description:
      type: string
      maxLength: 200
    device_count:
      type: integer
      format: int64
      readOnly: true
    virtualmachine_count:
      type: integer
      format: int64
      readOnly: true
  required:
  - device_count
  - display
  - id
  - name
  - slug
  - url
  - virtualmachine_count

Here, because device_count and virtualmachine_count are required, the OpenApi generator generate this kind of code :

module NetboxClient
  # Adds support for custom fields and tags.
  class BriefPlatform
    include JSON::Serializable
    include YAML::Serializable

    # Required properties
    @[JSON::Field(key: "id", type: Int32, nillable: false, emit_null: false)]
    property id : Int32

    @[JSON::Field(key: "url", type: String, nillable: false, emit_null: false)]
    property url : String

    @[JSON::Field(key: "display", type: String, nillable: false, emit_null: false)]
    property display : String

    @[JSON::Field(key: "name", type: String, nillable: false, emit_null: false)]
    property name : String

    @[JSON::Field(key: "slug", type: String, nillable: false, emit_null: false)]
    property slug : String

    @[JSON::Field(key: "device_count", type: Int64, nillable: false, emit_null: false)] # <= nillable: false
    property device_count : Int64

    @[JSON::Field(key: "virtualmachine_count", type: Int64, nillable: false, emit_null: false)] # <= nillable: false
    property virtualmachine_count : Int64

But because device_count and virtualmachine_count are missing from the server response I'm forced to patch the generated code to make it works :

https://github.com/jbox-web/netbox-extractor/blob/b5b989f3be49ca32adfd6234d350eb2c8d0b1753/vendor/netbox-client.4.2.7.diff#L96-L115

Here I change the type declaration to allow nil values (nillable: true and Int64? == Int64 | Nil

I understand that from your point view everything is good. I'm fine with that.

On the top of that device_count and virtualmachine_count are readOnly fields, so it should not be an issue.

    device_count:
      type: integer
      format: int64
      readOnly: true
    virtualmachine_count:
      type: integer
      format: int64
      readOnly: true

The thing is : in compiled language like Crystal or Go you can't declare a field as required and not having it in the response.

The project may compile but will fail at runtime with ugly errors :

Unhandled exception: Missing JSON attribute: device_count
  parsing NetboxClient::BriefDeviceType at line 1, column 313
  parsing NetboxClient::DeviceWithConfigContext#device_type at line 1, column 299
  parsing NetboxClient::PaginatedDeviceWithConfigContextList#results at line 1, column 103 (JSON::SerializableError)

To workaround this I would suggest to add a default field like for some other objects like : https://github.com/jbox-web/netbox-extractor/blob/master/vendor/netbox-client.4.2.7/src/netbox-client/models/brief_wireless_lan_group.cr#L38

    BriefWirelessLANGroup:
      type: object
      description: Extends PrimaryModelSerializer to include MPTT support.
      properties:
        id:
          type: integer
          readOnly: true
        url:
          type: string
          format: uri
          readOnly: true
        display:
          type: string
          readOnly: true
        name:
          type: string
          title: Nom
          maxLength: 100
        slug:
          type: string
          maxLength: 100
          pattern: ^[-a-zA-Z0-9_]+$
        description:
          type: string
          maxLength: 200
        wirelesslan_count:
          type: integer
          readOnly: true
          default: 0 # <= default value, it works
        _depth:
          type: integer
          readOnly: true
          title: ' depth'
      required:
      - _depth
      - display
      - id
      - name
      - slug
      - url
      - wirelesslan_count # <= required

n-rodriguez avatar Dec 09 '25 16:12 n-rodriguez

Ok, actually my issue is fixed on master :

4.2.7 => https://github.com/netbox-community/netbox/blob/v4.2.7/netbox/dcim/api/serializers_/platforms.py master => https://github.com/netbox-community/netbox/blob/main/netbox/dcim/api/serializers_/platforms.py

Sorry for the noise 🤦

n-rodriguez avatar Dec 09 '25 16:12 n-rodriguez

@Jirennor What kind of properties are you expecting here? Can you please provide the brief details about that?

kprince28 avatar Dec 15 '25 19:12 kprince28

@kprince28 There is currently a discrepancy between the actual implementation of the API endpoint and the API specification. I am not sure which one is correct. If the API specification is correct, then I would expect the installed_module property to contain the device and module_bay properties. If the current implementation is correct, then I would expect that the API specification is updated and reflects the current implementation of the API endpoint.

Jirennor avatar Dec 16 '25 10:12 Jirennor

@arthanson Could you assign this to me?

kprince28 avatar Dec 16 '25 10:12 kprince28

@kprince28 There is currently a discrepancy between the actual implementation of the API endpoint and the API specification. I am not sure which one is correct. If the API specification is correct, then I would expect the installed_module property to contain the device and module_bay properties. If the current implementation is correct, then I would expect that the API specification is updated and reflects the current implementation of the API endpoint.

yes, I can see the difference and also it is happening same with the module as well, so module also missing the properties of the device and module_bay according to the API Specification

kprince28 avatar Dec 16 '25 10:12 kprince28