File size: 4,978 Bytes
452f691
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
dd7ffbd
 
452f691
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
import apiClient from './apiClient.js';

const ENDPOINTS = [
    { label: 'Health', method: 'GET', path: '/api/health', description: 'Core service health check' },
    { label: 'Market Stats', method: 'GET', path: '/api/market/stats', description: 'Global market metrics' },
    { label: 'Top Coins', method: 'GET', path: '/api/coins/top', description: 'Top market cap coins', params: 'limit=10' },
    { label: 'Latest News', method: 'GET', path: '/api/news/latest', description: 'Latest curated news', params: 'limit=20' },
    { label: 'Chart History', method: 'GET', path: '/api/charts/price/BTC', description: 'Historical price data', params: 'timeframe=7d' },
    { label: 'Chart AI Analysis', method: 'POST', path: '/api/charts/analyze', description: 'AI chart insights', body: '{"symbol":"BTC","timeframe":"7d"}' },
    { label: 'Sentiment Analysis', method: 'POST', path: '/api/sentiment/analyze', description: 'Run sentiment models', body: '{"text":"Bitcoin rally","mode":"auto"}' },
    { label: 'News Summarize', method: 'POST', path: '/api/news/summarize', description: 'Summarize a headline', body: '{"title":"Headline","body":"Full article"}' },
];

class ApiExplorerView {
    constructor(section) {
        this.section = section;
        this.endpointSelect = section?.querySelector('[data-api-endpoint]');
        this.methodSelect = section?.querySelector('[data-api-method]');
        this.paramsInput = section?.querySelector('[data-api-params]');
        this.bodyInput = section?.querySelector('[data-api-body]');
        this.sendButton = section?.querySelector('[data-api-send]');
        this.responseNode = section?.querySelector('[data-api-response]');
        this.metaNode = section?.querySelector('[data-api-meta]');
    }

    init() {
        if (!this.section) return;
        this.populateEndpoints();
        this.bindEvents();
        this.applyPreset(ENDPOINTS[0]);
    }

    populateEndpoints() {
        if (!this.endpointSelect) return;
        this.endpointSelect.innerHTML = ENDPOINTS.map((endpoint, index) => `<option value="${index}">${endpoint.label}</option>`).join('');
    }

    bindEvents() {
        this.endpointSelect?.addEventListener('change', () => {
            const index = Number(this.endpointSelect.value);
            this.applyPreset(ENDPOINTS[index]);
        });
        this.sendButton?.addEventListener('click', () => this.sendRequest());
    }

    applyPreset(preset) {
        if (!preset) return;
        if (this.methodSelect) {
            this.methodSelect.value = preset.method;
        }
        if (this.paramsInput) {
            this.paramsInput.value = preset.params || '';
        }
        if (this.bodyInput) {
            this.bodyInput.value = preset.body || '';
        }
        this.section.querySelector('[data-api-description]').textContent = preset.description;
        this.section.querySelector('[data-api-path]').textContent = preset.path;
    }

    async sendRequest() {
        const index = Number(this.endpointSelect?.value || 0);
        const preset = ENDPOINTS[index];
        const method = this.methodSelect?.value || preset.method;
        let endpoint = preset.path;
        const params = (this.paramsInput?.value || '').trim();
        if (params) {
            endpoint += endpoint.includes('?') ? `&${params}` : `?${params}`;
        }

        let body = this.bodyInput?.value.trim();
        if (!body) body = undefined;
        let parsedBody;
        if (body && method !== 'GET') {
            try {
                parsedBody = JSON.parse(body);
            } catch (error) {
                this.renderError('Invalid JSON body');
                return;
            }
        }

        this.renderMeta('pending');
        this.renderResponse('Fetching...');
        const started = performance.now();
        const result = await apiClient.request(method, endpoint, { cache: false, body: parsedBody });
        const duration = Math.round(performance.now() - started);

        if (!result.ok) {
            this.renderError(result.error || 'Request failed', duration);
            return;
        }
        this.renderMeta('ok', duration, method, endpoint);
        this.renderResponse(result.data);
    }

    renderResponse(data) {
        if (!this.responseNode) return;
        if (typeof data === 'string') {
            this.responseNode.textContent = data;
            return;
        }
        this.responseNode.textContent = JSON.stringify(data, null, 2);
    }

    renderMeta(status, duration = 0, method = '', path = '') {
        if (!this.metaNode) return;
        if (status === 'pending') {
            this.metaNode.textContent = 'Sending request...';
            return;
        }
        this.metaNode.textContent = `${method} ${path}${duration}ms`;
    }

    renderError(message, duration = 0) {
        this.renderMeta('error', duration);
        this.renderResponse({ error: message });
    }
}

export default ApiExplorerView;