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

    Projects

    Status
    Final Axim Review

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions