ModuleBay API GET - Missing Properties #11909

Closed
opened 2025-12-29 21:51:24 +01:00 by adam · 6 comments
Owner

Originally created by @Jirennor on GitHub (Dec 8, 2025).

Originally assigned to: @kprince28 on GitHub.

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"
        }
    ]
}
Originally created by @Jirennor on GitHub (Dec 8, 2025). Originally assigned to: @kprince28 on GitHub. ### 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](https://github.com/netbox-community/go-netbox) (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" } ] } ```
adam added the type: bugstatus: acceptednetboxseverity: low labels 2025-12-29 21:51:24 +01:00
adam closed this issue 2025-12-29 21:51:25 +01:00
Author
Owner

@n-rodriguez commented on GitHub (Dec 9, 2025):

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 :

b5b989f3be/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 commented on GitHub (Dec 9, 2025): 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) : ```yml 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 : ```crystal 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. ```yml 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 : ```sh 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 ```yml 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 ```
Author
Owner

@n-rodriguez commented on GitHub (Dec 9, 2025):

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 commented on GitHub (Dec 9, 2025): 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 🤦
Author
Owner

@kprince28 commented on GitHub (Dec 15, 2025):

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

@kprince28 commented on GitHub (Dec 15, 2025): @Jirennor What kind of properties are you expecting here? Can you please provide the brief details about that?
Author
Owner

@Jirennor commented on GitHub (Dec 16, 2025):

@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 commented on GitHub (Dec 16, 2025): @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.
Author
Owner

@kprince28 commented on GitHub (Dec 16, 2025):

@arthanson Could you assign this to me?

@kprince28 commented on GitHub (Dec 16, 2025): @arthanson Could you assign this to me?
Author
Owner

@kprince28 commented on GitHub (Dec 16, 2025):

@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 commented on GitHub (Dec 16, 2025): > [@kprince28](https://github.com/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
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/netbox#11909