Сравнение версий

Ключ

  • Эта строка добавлена.
  • Эта строка удалена.
  • Изменено форматирование.
HTML
<style>
    .apitester {
        box-sizing: border-box;
        border: 1px solid #eaeaea;
        font-family: sans-serif;
    }

    .apitester * {
        box-sizing: border-box;
    }

    .apitester h3 {
        margin: 0;
    }

    .apitester-hint {
        color: #ccc;
    }

    .apitester pre {
        margin: 0;
        font-family: monospace;
    }

    .apitester-editor {
        padding: 1rem;
    }

    .apitester-editor>div {
        margin-top: 0.5rem;
    }

    .apitester-editor [data-ref=method] {
        display: inline-block;
    }

    .apitester-editor [data-ref=host] {
        display: inline-block;
        resize: horizontal;
        border: 1px solid #eaeaea;
        padding: 0.5rem;
        white-space: pre-wrap;
        font-family: monospace;
    }

    .apitester-editor [data-ref=url] {
        display: inline-block;
        padding: 0;
        white-space: pre-wrap;
    }

    .apitester-editor [data-ref=body] {
        display: block;
        resize: vertical;
        width: 100%;
        min-height: 3rem;
        border: 1px solid #eaeaea;
        padding: 0.5rem;
        white-space: pre-wrap;
    }

    .apitester [data-ref=execute] {
        padding: 0.5rem 1rem;
    }

    .apitester [data-ref=output] {
        background: #eaeaea;
        padding: 0.5rem 1rem;
        white-space: pre-wrap;
    }

    .apitester-error {
        border-color: red;
    }
</style>

<script>
"use strict";

const DEFAULT_HOST = "http://localhost:8080";
const API_KEY = "7fd18aaabd7d53ffa4846e4521c1f736c13490eb";

function stringify(obj) {
    let objStr = JSON.stringify(obj, null, 4);
    if (objStr == "{}") {
        objStr = obj.toString();
    }
    return objStr;
}

class ApiTester {
    constructor(selector, httpMethod, apiMethod, body) {
        this.state = {
            host: localStorage.getItem("apitester-.hostname") || DEFAULT_HOST,
            httpMethod: httpMethod,
            apiMethod: apiMethod,
            body: body,
            isExecuting: false,
            output: null,
        };
        this.el = this.initEl(selector);
        this.listen();
        this.render();
    }

    get txtMethod() {
        return this.el.querySelector("[data-ref=method]");
    }

    get txtHost() {
        return this.el.querySelector("[data-ref=host]");
    }

    get txtUrl() {
        return this.el.querySelector("[data-ref=url]");
    }

    get txtBody() {
        return this.el.querySelector("[data-ref=body]");
    }

    get btnExecute() {
        return this.el.querySelector("[data-ref=execute]");
    }

    get txtOutput() {
        return this.el.querySelector("[data-ref=output]");
    }

    initEl(selector) {
        const el = document.querySelector(selector);
        el.innerHTML = `
        <div class="apitester-editor">
            <h3>
                API-тестер
                <span class="apitester-hint">работает только по HTTPS</span>
            </h3>
            <div>
                <pre data-ref="method"></pre>
                <input data-ref="host">
                <pre data-ref="url"></pre>
            </div>
            <div>
                <textarea data-ref="body"></textarea>
            </div>
            <div>
                <button data-ref="execute">Выполнить</button>
            </div>
        </div>
        <pre data-ref="output">
        </pre>
        `;
        return el;
    }

    listen() {
        this.el.addEventListener("keydown", (event) => {
            this.onKeydown(event);
        });
        this.txtHost.addEventListener("blur", (event) => {
            this.onEdit();
        });
        this.txtBody.addEventListener("blur", (event) => {
            this.onEdit();
        });
        this.btnExecute.addEventListener("click", (event) => {
            this.onExecute();
        });
    }

    onKeydown(event) {
        if (event.keyCode == 13 && (event.ctrlKey || event.metaKey)) {
            // Ctrl + Enter
            event.preventDefault();
            this.onEdit();
            this.onExecute();
        }
    }

    onEdit() {
        try {
            this.state.host = this.txtHost.value;
            this.state.body = this.txtBody.value;
            localStorage.setItem("apitester-.hostname", this.state.host);
        } catch (exc) {
            this.state.output = exc.toString();
        } finally {
            this.render();
        }
    }

    onExecute() {
        this.markAsExecuting();
        this.execute()
            .then((response) => {
                return response.json();
            })
            .then((response) => {
                this.showResponse(response);
            })
            .catch((err) => {
                this.showResponse(err);
            });
    }

    markAsExecuting() {
        this.state.output = null;
        this.state.isExecuting = true;
        this.render();
    }

    showResponse(response) {
        this.state.output = stringify(response);
        this.state.isExecuting = false;
        this.render();
    }

    execute() {
        const url = this.state.host + this.state.apiMethod;
        const options = {
            method: this.state.httpMethod,
            mode: "cors",
            headers: {
                "Content-Type": "application/json",
                Authorization: `Token ${API_KEY}`,
            },
        };
        if (this.state.httpMethod == "POST") {
            options.body = this.state.body;
        }
        return fetch(url, options);
    }

    render() {
        this.txtMethod.innerHTML = this.state.httpMethod;
        this.txtHost.value = this.state.host;
        this.txtUrl.innerHTML = this.state.apiMethod;
        this.txtBody.value = this.state.body;
        if (this.state.isExecuting) {
            this.btnExecute.innerHTML = "Выполняю...";
            this.btnExecute.setAttribute("disabled", "disabled");
        } else {
            this.btnExecute.innerHTML = "Выполнить";
            this.btnExecute.removeAttribute("disabled");
        }
        this.txtOutput.innerHTML = this.state.output;
        if (this.state.output) {
            this.txtOutput.style.display = "block";
        } else {
            this.txtOutput.style.display = "none";
        }
    }
}
</script>