Skip to content

[BE] Update Get endpoint to return Taxonomy Type. #618

Description

@mgwozdz-unicon

Use Case

As a Platform Administrator, I want the taxonomy retrieval API to report each taxonomy's type ("tags" or "competency"), so that the Taxonomies page can support displaying a badge for Competency Taxonomies and correctly gate access to the Competency Management page.

Description

Current behavior

  1. GET /api/tagging/v1/taxonomies/{id}/ and GET /api/tagging/v1/taxonomies/ (TaxonomySerializer, src/openedx_tagging/rest_api/v1/serializers.py) return taxonomy fields including system_defined, but nothing identifies whether a taxonomy is a Competency Taxonomy.

Requested change

  1. Add a read-only taxonomy_type field to TaxonomySerializer, returned on both the single-taxonomy and list GET endpoints.
  2. Value is "competency" for Competency Taxonomies (the model introduced by [BE] Update taxonomy Create & Import endpoints to accept Taxonomy Type #614 and its data-model dependency) and "tags" for every other taxonomy, including all system_defined taxonomies. Never null.
  3. The two values are exactly what the Create/Import endpoint's taxonomy_type field ([BE] Update taxonomy Create & Import endpoints to accept Taxonomy Type #614) accepts, and both draw from one shared TaxonomyType enum so they cannot drift apart.

Depends on: #614 (Create/Import endpoint) merging first, since the CompetencyTaxonomy model this ticket detects doesn't exist until then.

Explicitly out of scope

  • No "competency only" / "non-competency only" filter or query parameter on Get/List. The list endpoint keeps returning all taxonomy types together, undifferentiated.
  • No change to content-tagging surfaces (Course Outline, Libraries). Tagging content with a Competency Taxonomy without linking Competency Criteria must stay possible; this ticket adds no restriction there.
  • No change to the existing system-level taxonomy indication.

Acceptance Criteria

These scenarios are verifiable via Postman.

Scenario: Get a single Competency Taxonomy
  Given a Competency Taxonomy exists (created via the #614 Create endpoint with taxonomy_type="competency")
  When a client sends GET /api/tagging/v1/taxonomies/{id}/ for that taxonomy
  Then the response has status code 200
  And the response body's "taxonomy_type" field equals "competency"

Scenario: Get a single standard tag taxonomy
  Given a standard (non-competency) taxonomy exists
  When a client sends GET /api/tagging/v1/taxonomies/{id}/ for that taxonomy
  Then the response has status code 200
  And the response body's "taxonomy_type" field equals "tags"
  And the field is never null

Scenario: Get a system-defined taxonomy
  Given a system-defined taxonomy exists (e.g. the built-in Language taxonomy, system_defined=true)
  When a client sends GET /api/tagging/v1/taxonomies/{id}/ for that taxonomy
  Then the response has status code 200
  And the response body's "taxonomy_type" field equals "tags"
  And "system_defined" is unchanged and still equals true

Scenario: List taxonomies of mixed type
  Given at least one Competency Taxonomy and at least one standard taxonomy exist
  When a client sends GET /api/tagging/v1/taxonomies/
  Then every Competency Taxonomy entry has "taxonomy_type" equal to "competency"
  And every other entry has "taxonomy_type" equal to "tags"
  And no entry's "taxonomy_type" is null
  And entries of both types are returned together, unfiltered

Technical Details

Files to create and modify

Modified files

File Nature of modification
src/openedx_tagging/models/base.py Add TaxonomyType(models.TextChoices); add Taxonomy.get_type() returning TaxonomyType.TAGS
src/openedx_tagging/rest_api/v1/serializers.py Add taxonomy_type SerializerMethodField to TaxonomySerializer; add to Meta.fields
src/openedx_tagging/rest_api/v1/tests/test_views.py (confirm exact path) Add coverage for base, system-defined, and overridden get_type() across detail + list

Recommended Approach

Add an overridable model method rather than probing for the CBE applet's model by name — mirroring the already-shipped system_defined pattern (Taxonomy.system_defined base property, overridden by SystemDefinedTaxonomy in src/openedx_tagging/models/system_defined.py:29-35). It’s also the pattern #614's implementer will already be reading when they subclass Taxonomy for CompetencyTaxonomy.

# src/openedx_tagging/models/base.py, above the Taxonomy model

class TaxonomyType(models.TextChoices):
    TAGS = "tags"
    COMPETENCY = "competency"


class Taxonomy(...):
    ...
    def get_type(self) -> str:
        """
        Returns this taxonomy's type as one of the TaxonomyType values.

        The base Taxonomy always returns TaxonomyType.TAGS. Subclasses (for
        example, a future CBE applet's CompetencyTaxonomy) override this to
        report their own type. openedx_tagging has no knowledge of what
        subclasses exist or what they override this to.
        """
        return TaxonomyType.TAGS

TaxonomySerializer.get_taxonomy_type() calls instance.get_type() on the already-.cast()ed instance (the serializer already casts before running field getters — reuse that seam, don't duplicate it).

Layering: openedx_tagging never references CompetencyTaxonomy or the competencytaxonomy relation name anywhere in its source. The default get_type() is an unconditional constant; only a class defined and owned outside this package can ever make it return something else.

Example Resolution Prompt

In openedx-core, add a taxonomy_type read-only field to the taxonomy Get endpoints. In src/openedx_tagging/models/base.py, add TaxonomyType(models.TextChoices) with TAGS = "tags" and COMPETENCY = "competency", placed above the Taxonomy class, and add a Taxonomy.get_type() method returning TaxonomyType.TAGS unconditionally — this mirrors the existing system_defined base/override pattern (system_defined.py:29-35) and must not reference CompetencyTaxonomy or the competencytaxonomy relation name anywhere. In src/openedx_tagging/rest_api/v1/serializers.py, add taxonomy_type = serializers.SerializerMethodField() to TaxonomySerializer, with get_taxonomy_type(self, obj) returning obj.get_type() (call this after the serializer's existing .cast() step), and add "taxonomy_type" to Meta.fields. Add test cases covering a base Taxonomy"tags", a SystemDefinedTaxonomy"tags", and a test-only Taxonomy subclass overriding get_type() → confirms polymorphism flows through both the detail and list endpoints. Import TaxonomyType from models/base.py for both this serializer field and #614's write-side ChoiceField, so the two can never drift.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    Status
    Final Axim Review

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions