JSONPlaceholder Network Request Lab

This example goes beyond showing a policy configuration — it lets users select real network tasks inside the sandbox: read posts, view details, pull comments, filter by user, or send a demo POST to JSONPlaceholder. Requests don't leave the iframe directly; they go through api.fetch() to the host, which decides whether to proxy based on allowlist, method, timeout, body size, and response type.

slex: "0.1",
  namespace: "example_jsonplaceholder_network_lab",
  g: {
    scenario: "posts",
    postId: 1,
    userId: 1,
    timeout: 3000,
    title: "SlexKit network demo",
    status: "Not requested",
    statusCode: "-",
    elapsed: "-",
    response: "Select a network task, then click 'Send request'.",
    lastUrl: "https://jsonplaceholder.typicode.com/posts",
    method: function () { return this.scenario === "create" ? "POST" : "GET"; },
    url: function () {
      if (this.scenario === "detail") return "https://jsonplaceholder.typicode.com/posts/" + this.postId;
      if (this.scenario === "comments") return "https://jsonplaceholder.typicode.com/posts/" + this.postId + "/comments";
      if (this.scenario === "user-posts") return "https://jsonplaceholder.typicode.com/users/" + this.userId + "/posts";
      if (this.scenario === "create") return "https://jsonplaceholder.typicode.com/posts";
      return "https://jsonplaceholder.typicode.com/posts?_limit=5";
    },
    requestBody: function () {
      if (this.scenario !== "create") return undefined;
      return {
        title: this.title,
        body: "A demo request from SlexKit secure runtime, proxied by the host.",
        userId: this.userId
      };
    },
    description: function () {
      if (this.scenario === "detail") return "Read a single post — suitable for detail pages or citation cards.";
      if (this.scenario === "comments") return "Read comments on a post — suitable for comment summaries, review flows, and evidence panels.";
      if (this.scenario === "user-posts") return "Read posts by user — suitable for personal spaces, author profiles, or related resource lists.";
      if (this.scenario === "create") return "Submit a demo post. JSONPlaceholder returns a fake write result — nothing is persisted.";
      return "Read the latest posts list — suitable for feeds, task lists, and knowledge base indexes.";
    },
    riskText: function () {
      if (this.method() === "POST") return "POST is restricted to the JSONPlaceholder origin, and request body size is constrained by policy.";
      return "GET requests still go through origin, timeout, response size, and content-type validation.";
    },
    requestSnippet: function () {
      var body = this.requestBody();
      var lines = [
        "await api.fetch('" + this.url() + "', {",
        "  method: '" + this.method() + "',",
        "  timeoutMs: " + this.timeout + ","
      ];
      if (body) lines.push("  body: " + JSON.stringify(body, null, 2).replace(/\n/g, "\n  ") + ",");
      lines.push("  credentials: 'omit'");
      lines.push("})");
      return lines.join("\n");
    },
    policyRows: function () {
      return [
        { item: "Origin", value: "https://jsonplaceholder.typicode.com", reason: "Demo API only" },
        { item: "Method", value: "GET, POST", reason: "Read lists/details and create demo data" },
        { item: "Credentials", value: "omit", reason: "No cookies or site identity" },
        { item: "Content-Type", value: "application/json", reason: "Reject non-JSON responses in sandbox" },
        { item: "Body", value: "<= 4096 bytes", reason: "Prevent large request body abuse" }
      ];
    },
    async run(api) {
      var targetUrl = String(this.url());
      this.status = "Requesting";
      this.statusCode = "-";
      this.elapsed = "-";
      this.lastUrl = targetUrl;
      this.response = "Waiting for host proxy " + this.method() + " " + targetUrl;
      try {
        var result = await api.fetch(targetUrl, {
          method: this.method(),
          timeoutMs: this.timeout,
          body: this.requestBody(),
          credentials: "omit"
        });
        this.status = result.ok ? "Success" : "HTTP Error";
        this.statusCode = String(result.status) + " " + result.statusText;
        this.elapsed = Math.round(result.elapsedMs) + " ms";
        this.response = JSON.stringify(result.data === undefined ? result.text : result.data, null, 2).slice(0, 2400);
      } catch (error) {
        this.status = api.isPolicyError(error) ? "Policy Blocked" : api.isTimeoutError(error) ? "Timeout" : "Network Error";
        this.statusCode = api.isPolicyError(error) ? "policy" : api.isTimeoutError(error) ? "timeout" : "network";
        var elapsedMs = error && typeof error === "object" && typeof error.elapsedMs === "number" ? error.elapsedMs : undefined;
        this.elapsed = elapsedMs === undefined ? "-" : Math.round(elapsedMs) + " ms";
        this.response = targetUrl + "\n" + api.errorMessage(error);
      }
    },
    async runBlocked(api) {
      var targetUrl = "https://example.com/posts/1";
      this.status = "Requesting";
      this.statusCode = "-";
      this.elapsed = "-";
      this.lastUrl = targetUrl;
      this.response = "This request intentionally targets an origin outside the allowlist — it should be blocked by host policy.";
      try {
        await api.get(targetUrl, { timeoutMs: this.timeout, credentials: "omit" });
        this.status = "Unexpected pass";
        this.statusCode = "unexpected";
        this.response = "If you see this, the policy didn't block as expected.";
      } catch (error) {
        this.status = api.isPolicyError(error) ? "Policy Blocked" : "Failed";
        this.statusCode = api.isPolicyError(error) ? "origin_blocked" : "network";
        this.response = targetUrl + "\n" + api.errorMessage(error);
      }
    }
  },
  layout: {
    "section:network": {
      eyebrow: "Platform Features",
      title: "JSONPlaceholder Network Request Lab",
      subtitle: "Select network tasks inside the sandbox — requests go through host policy proxy.",
      "card:network": {
        title: "JSONPlaceholder Request Lab",
      "callout:intent": { tone: "info", "$text": "g.description()" },
      "grid:controls": {
        columns: 1,
        mdColumns: 2,
        "select:scenario": {
          label: "Network task",
          "$value": "g.scenario",
          options: [
            { label: "Posts list GET /posts", value: "posts" },
            { label: "Post detail GET /posts/:id", value: "detail" },
            { label: "Comments GET /posts/:id/comments", value: "comments" },
            { label: "User posts GET /users/:id/posts", value: "user-posts" },
            { label: "Create post POST /posts", value: "create" }
          ],
          onchange: "g.scenario = String($event)"
        },
        "slider:postId": { label: "Post ID", "$value": "g.postId", min: 1, max: 10, step: 1, onchange: "g.postId = Number($event)" },
        "slider:userId": { label: "User ID", "$value": "g.userId", min: 1, max: 10, step: 1, onchange: "g.userId = Number($event)" },
        "slider:timeout": { label: "Timeout limit", "$value": "g.timeout", min: 500, max: 8000, step: 500, unit: "ms", onchange: "g.timeout = Number($event)" }
      },
      "row:actions": {
        "button:run": { label: "Send request", icon: "paper-plane-tilt", onclick: "g.run(api)" },
        "button:block": { label: "Test block", variant: "secondary", icon: "shield-warning", onclick: "g.runBlocked(api)" }
      },
      "grid:status": {
        columns: 1,
        mdColumns: 3,
        "stat:method": { label: "Method", "$value": "g.method()" },
        "stat:status": { label: "Status", "$value": "g.status" },
        "stat:elapsed": { label: "Elapsed", "$value": "g.elapsed" }
      },
      "code-block:request": { title: "Sandbox request code", language: "ts", "$code": "g.requestSnippet()" },
      "code-block:response": { title: "Host proxy response", language: "json", "$code": "g.response" },
      "table:policy_matrix": {
        columns: [
          { key: "item", label: "Policy Item" },
          { key: "value", label: "Allowed Value" },
          { key: "reason", label: "Reason" }
        ],
        "$rows": "g.policyRows()"
      },
      "callout:policy_note": { "$tone": "g.status === 'Policy Blocked' ? 'warning' : 'success'", "$text": "g.riskText()" }
      }
    }
  }
}