initial public commit
This commit is contained in:
@@ -0,0 +1,111 @@
|
||||
<script>
|
||||
import { Collection } from "pocketbase";
|
||||
import OverlayPanel from "@/components/base/OverlayPanel.svelte";
|
||||
import ListApiDocs from "@/components/collections/docs/ListApiDocs.svelte";
|
||||
import ViewApiDocs from "@/components/collections/docs/ViewApiDocs.svelte";
|
||||
import CreateApiDocs from "@/components/collections/docs/CreateApiDocs.svelte";
|
||||
import UpdateApiDocs from "@/components/collections/docs/UpdateApiDocs.svelte";
|
||||
import DeleteApiDocs from "@/components/collections/docs/DeleteApiDocs.svelte";
|
||||
import RealtimeApiDocs from "@/components/collections/docs/RealtimeApiDocs.svelte";
|
||||
|
||||
const tabs = [
|
||||
{
|
||||
id: "list",
|
||||
label: "List",
|
||||
component: ListApiDocs,
|
||||
},
|
||||
{
|
||||
id: "view",
|
||||
label: "View",
|
||||
component: ViewApiDocs,
|
||||
},
|
||||
{
|
||||
id: "create",
|
||||
label: "Create",
|
||||
component: CreateApiDocs,
|
||||
},
|
||||
{
|
||||
id: "update",
|
||||
label: "Update",
|
||||
component: UpdateApiDocs,
|
||||
},
|
||||
{
|
||||
id: "delete",
|
||||
label: "Delete",
|
||||
component: DeleteApiDocs,
|
||||
},
|
||||
{
|
||||
id: "realtime",
|
||||
label: "Realtime",
|
||||
component: RealtimeApiDocs,
|
||||
},
|
||||
];
|
||||
|
||||
let collectionPanel;
|
||||
let collection = new Collection();
|
||||
let activeTab = tabs[0].id;
|
||||
|
||||
export function show(model) {
|
||||
collection = model;
|
||||
|
||||
changeTab(tabs[0].id);
|
||||
|
||||
return collectionPanel?.show();
|
||||
}
|
||||
|
||||
export function hide() {
|
||||
return collectionPanel?.hide();
|
||||
}
|
||||
|
||||
export function changeTab(newTab) {
|
||||
activeTab = newTab;
|
||||
}
|
||||
|
||||
function changeTabViaKey(e, newTab) {
|
||||
if (e.code === "Enter" || e.code === "Space") {
|
||||
e.preventDefault();
|
||||
changeTab(newTab);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<OverlayPanel
|
||||
bind:this={collectionPanel}
|
||||
on:hide
|
||||
on:show
|
||||
class="overlay-panel-xl colored-header collection-panel"
|
||||
>
|
||||
<svelte:fragment slot="header">
|
||||
<h4><strong>{collection.name}</strong> records API</h4>
|
||||
|
||||
<div class="tabs-header stretched">
|
||||
{#each tabs as tab (tab.id)}
|
||||
<button
|
||||
tabindex="0"
|
||||
class="tab-item"
|
||||
class:active={activeTab === tab.id}
|
||||
on:click={() => changeTab(tab.id)}
|
||||
on:keydown|self={(e) => changeTabViaKey(e, tab.id)}
|
||||
>
|
||||
<span class="txt">{tab.label}</span>
|
||||
</button>
|
||||
{/each}
|
||||
</div>
|
||||
</svelte:fragment>
|
||||
|
||||
<div class="tabs-content">
|
||||
{#each tabs as tab (tab.id)}
|
||||
{#if activeTab === tab.id}
|
||||
<div class="tab-item active">
|
||||
<svelte:component this={tab.component} {collection} />
|
||||
</div>
|
||||
{/if}
|
||||
{/each}
|
||||
</div>
|
||||
|
||||
<svelte:fragment slot="footer">
|
||||
<button type="button" class="btn btn-secondary" on:click={() => hide()}>
|
||||
<span class="txt">Close</span>
|
||||
</button>
|
||||
</svelte:fragment>
|
||||
</OverlayPanel>
|
||||
@@ -0,0 +1,184 @@
|
||||
<script>
|
||||
import { Collection } from "pocketbase";
|
||||
import ApiClient from "@/utils/ApiClient";
|
||||
import CommonHelper from "@/utils/CommonHelper";
|
||||
import CodeBlock from "@/components/base/CodeBlock.svelte";
|
||||
|
||||
export let collection = new Collection();
|
||||
|
||||
let responseTab = 200;
|
||||
let sdkTab = "JavaScript";
|
||||
let responses = [];
|
||||
let sdkExamples = [];
|
||||
|
||||
$: adminsOnly = collection?.createRule === null;
|
||||
|
||||
$: responses = [
|
||||
{
|
||||
code: 200,
|
||||
body: JSON.stringify(CommonHelper.dummyCollectionRecord(collection), null, 2),
|
||||
},
|
||||
{
|
||||
code: 400,
|
||||
body: `
|
||||
{
|
||||
"code": 400,
|
||||
"message": "Failed to create record.",
|
||||
"data": {
|
||||
"${collection?.schema?.[0]?.name}": {
|
||||
"code": "validation_required",
|
||||
"message": "Missing required value."
|
||||
}
|
||||
}
|
||||
}
|
||||
`,
|
||||
},
|
||||
{
|
||||
code: 403,
|
||||
body: `
|
||||
{
|
||||
"code": 403,
|
||||
"message": "You are not allowed to perform this request.",
|
||||
"data": {}
|
||||
}
|
||||
`,
|
||||
},
|
||||
];
|
||||
|
||||
$: sdkExamples = [
|
||||
{
|
||||
lang: "JavaScript",
|
||||
code: `
|
||||
import PocketBase from 'pocketbase';
|
||||
|
||||
const client = new PocketBase("${ApiClient.baseUrl}");
|
||||
|
||||
const data = { ... };
|
||||
|
||||
client.Records.create("${collection?.name}", data)
|
||||
.then(function (record) {
|
||||
// success...
|
||||
}).catch(function (error) {
|
||||
// error...
|
||||
});
|
||||
`,
|
||||
},
|
||||
];
|
||||
</script>
|
||||
|
||||
<div class="alert alert-success">
|
||||
<strong class="label label-primary">POST</strong>
|
||||
<div class="content">
|
||||
<p>
|
||||
/api/collections/<strong>{collection.name}</strong>/records
|
||||
</p>
|
||||
</div>
|
||||
{#if adminsOnly}
|
||||
<p class="txt-hint txt-sm txt-right">Requires <code>Authorization: Admin TOKEN</code> header</p>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<div class="content m-b-base">
|
||||
<p>Create a new <strong>{collection.name}</strong> record.</p>
|
||||
<p>
|
||||
Body parameters could be sent as <code>application/json</code> or
|
||||
<code>multipart/form-data</code>.
|
||||
</p>
|
||||
<p>
|
||||
File upload is supported only via <code>multipart/form-data</code>.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="section-title">Client SDKs example</div>
|
||||
<div class="tabs m-b-lg">
|
||||
<div class="tabs-header compact left">
|
||||
{#each sdkExamples as example (example.lang)}
|
||||
<button
|
||||
class="tab-item"
|
||||
class:active={sdkTab === example.lang}
|
||||
on:click={() => (sdkTab = example.lang)}
|
||||
>
|
||||
{example.lang}
|
||||
</button>
|
||||
{/each}
|
||||
</div>
|
||||
<div class="tabs-content">
|
||||
{#each sdkExamples as example (example.lang)}
|
||||
<div class="tab-item" class:active={sdkTab === example.lang}>
|
||||
<CodeBlock content={example.code} />
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="section-title">Body Parameters</div>
|
||||
<table class="table-compact table-border m-b-lg">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Param</th>
|
||||
<th>Type</th>
|
||||
<th width="50%">Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{#each collection?.schema as field (field.name)}
|
||||
<tr>
|
||||
<td>
|
||||
<div class="inline-flex">
|
||||
{#if field.required}
|
||||
<span class="label label-success">Required</span>
|
||||
{:else}
|
||||
<span class="label label-warning">Optional</span>
|
||||
{/if}
|
||||
<span>{field.name}</span>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<span class="label">{CommonHelper.getFieldValueType(field)}</span>
|
||||
</td>
|
||||
<td>
|
||||
{#if field.type === "text"}
|
||||
Plain text value.
|
||||
{:else if field.type === "number"}
|
||||
Number value.
|
||||
{:else if field.type === "json"}
|
||||
JSON array or object.
|
||||
{:else if field.type === "email"}
|
||||
Email address.
|
||||
{:else if field.type === "url"}
|
||||
URL address.
|
||||
{:else if field.type === "file"}
|
||||
FormData object.<br />
|
||||
Set to <code>null</code> to delete already uploaded file(s).
|
||||
{:else if field.type === "relation"}
|
||||
Relation record {field.options?.maxSelect > 1 ? "ids" : "id"}.
|
||||
{:else if field.type === "user"}
|
||||
User {field.options?.maxSelect > 1 ? "ids" : "id"}.
|
||||
{/if}
|
||||
</td>
|
||||
</tr>
|
||||
{/each}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<div class="section-title">Responses</div>
|
||||
<div class="tabs">
|
||||
<div class="tabs-header compact left">
|
||||
{#each responses as response (response.code)}
|
||||
<button
|
||||
class="tab-item"
|
||||
class:active={responseTab === response.code}
|
||||
on:click={() => (responseTab = response.code)}
|
||||
>
|
||||
{response.code}
|
||||
</button>
|
||||
{/each}
|
||||
</div>
|
||||
<div class="tabs-content">
|
||||
{#each responses as response (response.code)}
|
||||
<div class="tab-item" class:active={responseTab === response.code}>
|
||||
<CodeBlock content={response.body} />
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,156 @@
|
||||
<script>
|
||||
import { Collection } from "pocketbase";
|
||||
import ApiClient from "@/utils/ApiClient";
|
||||
import CodeBlock from "@/components/base/CodeBlock.svelte";
|
||||
|
||||
export let collection = new Collection();
|
||||
|
||||
let responseTab = 204;
|
||||
let sdkTab = "JavaScript";
|
||||
let responses = [];
|
||||
let sdkExamples = [];
|
||||
|
||||
$: adminsOnly = collection?.deleteRule === null;
|
||||
|
||||
$: if (collection?.id) {
|
||||
responses.push({
|
||||
code: 204,
|
||||
body: `
|
||||
null
|
||||
`,
|
||||
});
|
||||
|
||||
responses.push({
|
||||
code: 400,
|
||||
body: `
|
||||
{
|
||||
"code": 400,
|
||||
"message": "Failed to delete record. Make sure that the record is not part of a required relation reference.",
|
||||
"data": {}
|
||||
}
|
||||
`,
|
||||
});
|
||||
|
||||
if (adminsOnly) {
|
||||
responses.push({
|
||||
code: 403,
|
||||
body: `
|
||||
{
|
||||
"code": 403,
|
||||
"message": "Only admins can access this action.",
|
||||
"data": {}
|
||||
}
|
||||
`,
|
||||
});
|
||||
}
|
||||
|
||||
responses.push({
|
||||
code: 404,
|
||||
body: `
|
||||
{
|
||||
"code": 404,
|
||||
"message": "The requested resource wasn't found.",
|
||||
"data": {}
|
||||
}
|
||||
`,
|
||||
});
|
||||
}
|
||||
|
||||
$: sdkExamples = [
|
||||
{
|
||||
lang: "JavaScript",
|
||||
code: `
|
||||
import PocketBase from 'pocketbase';
|
||||
|
||||
const client = new PocketBase("${ApiClient.baseUrl}");
|
||||
|
||||
client.Records.delete("${collection?.name}", "RECORD_ID")
|
||||
.then(function () {
|
||||
// success...
|
||||
}).catch(function (error) {
|
||||
// error...
|
||||
});
|
||||
`,
|
||||
},
|
||||
];
|
||||
</script>
|
||||
|
||||
<div class="alert alert-danger">
|
||||
<strong class="label label-primary">DELETE</strong>
|
||||
<div class="content">
|
||||
<p>
|
||||
/api/collections/<strong>{collection.name}</strong>/records/<strong>:id</strong>
|
||||
</p>
|
||||
</div>
|
||||
{#if adminsOnly}
|
||||
<p class="txt-hint txt-sm txt-right">Requires <code>Authorization: Admin TOKEN</code> header</p>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<div class="content m-b-base">
|
||||
<p>Delete a single <strong>{collection.name}</strong> record.</p>
|
||||
</div>
|
||||
|
||||
<div class="section-title">Client SDKs example</div>
|
||||
<div class="tabs m-b-lg">
|
||||
<div class="tabs-header compact left">
|
||||
{#each sdkExamples as example (example.lang)}
|
||||
<button
|
||||
class="tab-item"
|
||||
class:active={sdkTab === example.lang}
|
||||
on:click={() => (sdkTab = example.lang)}
|
||||
>
|
||||
{example.lang}
|
||||
</button>
|
||||
{/each}
|
||||
</div>
|
||||
<div class="tabs-content">
|
||||
{#each sdkExamples as example (example.lang)}
|
||||
<div class="tab-item" class:active={sdkTab === example.lang}>
|
||||
<CodeBlock content={example.code} />
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="section-title">Path parameters</div>
|
||||
<table class="table-compact table-border m-b-lg">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Param</th>
|
||||
<th>Type</th>
|
||||
<th width="60%">Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>id</td>
|
||||
<td>
|
||||
<span class="label">String</span>
|
||||
</td>
|
||||
<td>ID of the record to delete.</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<div class="section-title">Responses</div>
|
||||
<div class="tabs">
|
||||
<div class="tabs-header compact left">
|
||||
{#each responses as response (response.code)}
|
||||
<button
|
||||
class="tab-item"
|
||||
class:active={responseTab === response.code}
|
||||
on:click={() => (responseTab = response.code)}
|
||||
>
|
||||
{response.code}
|
||||
</button>
|
||||
{/each}
|
||||
</div>
|
||||
<div class="tabs-content">
|
||||
{#each responses as response (response.code)}
|
||||
<div class="tab-item" class:active={responseTab === response.code}>
|
||||
<CodeBlock content={response.body} />
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,75 @@
|
||||
<p>
|
||||
The syntax basically follows the format
|
||||
<code>
|
||||
<span class="txt-success">OPERAND</span>
|
||||
<span class="txt-danger">OPERATOR</span>
|
||||
<span class="txt-success">OPERAND</span></code
|
||||
>, where:
|
||||
</p>
|
||||
<ul>
|
||||
<li>
|
||||
<code class="txt-success">OPERAND</code> - could be any of the above field literal, string (single or double
|
||||
quoted), number, null, true, false
|
||||
</li>
|
||||
<li>
|
||||
<code class="txt-danger">OPERATOR</code> - is one of:
|
||||
<br />
|
||||
<ul>
|
||||
<li>
|
||||
<code class="filter-op">{"="}</code>
|
||||
<span class="txt-hint">Equal</span>
|
||||
</li>
|
||||
<li>
|
||||
<code class="filter-op">{"!="}</code>
|
||||
<span class="txt-hint">NOT equal</span>
|
||||
</li>
|
||||
<li>
|
||||
<code class="filter-op">{">"}</code>
|
||||
<span class="txt-hint">Greater than</span>
|
||||
</li>
|
||||
<li>
|
||||
<code class="filter-op">{">="}</code>
|
||||
<span class="txt-hint">Greater than or equal</span>
|
||||
</li>
|
||||
<li>
|
||||
<code class="filter-op">{"<"}</code>
|
||||
<span class="txt-hint">Less than or equal</span>
|
||||
</li>
|
||||
<li>
|
||||
<code class="filter-op">{"<="}</code>
|
||||
<span class="txt-hint">Less than or equal</span>
|
||||
</li>
|
||||
<li>
|
||||
<code class="filter-op">{"~"}</code>
|
||||
<span class="txt-hint">
|
||||
Like/Contains (if not specified auto wraps the right string OPERAND in a "%" for wildcard
|
||||
match)
|
||||
</span>
|
||||
</li>
|
||||
<li>
|
||||
<code class="filter-op">{"!~"}</code>
|
||||
<span class="txt-hint">
|
||||
NOT Like/Contains (if not specified auto wraps the right string OPERAND in a "%" for
|
||||
wildcard match)
|
||||
</span>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p>
|
||||
To group and combine several expressions you could use brackets
|
||||
<code>(...)</code>, <code>&&</code> (AND) and <code>||</code> (OR) tokens.
|
||||
</p>
|
||||
|
||||
<style>
|
||||
.filter-op {
|
||||
display: inline-block;
|
||||
vertical-align: top;
|
||||
margin-right: 5px;
|
||||
width: 30px;
|
||||
text-align: center;
|
||||
padding-left: 0;
|
||||
padding-right: 0;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,232 @@
|
||||
<script>
|
||||
import { Collection } from "pocketbase";
|
||||
import ApiClient from "@/utils/ApiClient";
|
||||
import CommonHelper from "@/utils/CommonHelper";
|
||||
import CodeBlock from "@/components/base/CodeBlock.svelte";
|
||||
import FilterSyntax from "@/components/collections/docs/FilterSyntax.svelte";
|
||||
|
||||
export let collection = new Collection();
|
||||
|
||||
let responseTab = 200;
|
||||
let sdkTab = "JavaScript";
|
||||
let responses = [];
|
||||
let sdkExamples = [];
|
||||
|
||||
$: adminsOnly = collection?.listRule === null;
|
||||
|
||||
$: if (collection?.id) {
|
||||
responses.push({
|
||||
code: 200,
|
||||
body: JSON.stringify(
|
||||
{
|
||||
page: 1,
|
||||
perPage: 30,
|
||||
totalItems: 2,
|
||||
items: [
|
||||
CommonHelper.dummyCollectionRecord(collection),
|
||||
CommonHelper.dummyCollectionRecord(collection),
|
||||
],
|
||||
},
|
||||
null,
|
||||
2
|
||||
),
|
||||
});
|
||||
|
||||
responses.push({
|
||||
code: 400,
|
||||
body: `
|
||||
{
|
||||
"code": 400,
|
||||
"message": "Something went wrong while processing your request. Invalid filter.",
|
||||
"data": {}
|
||||
}
|
||||
`,
|
||||
});
|
||||
|
||||
if (adminsOnly) {
|
||||
responses.push({
|
||||
code: 403,
|
||||
body: `
|
||||
{
|
||||
"code": 403,
|
||||
"message": "Only admins can access this action.",
|
||||
"data": {}
|
||||
}
|
||||
`,
|
||||
});
|
||||
}
|
||||
|
||||
responses.push({
|
||||
code: 404,
|
||||
body: `
|
||||
{
|
||||
"code": 404,
|
||||
"message": "The requested resource wasn't found.",
|
||||
"data": {}
|
||||
}
|
||||
`,
|
||||
});
|
||||
}
|
||||
|
||||
$: sdkExamples = [
|
||||
{
|
||||
lang: "JavaScript",
|
||||
code: `
|
||||
import PocketBase from 'pocketbase';
|
||||
|
||||
const client = new PocketBase("${ApiClient.baseUrl}");
|
||||
|
||||
client.Records.getList("${collection?.name}", { page: 2 })
|
||||
.then(function (list) {
|
||||
// success...
|
||||
}).catch(function (error) {
|
||||
// error...
|
||||
});
|
||||
|
||||
// alternatively you can also fetch all records at once via getFullList:
|
||||
client.Records.getFullList("${collection?.name}", 200 /* batch size */);
|
||||
.then(function (records) {
|
||||
// success...
|
||||
}).catch(function (error) {
|
||||
// error...
|
||||
});
|
||||
`,
|
||||
},
|
||||
];
|
||||
</script>
|
||||
|
||||
<div class="alert alert-info">
|
||||
<strong class="label label-primary">GET</strong>
|
||||
<div class="content">
|
||||
<p>
|
||||
/api/collections/<strong>{collection.name}</strong>/records
|
||||
</p>
|
||||
</div>
|
||||
{#if adminsOnly}
|
||||
<p class="txt-hint txt-sm txt-right">Requires <code>Authorization: Admin TOKEN</code> header</p>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<div class="content m-b-base">
|
||||
<p>Fetch a paginated <strong>{collection.name}</strong> records list.</p>
|
||||
</div>
|
||||
|
||||
<div class="section-title">Client SDKs example</div>
|
||||
<div class="tabs m-b-lg">
|
||||
<div class="tabs-header compact left">
|
||||
{#each sdkExamples as example (example.lang)}
|
||||
<button
|
||||
class="tab-item"
|
||||
class:active={sdkTab === example.lang}
|
||||
on:click={() => (sdkTab = example.lang)}
|
||||
>
|
||||
{example.lang}
|
||||
</button>
|
||||
{/each}
|
||||
</div>
|
||||
<div class="tabs-content">
|
||||
{#each sdkExamples as example (example.lang)}
|
||||
<div class="tab-item" class:active={sdkTab === example.lang}>
|
||||
<CodeBlock content={example.code} />
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="section-title">Query parameters</div>
|
||||
<table class="table-compact table-border m-b-lg">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Param</th>
|
||||
<th>Type</th>
|
||||
<th width="60%">Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>page</td>
|
||||
<td>
|
||||
<span class="label">Number</span>
|
||||
</td>
|
||||
<td>The page (aka. offset) of the paginated list (default to 1).</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>perPage</td>
|
||||
<td>
|
||||
<span class="label">Number</span>
|
||||
</td>
|
||||
<td>Specify the max returned records per page (default to 30).</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>sort</td>
|
||||
<td>
|
||||
<span class="label">String</span>
|
||||
</td>
|
||||
<td>
|
||||
Specify the records order attribute(s). <br />
|
||||
Add <code>-</code> / <code>+</code> (default) in front of the attribute for DESC / ASC order.
|
||||
Ex.:
|
||||
<CodeBlock
|
||||
content={`
|
||||
// DESC by created and ASC by id
|
||||
?sort=-created,id
|
||||
`}
|
||||
/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>filter</td>
|
||||
<td>
|
||||
<span class="label">String</span>
|
||||
</td>
|
||||
<td>
|
||||
Filter the returned records. Ex.:
|
||||
<CodeBlock
|
||||
content={`
|
||||
?filter=(id='abc' && created>'2022-01-01')
|
||||
`}
|
||||
/>
|
||||
<FilterSyntax />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>expand</td>
|
||||
<td>
|
||||
<span class="label">String</span>
|
||||
</td>
|
||||
<td>
|
||||
Auto expand nested record relations. Ex.:
|
||||
<CodeBlock
|
||||
content={`
|
||||
?expand=rel1,rel2.subrel21.subrel22
|
||||
`}
|
||||
/>
|
||||
Supports up to 6-levels depth nested relations expansion. <br />
|
||||
The expanded relations will be appended to each individual record under the
|
||||
<code>@expand</code> property (eg. <code>{`"@expand": {"rel1": {...}, ...}`}</code>).
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<div class="section-title">Responses</div>
|
||||
<div class="tabs">
|
||||
<div class="tabs-header compact left">
|
||||
{#each responses as response (response.code)}
|
||||
<div
|
||||
class="tab-item"
|
||||
class:active={responseTab === response.code}
|
||||
on:click={() => (responseTab = response.code)}
|
||||
>
|
||||
{response.code}
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
<div class="tabs-content">
|
||||
{#each responses as response (response.code)}
|
||||
<div class="tab-item" class:active={responseTab === response.code}>
|
||||
<CodeBlock content={response.body} />
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,109 @@
|
||||
<script>
|
||||
import { Collection } from "pocketbase";
|
||||
import ApiClient from "@/utils/ApiClient";
|
||||
import CommonHelper from "@/utils/CommonHelper";
|
||||
import CodeBlock from "@/components/base/CodeBlock.svelte";
|
||||
|
||||
export let collection = new Collection();
|
||||
|
||||
let sdkTab = "JavaScript";
|
||||
let sdkExamples = [];
|
||||
|
||||
$: sdkExamples = [
|
||||
{
|
||||
lang: "JavaScript",
|
||||
code: `
|
||||
import PocketBase from 'pocketbase';
|
||||
|
||||
const client = new PocketBase("${ApiClient.baseUrl}");
|
||||
|
||||
// (Optionally) authenticate
|
||||
client.Users.authViaEmail("test@example.com", "123456");
|
||||
|
||||
// Subscribe to changes in any record from the collection
|
||||
client.Realtime.subscribe("${collection?.name}", function (e) {
|
||||
console.log(e.data);
|
||||
});
|
||||
|
||||
// Subscribe to changes in a single record
|
||||
client.Realtime.subscribe("${collection?.name}/RECORD_ID", function (e) {
|
||||
console.log(e.data);
|
||||
});
|
||||
|
||||
// Unsubscribe
|
||||
client.Realtime.unsubscribe() // remove all subscriptions
|
||||
client.Realtime.unsubscribe("${collection?.name}") // remove the collection subscription
|
||||
client.Realtime.unsubscribe("${collection?.name}/RECORD_ID") // remove the record subscription
|
||||
`,
|
||||
},
|
||||
];
|
||||
</script>
|
||||
|
||||
<div class="alert">
|
||||
<strong class="label label-primary">SSE</strong>
|
||||
<div class="content">
|
||||
<p>/api/realtime</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="content m-b-base">
|
||||
<p>Subscribe to realtime changes via Server-Sent Events (SSE).</p>
|
||||
<p>
|
||||
Events are send for <strong>create</strong>, <strong>update</strong>
|
||||
and <strong>delete</strong> record operations (see "Event data format" section below).
|
||||
</p>
|
||||
<div class="alert alert-info m-t-10">
|
||||
<div class="icon">
|
||||
<i class="ri-information-line" />
|
||||
</div>
|
||||
<div class="contet">
|
||||
<p>
|
||||
<strong>You could subscribe to a single record or to an entire collection.</strong>
|
||||
</p>
|
||||
<p>
|
||||
When you subscribe to a <strong>single record</strong>, the collection's
|
||||
<strong>ViewRule</strong> will be used to determine whether the subscriber has access to receive
|
||||
the event message.
|
||||
</p>
|
||||
<p>
|
||||
When you subscribe to an <strong>entire collection</strong>, the collection's
|
||||
<strong>ListRule</strong> will be used to determine whether the subscriber has access to receive
|
||||
the event message.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="section-title">Client SDKs example</div>
|
||||
<div class="tabs m-b-base">
|
||||
<div class="tabs-header compact left">
|
||||
{#each sdkExamples as example (example.lang)}
|
||||
<button
|
||||
class="tab-item"
|
||||
class:active={sdkTab === example.lang}
|
||||
on:click={() => (sdkTab = example.lang)}
|
||||
>
|
||||
{example.lang}
|
||||
</button>
|
||||
{/each}
|
||||
</div>
|
||||
<div class="tabs-content">
|
||||
{#each sdkExamples as example (example.lang)}
|
||||
<div class="tab-item" class:active={sdkTab === example.lang}>
|
||||
<CodeBlock content={example.code} />
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="section-title">Event data format</div>
|
||||
<CodeBlock
|
||||
content={JSON.stringify(
|
||||
{
|
||||
action: "create",
|
||||
record: CommonHelper.dummyCollectionRecord(collection),
|
||||
},
|
||||
null,
|
||||
2
|
||||
).replace('"action": "create"', '"action": "create" // create, update or delete')}
|
||||
/>
|
||||
@@ -0,0 +1,214 @@
|
||||
<script>
|
||||
import { Collection } from "pocketbase";
|
||||
import ApiClient from "@/utils/ApiClient";
|
||||
import CommonHelper from "@/utils/CommonHelper";
|
||||
import CodeBlock from "@/components/base/CodeBlock.svelte";
|
||||
|
||||
export let collection = new Collection();
|
||||
|
||||
let responseTab = 200;
|
||||
let sdkTab = "JavaScript";
|
||||
let responses = [];
|
||||
let sdkExamples = [];
|
||||
|
||||
$: adminsOnly = collection?.updateRule === null;
|
||||
|
||||
$: responses = [
|
||||
{
|
||||
code: 200,
|
||||
body: JSON.stringify(CommonHelper.dummyCollectionRecord(collection), null, 2),
|
||||
},
|
||||
{
|
||||
code: 400,
|
||||
body: `
|
||||
{
|
||||
"code": 400,
|
||||
"message": "Failed to update record.",
|
||||
"data": {
|
||||
"${collection?.schema?.[0]?.name}": {
|
||||
"code": "validation_required",
|
||||
"message": "Missing required value."
|
||||
}
|
||||
}
|
||||
}
|
||||
`,
|
||||
},
|
||||
{
|
||||
code: 403,
|
||||
body: `
|
||||
{
|
||||
"code": 403,
|
||||
"message": "You are not allowed to perform this request.",
|
||||
"data": {}
|
||||
}
|
||||
`,
|
||||
},
|
||||
{
|
||||
code: 404,
|
||||
body: `
|
||||
{
|
||||
"code": 404,
|
||||
"message": "The requested resource wasn't found.",
|
||||
"data": {}
|
||||
}
|
||||
`,
|
||||
},
|
||||
];
|
||||
|
||||
$: sdkExamples = [
|
||||
{
|
||||
lang: "JavaScript",
|
||||
code: `
|
||||
import PocketBase from 'pocketbase';
|
||||
|
||||
const client = new PocketBase("${ApiClient.baseUrl}");
|
||||
|
||||
const data = { ... };
|
||||
|
||||
client.Records.update("${collection?.name}", "RECORD_ID", data)
|
||||
.then(function (record) {
|
||||
// success...
|
||||
}).catch(function (error) {
|
||||
// error...
|
||||
});
|
||||
`,
|
||||
},
|
||||
];
|
||||
</script>
|
||||
|
||||
<div class="alert alert-warning">
|
||||
<strong class="label label-primary">PATCH</strong>
|
||||
<div class="content">
|
||||
<p>
|
||||
/api/collections/<strong>{collection.name}</strong>/records/<strong>:id</strong>
|
||||
</p>
|
||||
</div>
|
||||
{#if adminsOnly}
|
||||
<p class="txt-hint txt-sm txt-right">Requires <code>Authorization: Admin TOKEN</code> header</p>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<div class="content m-b-base">
|
||||
<p>Update a single <strong>{collection.name}</strong> record.</p>
|
||||
<p>
|
||||
Body parameters could be sent as <code>application/json</code> or
|
||||
<code>multipart/form-data</code>.
|
||||
</p>
|
||||
<p>
|
||||
File upload is supported only via <code>multipart/form-data</code>.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="section-title">Client SDKs example</div>
|
||||
<div class="tabs m-b-lg">
|
||||
<div class="tabs-header compact left">
|
||||
{#each sdkExamples as example (example.lang)}
|
||||
<button
|
||||
class="tab-item"
|
||||
class:active={sdkTab === example.lang}
|
||||
on:click={() => (sdkTab = example.lang)}
|
||||
>
|
||||
{example.lang}
|
||||
</button>
|
||||
{/each}
|
||||
</div>
|
||||
<div class="tabs-content">
|
||||
{#each sdkExamples as example (example.lang)}
|
||||
<div class="tab-item" class:active={sdkTab === example.lang}>
|
||||
<CodeBlock content={example.code} />
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="section-title">Path parameters</div>
|
||||
<table class="table-compact table-border m-b-lg">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Param</th>
|
||||
<th>Type</th>
|
||||
<th width="60%">Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>id</td>
|
||||
<td>
|
||||
<span class="label">String</span>
|
||||
</td>
|
||||
<td>ID of the record to update.</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<div class="section-title">Body Parameters</div>
|
||||
<table class="table-compact table-border m-b-lg">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Param</th>
|
||||
<th width="60%">Type</th>
|
||||
<th width="50%">Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{#each collection?.schema as field (field.name)}
|
||||
<tr>
|
||||
<td>
|
||||
<div class="inline-flex">
|
||||
{#if field.required}
|
||||
<span class="label label-success">Required</span>
|
||||
{:else}
|
||||
<span class="label label-warning">Optional</span>
|
||||
{/if}
|
||||
<span>{field.name}</span>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<span class="label">{CommonHelper.getFieldValueType(field)}</span>
|
||||
</td>
|
||||
<td>
|
||||
{#if field.type === "text"}
|
||||
Plain text value.
|
||||
{:else if field.type === "number"}
|
||||
Number value.
|
||||
{:else if field.type === "json"}
|
||||
JSON array or object.
|
||||
{:else if field.type === "email"}
|
||||
Email address.
|
||||
{:else if field.type === "url"}
|
||||
URL address.
|
||||
{:else if field.type === "file"}
|
||||
FormData object.<br />
|
||||
Set to <code>null</code> to delete already uploaded file(s).
|
||||
{:else if field.type === "relation"}
|
||||
Relation record {field.options?.maxSelect > 1 ? "ids" : "id"}.
|
||||
{:else if field.type === "user"}
|
||||
User {field.options?.maxSelect > 1 ? "ids" : "id"}.
|
||||
{/if}
|
||||
</td>
|
||||
</tr>
|
||||
{/each}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<div class="section-title">Responses</div>
|
||||
<div class="tabs">
|
||||
<div class="tabs-header compact left">
|
||||
{#each responses as response (response.code)}
|
||||
<button
|
||||
class="tab-item"
|
||||
class:active={responseTab === response.code}
|
||||
on:click={() => (responseTab = response.code)}
|
||||
>
|
||||
{response.code}
|
||||
</button>
|
||||
{/each}
|
||||
</div>
|
||||
<div class="tabs-content">
|
||||
{#each responses as response (response.code)}
|
||||
<div class="tab-item" class:active={responseTab === response.code}>
|
||||
<CodeBlock content={response.body} />
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,174 @@
|
||||
<script>
|
||||
import { Collection } from "pocketbase";
|
||||
import ApiClient from "@/utils/ApiClient";
|
||||
import CommonHelper from "@/utils/CommonHelper";
|
||||
import CodeBlock from "@/components/base/CodeBlock.svelte";
|
||||
|
||||
export let collection = new Collection();
|
||||
|
||||
let responseTab = 200;
|
||||
let sdkTab = "JavaScript";
|
||||
let responses = [];
|
||||
let sdkExamples = [];
|
||||
|
||||
$: adminsOnly = collection?.viewRule === null;
|
||||
|
||||
$: if (collection?.id) {
|
||||
responses.push({
|
||||
code: 200,
|
||||
body: JSON.stringify(CommonHelper.dummyCollectionRecord(collection), null, 2),
|
||||
});
|
||||
|
||||
if (adminsOnly) {
|
||||
responses.push({
|
||||
code: 403,
|
||||
body: `
|
||||
{
|
||||
"code": 403,
|
||||
"message": "Only admins can access this action.",
|
||||
"data": {}
|
||||
}
|
||||
`,
|
||||
});
|
||||
}
|
||||
|
||||
responses.push({
|
||||
code: 404,
|
||||
body: `
|
||||
{
|
||||
"code": 404,
|
||||
"message": "The requested resource wasn't found.",
|
||||
"data": {}
|
||||
}
|
||||
`,
|
||||
});
|
||||
}
|
||||
|
||||
$: sdkExamples = [
|
||||
{
|
||||
lang: "JavaScript",
|
||||
code: `
|
||||
import PocketBase from 'pocketbase';
|
||||
|
||||
const client = new PocketBase("${ApiClient.baseUrl}");
|
||||
|
||||
client.Records.getOne("${collection?.name}", "RECORD_ID")
|
||||
.then(function (record) {
|
||||
// success...
|
||||
}).catch(function (error) {
|
||||
// error...
|
||||
});
|
||||
`,
|
||||
},
|
||||
];
|
||||
</script>
|
||||
|
||||
<div class="alert alert-info">
|
||||
<strong class="label label-primary">GET</strong>
|
||||
<div class="content">
|
||||
<p>
|
||||
/api/collections/<strong>{collection.name}</strong>/records/<strong>:id</strong>
|
||||
</p>
|
||||
</div>
|
||||
{#if adminsOnly}
|
||||
<p class="txt-hint txt-sm txt-right">Requires <code>Authorization: Admin TOKEN</code> header</p>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<div class="content m-b-base">
|
||||
<p>Fetch a single <strong>{collection.name}</strong> record.</p>
|
||||
</div>
|
||||
|
||||
<div class="section-title">Client SDKs example</div>
|
||||
<div class="tabs m-b-lg">
|
||||
<div class="tabs-header compact left">
|
||||
{#each sdkExamples as example (example.lang)}
|
||||
<button
|
||||
class="tab-item"
|
||||
class:active={sdkTab === example.lang}
|
||||
on:click={() => (sdkTab = example.lang)}
|
||||
>
|
||||
{example.lang}
|
||||
</button>
|
||||
{/each}
|
||||
</div>
|
||||
<div class="tabs-content">
|
||||
{#each sdkExamples as example (example.lang)}
|
||||
<div class="tab-item" class:active={sdkTab === example.lang}>
|
||||
<CodeBlock content={example.code} />
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="section-title">Path Parameters</div>
|
||||
<table class="table-compact table-border m-b-lg">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Param</th>
|
||||
<th>Type</th>
|
||||
<th width="60%">Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>id</td>
|
||||
<td>
|
||||
<span class="label">String</span>
|
||||
</td>
|
||||
<td>ID of the record to view.</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<div class="section-title">Query parameters</div>
|
||||
<table class="table-compact table-border m-b-lg">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Param</th>
|
||||
<th>Type</th>
|
||||
<th width="60%">Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>expand</td>
|
||||
<td>
|
||||
<span class="label">String</span>
|
||||
</td>
|
||||
<td>
|
||||
Auto expand nested record relations. Ex.:
|
||||
<CodeBlock
|
||||
content={`
|
||||
?expand=rel1,rel2.subrel21.subrel22
|
||||
`}
|
||||
/>
|
||||
Supports up to 6-levels depth nested relations expansion. <br />
|
||||
The expanded relations will be appended to the record under the
|
||||
<code>@expand</code> property (eg. <code>{`"@expand": {"rel1": {...}, ...}`}</code>).
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<div class="section-title">Responses</div>
|
||||
<div class="tabs">
|
||||
<div class="tabs-header compact left">
|
||||
{#each responses as response (response.code)}
|
||||
<button
|
||||
class="tab-item"
|
||||
class:active={responseTab === response.code}
|
||||
on:click={() => (responseTab = response.code)}
|
||||
>
|
||||
{response.code}
|
||||
</button>
|
||||
{/each}
|
||||
</div>
|
||||
<div class="tabs-content">
|
||||
{#each responses as response (response.code)}
|
||||
<div class="tab-item" class:active={responseTab === response.code}>
|
||||
<CodeBlock content={response.body} />
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
Reference in New Issue
Block a user