Skip to content

[BE] Update taxonomy Create & Import endpoints to accept Taxonomy Type #614

Description

@mgwozdz-unicon

Use Case

As a Platform Administrator, I need the taxonomy Create and Import endpoints to accept a Taxonomy Type field so that I can indicate when a taxonomy should be treated as a Competency Taxonomy rather than a standard tag taxonomy.


Description

This issue updates the REST Create endpoint and REST Import action in openedx-core to accept an optional taxonomy_type field. The field accepts two values: "competency" (triggers creation of a CompetencyTaxonomy record alongside the base Taxonomy in a single transaction) and "tags" (creates a plain Taxonomy; also the default when the field is omitted). Unsupported values, including "system", must be rejected with a 400 — system taxonomies are created programmatically and must not be user-creatable via these endpoints.

Taxonomy type is a derived property of the model structure — a competency taxonomy has a CompetencyTaxonomy MTI child row, a system taxonomy has system_defined = True, and a tag taxonomy is neither. No new type column is added to the schema.

Architecture constraint: openedx_tagging is a standalone library with no dependencies on other openedx-core packages. It must not import or instantiate CompetencyTaxonomy. The creation of a CompetencyTaxonomy row belongs in the CBE applet (openedx_learning/applets/cbe/), which depends on openedx_tagging — not the other way around. This ticket updates the openedx_tagging serializer and view layer to accept and surface taxonomy_type, but the dispatching of competency-specific creation logic is handled at a higher layer. The specific mechanism (view override, mixin, or extension point in the CBE applet) is an implementation decision for the developer.

Endpoints in scope:

  • POST /api/tagging/v1/taxonomies/ — the direct Create endpoint in openedx-core
  • POST /api/content_tagging/v1/taxonomies/import/ — the Studio import endpoint in openedx-platform, whose create_import() action inherits from TaxonomyView in openedx-core. Most of the work is in the parent class; the openedx-platform layer needs verification that taxonomy_type flows through the super() call correctly.

Out of scope:


Acceptance Criteria

These scenarios are verifiable via Postman against a local or dev environment.

Scenario 1: Creating a Competency Taxonomy

Given a POST request to /api/content_tagging/v1/taxonomies/
And the request body includes taxonomy_type set to "competency"
When the endpoint processes the request
Then the response returns 201
And a CompetencyTaxonomy record is created linked to the new Taxonomy

Scenario 2: Creating a taxonomy with taxonomy_type set to "tags"

Given a POST request to /api/content_tagging/v1/taxonomies/
And the request body includes taxonomy_type set to "tags"
When the endpoint processes the request
Then the response returns 201
And no CompetencyTaxonomy record is created

Scenario 3: Creating a taxonomy without a taxonomy_type (default)

Given a POST request to /api/content_tagging/v1/taxonomies/
And the request body does not include a taxonomy_type field
When the endpoint processes the request
Then the response returns 201
And the behavior is identical to Scenario 2

Scenario 4: Rejected taxonomy_type values

Given a POST request to /api/content_tagging/v1/taxonomies/
And the request body includes taxonomy_type set to "system" or any unsupported value
When the endpoint processes the request
Then the response returns 400
And the validation error identifies taxonomy_type as the invalid field

Scenario 5: Importing a Competency Taxonomy

Given a multipart POST request to /api/content_tagging/v1/taxonomies/import/
And the request includes a valid taxonomy file and taxonomy_type set to "competency"
When the endpoint processes the request
Then the import completes successfully
And a CompetencyTaxonomy record is created linked to the new Taxonomy

Scenario 6: Importing without a taxonomy_type (default)

Given a multipart POST request to /api/content_tagging/v1/taxonomies/import/
And the request does not include a taxonomy_type field
When the endpoint processes the request
Then the import completes successfully
And no CompetencyTaxonomy record is created

Scenario 7: Rejected taxonomy_type on import

Given a multipart POST request to /api/content_tagging/v1/taxonomies/import/
And the request includes taxonomy_type set to "system" or any unsupported value
When the endpoint processes the request
Then the response returns 400
And the validation error identifies taxonomy_type as the invalid field

Technical Notes

Files to Create

The CBE applet will need a create_competency_taxonomy() function. If openedx_learning/applets/cbe/api.py does not already exist (from the data model ticket), it should be created here.

Modified Files

openedx-core

File Nature of modification
src/openedx_tagging/rest_api/v1/serializers.py Add taxonomy_type as a write-only ChoiceField
src/openedx_tagging/rest_api/v1/views.py Update perform_create() and create_import() to surface taxonomy_type for use by higher layers
openedx_learning/applets/cbe/api.py Add create_competency_taxonomy() — wraps create_taxonomy() and creates the CompetencyTaxonomy row in a single transaction.atomic()

openedx-platform

File Nature of modification
openedx/core/djangoapps/content_tagging/rest_api/v1/views.py Verify TaxonomyOrgView.create_import() (lines 109–133) passes taxonomy_type through the super() call; patch if it does not

Implementation Notes

  • Layering constraint. openedx_tagging/api.py::create_taxonomy() creates only a plain Taxonomy. It must not import or call anything from openedx_learning. The CompetencyTaxonomy creation belongs exclusively in the CBE applet.

  • create_competency_taxonomy() in the CBE applet. This function calls create_taxonomy() then creates a linked CompetencyTaxonomy row, wrapped in transaction.atomic(). It is the only place that knows about both layers.

  • Routing in the REST layer. The openedx_tagging view accepts taxonomy_type from validated data and makes it available, but the dispatch to create_competency_taxonomy() happens at a layer that can see both openedx_tagging and the CBE applet. The specific mechanism (a CBE-provided view mixin that overrides perform_create(), or an extension point) is an implementation decision — choose the approach that best fits the existing extension patterns in this codebase.

  • Validation in the serializer. Add taxonomy_type as a ChoiceField with required=False, write_only=True, and choices=["tags", "competency"]. Omitting the field is equivalent to "tags". "system" is intentionally absent, producing a standard DRF 400 if attempted.

  • Coordination with [BE] Update Get endpoint to return Taxonomy Type. #618 (GET responses). This ticket owns the write side of taxonomy_type: a write_only=True ChoiceField on openedx_tagging's serializer. Issue [BE] Update Get endpoint to return Taxonomy Type. #618 owns the read side, implemented separately in openedx-platform's TaxonomyOrgSerializer per ADR 0013 (docs/openedx_tagging/decisions/0013-competency-taxonomy-detection.rst) — a different serializer in a different repo, not a second field on this one. The two don't share code or constants: [BE] Update Get endpoint to return Taxonomy Type. #618 derives its value directly from the CompetencyTaxonomy relation rather than reading anything this ticket writes.

  • create_import() action. Locate this action in TaxonomyView in views.py and apply the same taxonomy_type handling as perform_create(). The openedx-platform TaxonomyOrgView.create_import() calls super().create_import(), so if the parent handles taxonomy_type, the platform layer likely requires no code changes — only verification that the field is not stripped before the super() call.

Example Resolution Prompt

Across openedx-core and openedx-platform, add taxonomy_type support to taxonomy creation and import. In openedx-core/src/openedx_tagging/rest_api/v1/serializers.py, add taxonomy_type as a write-only ChoiceField with required=False and choices=["tags", "competency"]. In src/openedx_tagging/rest_api/v1/views.py, update both perform_create() (around line 262) and the create_import() action to surface taxonomy_type from validated data for use by higher layers — do not call CompetencyTaxonomy directly from this layer. In openedx_learning/applets/cbe/api.py, add create_competency_taxonomy(): call create_taxonomy() from openedx_tagging, then create the linked CompetencyTaxonomy row, wrapped in transaction.atomic(). Wire the dispatch to create_competency_taxonomy() at a layer that can see both openedx_tagging and the CBE applet — a CBE-provided view mixin overriding perform_create() is one viable approach. In openedx-platform/openedx/core/djangoapps/content_tagging/rest_api/v1/views.py, verify that TaxonomyOrgView.create_import() (lines 109–133) does not strip taxonomy_type before calling super().create_import(); patch if needed. Reject "system" and all other unsupported values with a 400 on both endpoints.

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