Skip to content

IpAddressString scalar should accept CIDR notation for PostgreSQL INET compatibility #77

@evoludigit

Description

@evoludigit

Context

FraiseQL provides tight Python/PostgreSQL integration. PostgreSQL has native INET and CIDR types that store IP addresses with optional prefix length (e.g., 192.168.1.1/24).

Problem

The IpAddressString scalar currently rejects CIDR notation:

# Current implementation in parse_ip_address_value()
return ip_address(value)  # ip_address() doesn't accept "192.168.1.1/24"

When GraphQL receives:

mutation {
  updateNetworkConfig(ipAddress: "192.168.1.1/24") { ... }
}

It fails with:

Variable '$ipAddress' got invalid value '192.168.1.1/24'; 
Invalid IP address string: '192.168.1.1/24'

PostgreSQL Context

When data is stored as PostgreSQL INET/CIDR:

CREATE TABLE network_config (
  ip_address_cidr INET  -- Stores "192.168.1.1/24"
);

Views can expose both representations:

CREATE VIEW v_network_config AS
SELECT
  host(ip_address_cidr) AS ip_address,    -- "192.168.1.1"
  netmask(ip_address_cidr) AS subnet_mask -- "255.255.255.0"
FROM network_config;

Proposed Solution

Make IpAddressString accept CIDR notation using ip_interface():

def parse_ip_address_value(value: Any) -> IPv4Address | IPv6Address:
    if isinstance(value, str):
        try:
            # Accept both "192.168.1.1" and "192.168.1.1/24"
            interface = ip_interface(value)
            return interface.ip  # Extract just the IP part
        except ValueError as e:
            msg = f"Invalid IP address string: {value!r}"
            raise GraphQLError(msg) from e

This maintains backward compatibility (plain IPs still work) while supporting CIDR input for PostgreSQL INET compatibility.

Use Case

Network configuration APIs commonly accept CIDR notation. Users can input:

  • 192.168.1.1/24 (CIDR) → parsed to IP + subnet
  • 192.168.1.1 (plain) → still works

This aligns with PostgreSQL's native INET type behavior and reduces API friction.

Files

  • Implementation: src/fraiseql/types/scalars/ip_address.py:50-59
  • Tests: tests/unit/core/type_system/test_ip_address_scalar.py

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions