# Client

## Setting Up for Client Requests

This section shows how to connect to PPDRIVE in client mode. Before you start, please make sure a PPDRIVE service is running in [Client Mode](/ppdrive/starter-guide.md#auth-mode) and you have the `ID` of the service. You can check running services with `ppdrive list` command and see `Auth-modes` column:

Once you confirm that a service is running in client mode and you have its `ID`, follow these steps:

{% stepper %}
{% step %}

### Create a new client for the service

```sh
ppdrive client create --svc-id [ID] --name [client_name]
```

* `svc-id` is self-explanatory.
* `name` is the name assigned to your client. Hint: Use a name you can easily associate with the client, e.g., "Raymond Edutech App". `name` is required but **not unique**.

If the client is successfully created, the client's `id` and secret `token` will be printed like this:
{% endstep %}

{% step %}

### Save the token securely

After the client is created, copy and save the token **securely** in your client application — TOKENS MUST BE KEPT SECRET! Do not expose your client token to public APIs. For example, you may save it in your environment variables:

```sh
PPD_TOKEN=74352d4a4df...
```

If you think your token is compromised, refresh it with:

```sh
ppdrive client refresh --svc-id [ID] --client-id [ID]
```

{% endstep %}

{% step %}

### Send requests with the client token

Add the token to the `ppd-client-token` header and send requests to the available endpoints.

```js
const ppdToken = process.env.PPD_TOKEN;
const baseUrl = "0.0.0.0:5000" // or whatever location PPDRIVE is running from.

const resp = await fetch(`${baseUrl}/client/user`, {
    headers: {
        'Content-Type': 'application/json',
        'ppd-client-token': ppdToken
    }
})
```

{% endstep %}
{% endstepper %}

***

## API Endpoints

This section documents **currently available** endpoints on PPDRIVE client mode. The endpoints can be categorized into two:

1. [Client Handlers](#1-client-handlers): Endpoints used by the client to perform administrative tasks such as user authentication, user management, asset assignment, etc. When sending requests to these endpoints, ensure you provide the client's token via the `ppd-client-token` request header.
2. [Client User Handlers](#2-client-user-handlers): Endpoints used by clients to operate on behalf of a specific user and simulate some kind of "passwordless" authorization. To access protected resources, provide a client token and user ID via `ppd-client-token` and `ppd-client-user` respectively.

***

## 1. Client Handlers

<details>

<summary><strong>User Registration</strong></summary>

**Endpoint:** /client/user/register

**Description:** Registers a new user for a client.

**Method:** POST

**Headers:**

* `ppd-client-token` (*string*): The client's token

**Body:**

* `max_bucket`:

  * required: `false`
  * type: `float64`
  * description: Total size of buckets the user can create in megabytes (MB). This is the total accumulated size, which means the user can create as many buckets as possible as long as the total size of all the buckets combined doesn't exceed this size. To put simply, this is **total filesize** this user can upload.

  When the option is not specified, user can create unlimited number of buckets and in turn, unlimited files.

**Response:**

* type: `String`
* description: Public ID (UUID) of the user created.

**Example:**

```kt
const resp = await fetch(`${baseUrl}/client/user/register`, {
    method: 'POST',
    headers: {
        'Content-Type': 'application/json',
        'ppd-client-token': ppdToken
    },
    body: JSON.stringify({
      max_bucket: 10.0 // 10MB space assigned to the user
    })
})

console.log(resp.data) // 5c4699dc-476a-4133-af65-b799c09abb67
```

</details>

<details>

<summary><strong>User Login</strong></summary>

**Endpoint:** /client/user/login

**Description:** Authenticate a user with the given `id` and return authorization tokens. This endpoint is *mostly* useful when your users access PPDRIVE directly from the client side of your application. The returned auth token (JWT) can be added to `authorization` header in order to access "protected" routes directly.

**Method:** POST

**Headers:**

* `ppd-client-token` (*string*): The client's token

**Body:**

* `id`:
  * required: `true`
  * type: `String`
  * description: ID of the user to authenticate. The ID is returned when a [client registers new user](#user-registration).
* `access_exp`:
  * required: `false`
  * type: `unsigned64`
  * description: How long it should take for returned `access` token to expire (in seconds).
* `refresh_exp`:
  * required: `false`
  * type: `unsigned64`
  * description: How long it should take for returned `refresh` token to expire (in seconds).

**Response:**

* type: `Object`
  * `access`:
    * type: \[`String`, `unsigned64`]
    * description: A 2-length-array where the `first` element is access token and the `second` element is access token expiration in seconds.
  * `refresh`:
    * type: \[`String`, `unsigned64`]
    * description: A 2-length-array where the `first` element is refresh token and the `second` element is refresh token expiration in seconds.

**Example:**

```js
const resp = await fetch(`${baseUrl}/client/user/login`, {
    method: 'POST',
    headers: {
        'Content-Type': 'application/json',
        'ppd-client-token': ppdToken
    },
    body: JSON.stringify({
      id: '5c4699dc-476a-4133-af65-b799c09abb67'
    })
})

console.log(resp.data) 
// {
// "access":["eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzUxMiJ9...",900],
// "refresh":["eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzUxMiJ9...",86400]
// }
```

</details>

<details>

<summary><strong>Delete User</strong></summary>

**Endpoint:** /client/user/:id

**Description:** Deletes user with the given id.

**Method:** DELETE

**Headers:**

* `ppd-client-token` (*string*): The client's token

**Response:**

* type: `String`
* description: A string that indicates the operation is successful.

**Example:**

```js
const resp = await fetch(`${baseUrl}/client/user/5c4699dc-476a-4133-af65-b799c09abb67`, {
    method: 'DELETE',
    headers: {
        'Content-Type': 'application/json',
        'ppd-client-token': ppdToken
    }
})

console.log(resp.data) // operation successful!
```

</details>

<details>

<summary><strong>Create Client's Bucket</strong></summary>

**Endpoint:** /client/bucket

**Description:** Create a [Bucket](/ppdrive/terminologies.md#bucket) for the client.

**Method:** POST

**Headers:**

* `ppd-client-token` (*string*): The client's token

**Body:** Please see [CreateBucketOptions](/ppdrive/common.md#createbucketoptions).

**Response:**

* type: `String`
* description: ID of the bucket that was created.

**Example:**

```js
const resp = await fetch(`${baseUrl}/client/bucket`, {
    method: 'POST',
    headers: {
        'Content-Type': 'application/json',
        'ppd-client-token': ppdToken
    },
    body: JSON.stringify({
      label: 'My Test Bucket'
    })
})

console.log(resp.data) // c7040c69-878c-4ea5-9e44-bd56bce8fd0f
```

</details>

***

## 2. Client User Handlers

<details>

<summary><strong>Get User</strong></summary>

**Endpoint:** /client/user

**Description:** Retrieve information about the user.

**Method:** GET

**Headers:**

* `ppd-client-token` (*string*): The client's token.
* `ppd-client-user` (*string*): The user's ID.

**Response:**

* type: `String`
* description: Public ID (UUID) of the user created.

**Example:**

```js
const resp = await fetch(`${baseUrl}/client/user`, {
    method: 'POST',
    headers: {
        'Content-Type': 'application/json',
        'ppd-client-token': ppdToken,
        'ppd-client-user': 'USER-ID-HERE'
    },
    body: JSON.stringify({
      max_bucket: 10.0 // 10MB space assigned to the user
    })
})

console.log(resp.data) // 5c4699dc-476a-4133-af65-b799c09abb67
```

</details>

<details>

<summary><strong>Create Asset</strong></summary>

**Endpoint:** /client/user/asset

**Description:** Create an [Asset](/ppdrive/terminologies.md#asset). Use this endpoint to upload a file or create a folder.

**Method:** POST

**Headers:**

* `ppd-client-token` (*string*): The client's token.
* `ppd-client-user` (*string*): The user's ID.

**Body:**

* `multipart`:
  * `file`:
    * required: `false`
    * type: `File`
    * description: An optional field that holds the file object to be uploaded. This field is required only if `options.asset_type` (see below) is `File`. Without it, the request will fail.
  * `options`:
    * required: `true`
    * type: `Object`
    * description: Specify options for creating the asset.
      * `asset_path`:
        * required: `true`
        * type: `String`
        * description: Destination path where asset should be created or uploaded.
      * `asset_type`:
        * required: `true`
        * type: `Enum` (acceptable values: `File` | `Folder`)
        * description: The type of asset - whether it's a file or folder.
      * `bucket`:
        * required: `true`
        * type: `String`
        * description: The public ID of the bucket in which to save the asset.
      * `public`:
        * required: `false`
        * type: `Bool`
        * description: Asset's visibility. If true, asset can be read/accessed by everyone. Else, asset can be viewed ONLY by permission.
      * `slug`:
        * required: `false`
        * type: `String`
        * description: Set a custom URL slug for your asset instead of the one auto-generated from `asset_path`. This is useful if you'd like to conceal your original asset path and make it less predictable. Custom slug must be unique in that no other asset in the entire PPDRIVE instance is already using it.

          Your original asset slug makes url look like this `https://mydrive.com/images/somewhere/my-image.png/`. Using custom slug, you can conceal the original path: `https://mydrive.com/some/hidden-path`.
      * `create_parents`:
        * required: `false`
        * type: `Bool`
        * description: Create asset's parent folders if they don't already exist. The endpoint will return an error if `create_parents` is `false` and folder parents don't exist.
      * `sharing`:
        * required: `false`
        * type: `Array`
        * description: Determine whether to share asset with other users. This is mostly useful for private assets.
      * `overwrite`:
        * required: `false`
        * type: `Bool`
        * description: Overwrite existing asset.

**Response:**

* type: `String`
* description: URL path of the asset created.

**Example:**

```js
const file = new File() // retrieve file object
const formData = new FormData();
formData.append("file", file)
formData.append("options", JSON.stringify({
  "asset_path": "/user/images/profile-picture.jpg",
  "asset_type": "File",
  "bucket": "c7040c69-878c-4ea5-9e44-bd56bce8fd0f",
  ...
}))

const resp = await fetch(`${baseUrl}/client/bucket`, {
    method: 'POST',
    headers: {
        'Content-Type': 'application/json',
        'ppd-client-token': ppdToken,
        'ppd-client-user': 'USER-ID-HERE'
    },
    body: formData
})

console.log(resp.data) // /user/images/profile-picture.jpg
```

</details>

<details>

<summary><strong>Delete Asset</strong></summary>

**Endpoint:** /client/user/asset?slug={slug}

**Description:** Delete an asset.

* `slug` is the URL path you use for getting the file.

**Method:** DELETE

**Headers:**

* `ppd-client-token` (*string*): The client's token
* `ppd-client-user` (*string*): The user's ID.

**Response:**

* type: `String`
* description: A string that indicates the operation is successful.

**Example:**

```js
const resp = await fetch(`${baseUrl}/client/user?slug=user/images/profile-picture.jpg`, {
    method: 'DELETE',
    headers: {
        'Content-Type': 'application/json',
        'ppd-client-token': ppdToken,
        'ppd-client-user': 'USER-ID-HERE'
    }
})

console.log(resp.data) // operation successful!
```

</details>

<details>

<summary><strong>Create User Bucket</strong></summary>

**Endpoint:** /client/user/bucket

**Description:** Create a [Bucket](/ppdrive/terminologies.md#bucket) for the user.

**Method:** POST

**Headers:**

* `ppd-client-token` (*string*): The client's token.
* `ppd-client-user` (*string*): The user's ID.

**Body:** Please see [CreateBucketOptions](/ppdrive/common.md#createbucketoptions).

**Response:**

* type: `String`
* description: ID of the bucket that was created.

**Example:**

```js
const resp = await fetch(`${baseUrl}/client/bucket`, {
    method: 'POST',
    headers: {
        'Content-Type': 'application/json',
        'ppd-client-token': ppdToken,
        'ppd-client-user': 'USER-ID-HERE'
    },
    body: JSON.stringify({
      label: 'My Test Bucket'
    })
})

console.log(resp.data) // c7040c69-878c-4ea5-9e44-bd56bce8fd0f
```

</details>


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://dududaa.gitbook.io/ppdrive/rest-api/client.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
