Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Select an option

  • Save laureaudubon1/6bc92743d422ba62b61e2af467df4053 to your computer and use it in GitHub Desktop.

Select an option

Save laureaudubon1/6bc92743d422ba62b61e2af467df4053 to your computer and use it in GitHub Desktop.

Technical Strategy - Task 5: API Endpoints & Authorization

Feature: Export study data - API Endpoints & Authorization

Technical Gaps

  • Gap 1: No REST endpoints for creating and monitoring export tasks
  • Gap 2: No authorization logic to verify publisher/admin access to study exports
  • Gap 3: No presigned URL generation for secure download access
  • Gap 4: No API endpoints for export task status polling

Solution Overview

Create secure REST API endpoints for export task management with proper authorization checks, following existing controller patterns and security standards.

Key decisions:

  1. Authorization: Only study publisher (publishedBy) or admin role can export
  2. API Design: Follow existing REST patterns with proper HTTP status codes
  3. Security: Use existing @ResearcherAuth() and @Role() decorators
  4. Download: Generate presigned URLs for secure temporary access

Testing Strategy

describe('Study Export API HTTP routes', () => {
  it('POST /admin/studies/:studyId/export - creates export task for study publisher or admin');
  it('POST /admin/studies/:studyId/export - rejects export request from non-publisher researcher');
  it('POST /admin/studies/:studyId/export - returns 404 for non-existent study');
  it('GET /admin/studies/:studyId/export/:taskId - polls export status');
  it('GET /admin/studies/:studyId/export/:taskId/download - generates valid presigned download URL');
});

Implementation Files

backend/src/modules/studies/export/
├── study-export.controller.ts            # Export API endpoints
├── study-export.service.ts            # Export API endpoints
└── tests/
    └── study-export.controller.spec-e2e.ts

API Endpoints Design

Export Controller:

@Controller('admin/studies/:studyId/export')
@ResearcherAuth()
export class StudyExportController {
  @Post()
  @HttpCode(HttpStatus.CREATED)
  @Audit({ action: 'CREATE_EXPORT_TASK' })
  async createExport(
    @Param('studyId') studyId: string,
    @Researcher() researcher: ResearcherDB
  ): Promise<ExportTaskDto>

  @Get(':taskId')
  async getExportStatus(
    @Param('studyId') studyId: string,
    @Param('taskId') taskId: string,
    @Researcher() researcher: ResearcherDB
  ): Promise<ExportTaskDto>
}

Authorization Logic

Study Access Validation:

private async validateExportAccess(
  studyId: string,
  researcher: ResearcherDB
): Promise<StudyWithQuestionnaires> {
  // Allow admin role or study publisher
}

Endpoint Implementations

Create Export Task:

async createExport(studyId: string, researcher: ResearcherDB): Promise<ExportTaskDto> {
  // Check for existing pending export
  // Create new export task and queue job
}

Get Export Status with Fresh URL:

async getExportStatus(studyId: string, taskId: string, researcher: ResearcherDB): Promise<ExportTaskDto> {
  // Generate fresh presigned URL for completed exports
}

Request/Response Schemas

Export Task Response:

export const ExportTaskResponseSchema = z.object({
  id: z.string(),
  studyId: z.string(),
  status: z.enum(['pending', 'processing', 'completed', 'failed']),
  progress: z.number().min(0).max(100),
  downloadUrl: z.string().url().optional(),
  fileName: z.string().optional(),
  fileSizeBytes: z.number().int().nonnegative().optional(),
  expiresAt: z.string().datetime().optional(),
  errorMessage: z.string().optional(),
  createdAt: z.string().datetime(),
  completedAt: z.string().datetime().optional(),
});

Integration Points

  • Studies Service: Study access validation
  • Export Task Service: Task lifecycle management
  • Job Queue Service: Background job processing
  • Storage Service: Presigned URL generation
  • Audit Service: Export operation logging

Standards of Code

@docs/standards/general.md @docs/standards/backend.md @docs/standards/e2e-tests.md Use existing @ResearcherAuth() and authorization patterns Handle user expectable errors in controller with proper NestJS HTTP built-in exception Implement proper HTTP status codes and error responses Validate study publisher or admin role access before export Generate fresh presigned URLs on each status check for security Use existing audit patterns for export operation logging Follow REST API conventions with proper resource nesting Handle concurrent export requests with appropriate conflict responses

Future Enhancements - Out of scope

  • Bulk export endpoints for multiple studies
  • Export scheduling API endpoints
  • Export sharing between researchers
  • Export template customization endpoints
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment