RelationApiController.java

package com.taxonomy.relations.controller;

import com.taxonomy.dto.TaxonomyRelationDto;
import com.taxonomy.model.RelationType;
import com.taxonomy.catalog.service.TaxonomyRelationService;
import com.taxonomy.workspace.service.WorkspaceContext;
import com.taxonomy.workspace.service.WorkspaceContextResolver;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.util.List;
import java.util.Map;

@RestController
@RequestMapping("/api")
@Tag(name = "Relations")
public class RelationApiController {

    private final TaxonomyRelationService relationService;
    private final WorkspaceContextResolver contextResolver;

    public RelationApiController(TaxonomyRelationService relationService,
                                  WorkspaceContextResolver contextResolver) {
        this.relationService = relationService;
        this.contextResolver = contextResolver;
    }

    @Operation(summary = "List relations", description = "Returns all taxonomy relations, optionally filtered by type")
    @GetMapping("/relations")
    public ResponseEntity<List<TaxonomyRelationDto>> getRelations(
            @Parameter(description = "Filter by relation type") @RequestParam(required = false) String type) {
        WorkspaceContext ctx = contextResolver.resolveCurrentContext();
        if (type != null && !type.isBlank()) {
            RelationType relationType;
            try {
                relationType = RelationType.valueOf(type.toUpperCase());
            } catch (IllegalArgumentException e) {
                return ResponseEntity.badRequest().build();
            }
            return ResponseEntity.ok(relationService.getRelationsByType(relationType, ctx.workspaceId()));
        }
        return ResponseEntity.ok(relationService.getAllRelations(ctx.workspaceId()));
    }

    @Operation(summary = "Get node relations", description = "Returns all relations for a specific taxonomy node")
    @GetMapping("/node/{code}/relations")
    public ResponseEntity<List<TaxonomyRelationDto>> getRelationsForNode(
            @PathVariable String code) {
        WorkspaceContext ctx = contextResolver.resolveCurrentContext();
        return ResponseEntity.ok(relationService.getRelationsForNode(code, ctx.workspaceId()));
    }

    @Operation(summary = "Create relation", description = "Creates a new taxonomy relation between two nodes")
    @PostMapping("/relations")
    public ResponseEntity<TaxonomyRelationDto> createRelation(
            @RequestBody Map<String, String> body) {
        String sourceCode = body.get("sourceCode");
        String targetCode = body.get("targetCode");
        String relationTypeStr = body.get("relationType");
        String description = body.get("description");
        String provenance = body.get("provenance");

        if (sourceCode == null || sourceCode.isBlank() ||
                targetCode == null || targetCode.isBlank() ||
                relationTypeStr == null || relationTypeStr.isBlank()) {
            return ResponseEntity.badRequest().build();
        }

        RelationType relationType;
        try {
            relationType = RelationType.valueOf(relationTypeStr.toUpperCase());
        } catch (IllegalArgumentException e) {
            return ResponseEntity.badRequest().build();
        }

        try {
            WorkspaceContext ctx = contextResolver.resolveCurrentContext();
            TaxonomyRelationDto dto = relationService.createRelation(
                    sourceCode, targetCode, relationType, description, provenance,
                    ctx.workspaceId(), ctx.username());
            return ResponseEntity.ok(dto);
        } catch (IllegalArgumentException e) {
            return ResponseEntity.badRequest().build();
        }
    }

    @Operation(summary = "Delete relation", description = "Deletes a taxonomy relation by ID")
    @DeleteMapping("/relations/{id}")
    public ResponseEntity<Void> deleteRelation(@PathVariable Long id) {
        WorkspaceContext ctx = contextResolver.resolveCurrentContext();
        try {
            relationService.deleteRelation(id, ctx.workspaceId());
        } catch (IllegalArgumentException e) {
            return ResponseEntity.status(403).build();
        }
        return ResponseEntity.noContent().build();
    }

    @Operation(summary = "Count relations", description = "Returns the total number of taxonomy relations visible in the current workspace")
    @GetMapping("/relations/count")
    public ResponseEntity<Map<String, Long>> countRelations() {
        WorkspaceContext ctx = contextResolver.resolveCurrentContext();
        return ResponseEntity.ok(Map.of("count", relationService.countRelations(ctx.workspaceId())));
    }
}