# Step 4: Run (Part 1)

## Run Your Local Web Server

Open a terminal window.

### Enter Your Client Credentials

{% hint style="danger" %}
Safeguard your **`Client ID`** and **`Client Secret`** values. Do not share these with any third parties as anyone with your **`Client ID`** and **`Client Secret`** values can impersonate you and act fully on your behalf.
{% endhint %}

Export your registered client credentials (see the [Prerequisites](/sdk/java-sdk/tutorial/prerequisites.md)) as environment variables.

1\. Identity Provider (the IDP with whom you registered your application):

```sh
read -s MY_SOLID_IDP && export MY_SOLID_IDP
```

Enter `https://login.inrupt.com`

2\. Client ID:

```sh
read -s MY_SOLID_CLIENT_ID && export MY_SOLID_CLIENT_ID
```

Enter your Client ID.

3\. Client Secret:

```sh
read -s MY_SOLID_CLIENT_SECRET && export MY_SOLID_CLIENT_SECRET
```

Enter your Client Secret.

4\. Authentication Flow Method:

```sh
read -s MY_AUTH_FLOW && export MY_AUTH_FLOW
```

Enter `client_secret_basic`

### Run the Application

Once you have entered your client credentials, start your application. From your project ( `getting-started/` ) directory, run your Spring Boot application:

* For Java, this tutorial assumes a Spring Boot Web Maven Project.
* For Kotlin, this tutorial assumes a Spring Boot Web Gradle Project.

{% tabs %}
{% tab title="Java" %}

```sh
./mvnw spring-boot:run
```

{% endtab %}

{% tab title="Kotlin" %}

```sh
./gradlew bootRun
```

{% endtab %}
{% endtabs %}

Your Web service runs on `http://localhost:8080` .

{% hint style="info" %}
Reminder\
The application is running **as** you, the user who registered it.
{% endhint %}

## Test the Service

Open another terminal window. To test, call the various endpoints defined in the **`ExpenseController`** class:

<table><thead><tr><th width="223.58984375">Endpoint</th><th>Description</th></tr></thead><tbody><tr><td><strong><code>/api/pods</code></strong></td><td>Gets Pod URL(s) from the WebID Profile.</td></tr><tr><td><strong><code>/api/expenses/create</code></strong></td><td>Saves an Expense object as a new RDF resource. Returns the saved Expense object.</td></tr><tr><td><strong><code>/api/expenses/get</code></strong></td><td>Reads an RDF resource as an Expense object. Returns the Expense object.</td></tr><tr><td><strong><code>/api/expenses/update</code></strong></td><td><p>Saves an Expense object as an RDF resource.</p><ul><li>If a resource already exists, overwrites the existing resource.</li><li>If no resource exists, creates a new resource.</li></ul><p>Returns the saved Expense object.</p></td></tr><tr><td><strong><code>/api/expenses/delete</code></strong></td><td>Deletes an Expense resource (i.e., the RDF resource associated with the <strong><code>Expense</code></strong>).</td></tr></tbody></table>

For simplicity, the calls to the Web Server uses **`curl`** . However, you can access the endpoints from your front-end app as well.

### Get Pod URL

To find your Pod URL, issue the following **`curl`** command, substituting your WebID (e.g., **`https://id.inrupt.com/yourUserName`** ):

```sh
curl -X GET http://localhost:8080/api/pods\?webid\=SUBSTITUTE_YOUR_WEBID
```

Upon success, the operation should return an array with your Pod Root URL; for example:

```sh
["https://storage.inrupt.com/your-root-container/"]
```

Since the application is running as you, it should have access to your Pod for the following CRUD operations.

{% hint style="info" %}
Note\
In the following CRUD operations, substitue **`your-root-container`** with the value of your root container.
{% endhint %}

### Create an Expense Record

To create an expense record as an RDF resource on your Pod at **`https://storage.inrupt.com/your-root-container/expenses/20230315/expense1`** , issue the following **`curl`** command, <mark style="color:red;">**substituting**</mark> your root container in the request body:

<pre class="language-sh"><code class="lang-sh">curl -X POST http://localhost:8080/api/expenses/create \
   -H 'Content-type:application/json'  \
   -d '{
<strong>      "identifier": "https://storage.inrupt.com/your-root-container/expenses/20230315/expense1",
</strong>      "merchantProvider": "Example Restaurant",
      "description": "Team Lunch",
      "expenseDate": "2023-03-06",
      "amount": 100,
      "currency": "USD",
      "category": "Travel &#x26; Entertainment" }'
</code></pre>

{% hint style="info" %}
Tip

* If you encounter a `ForbiddenException` , double check that you have substituted `your-root-container` in the command.
* If you encounter a `PreconditionFailedException` , check that the resource does not already exist at the the specified identifier. The `.create()` operation errors with `PreconditionFailedException` if a resource already exists.
  {% endhint %}

Upon success, the operation returns the created Expense object:

```json
{
    "identifier": "https://storage.inrupt.com/your-root-container/expenses/20230315/expense1",
    "merchantProvider": "Example Restaurant",
    "expenseDate": "2023-03-06T00:00:00.000+00:00",
    "description": "Team Lunch",
    "amount": 100,
    "currency": "USD",
    "category": "Travel & Entertainment",
    "rdftype": "https://schema.org/Invoice"
}
```

For illustrative purposes, the server also prints out the content of the resource, formatted in Turtle:

```turtle
<https://storage.inrupt.com/your-root-container/expenses/20230315/expense1>
        a                              <https://schema.org/Invoice> ;
        <https://schema.org/purchaseDate>  "2023-03-06T00:00:00Z"^^<http://www.w3.org/2001/XMLSchema#dateTime> ;
        <https://schema.org/category>  "Travel & Entertainment" ;
        <https://schema.org/description>
                "Team Lunch" ;
        <https://schema.org/priceCurrency>
                "USD" ;
        <https://schema.org/provider>  "Example Restaurant" ;
        <https://schema.org/totalPrice>
                "100"^^<http://www.w3.org/2001/XMLSchema#decimal> .
```

See also [CRUD Module](/sdk/java-sdk/crud-data.md).

### Read the Expense RDF Resource

To read the content at **`https://storage.inrupt.com/your-root-container/expenses/20230315/expense1`** , map it to the **`Expense`** class and return it serialized as a JSON, issue the following **`curl`** command, <mark style="color:red;">**substituting**</mark> your your root container :

```sh
curl -X GET http://localhost:8080/api/expenses/get\?resourceURL\=https://storage.inrupt.com/your-root-container/expenses/20230315/expense1
```

{% hint style="info" %}
Tip\
If you encounter an `HTTP 403 Forbidden` error, double check that you have substituted `your-root-container` in the command.
{% endhint %}

Upon success, the operation should return the contents as JSON:

```json
{"identifier":"https://storage.inrupt.com/your-root-container/expenses/20230315/expense1","merchantProvider":"Example Restaurant","expenseDate":"2023-03-06T00:00:00.000+00:00","description":"Team Lunch","amount":100,"currency":"USD","category":"Travel & Entertainment","rdftype":"https://schema.org/Invoice"}
```

See also [CRUD Module](/sdk/java-sdk/crud-data.md).

### Update the Expense RDF Resource

To update the content at **`https://storage.inrupt.com/your-root-container/expenses/20230315/expense1`** , issue the following **`curl`** command, <mark style="color:red;">**substituting**</mark> your your root container in the request body (the **`expenseDate`** field has changed):

<pre class="language-sh"><code class="lang-sh">
curl -X PUT http://localhost:8080/api/expenses/update \
   -H 'Content-type:application/json'  \
   -d '{
<strong>      "identifier": "https://storage.inrupt.com/your-root-container/expenses/20230315/expense1",
</strong>      "merchantProvider": "Example Restaurant",
      "description": "Team Lunch",
      "expenseDate": "2023-03-15",
      "amount": 100,
      "currency": "USD",
      "category": "Travel &#x26; Entertainment" }'
</code></pre>

{% hint style="info" %}
Tip\
If you encounter an `HTTP 403 Forbidden` error, double check that you have substituted `your-root-container` in the command.
{% endhint %}

Upon success, the operation should return the updated Expense object as JSON (as well as print out, on the server-side, the content formatted in Turtle):

{% tabs %}
{% tab title="Returned Expense Object" %}

```json
{
    "identifier": "https://storage.inrupt.com/your-root-container/expenses/20230315/expense1",
    "merchantProvider": "Example Restaurant",
    "expenseDate": "2023-03-15T00:00:00.000+00:00",
    "description": "Team Lunch",
    "amount": 100,
    "currency": "USD",
    "category": "Travel & Entertainment",
    "rdftype": "https://schema.org/Invoice"
}
```

{% endtab %}

{% tab title="Content Formatted as Turtle" %}

```turtle
<https://storage.inrupt.com/your-root-container/expenses/20230315/expense1>
     a                              <https://schema.org/Invoice> ;
     <https://schema.org/purchaseDate>
             "2023-03-15T00:00:00Z"^^<http://www.w3.org/2001/XMLSchema#dateTime> ;
     <https://schema.org/category>  "Travel & Entertainment" ;
     <https://schema.org/description>
             "Team Lunch" ;
     <https://schema.org/priceCurrency>
             "USD" ;
     <https://schema.org/provider>  "Example Restaurant" ;
     <https://schema.org/totalPrice>
             "100"^^<http://www.w3.org/2001/XMLSchema#decimal> .
```

{% endtab %}
{% endtabs %}

Unlike the **`POST`** request to **`http://localhost:8080/api/expenses/create`** (which uses the **`.create()`** method), the **`PUT`** request to **`http://localhost:8080/api/expenses/update`** (which uses the **`.update()`** method) can either:

* Update an existing resource, or
* Create a new resource if it does not exists.

For example, issue the following **`PUT`** request to the **`api/expenses/update`** endpoint to create another expense resource, <mark style="color:red;">**substitute**</mark> your root container:

<pre class="language-sh"><code class="lang-sh">curl -X PUT http://localhost:8080/api/expenses/update \
   -H 'Content-type:application/json'  \
   -d '{
<strong>      "identifier": "https://storage.inrupt.com/your-root-container/expenses/20230315/expense2",
</strong><strong>      "merchantProvider": "Example Supply Store",
</strong>      "description": "Monitor",
      "expenseDate": "2023-03-15",
      "amount": 300,
      "currency": "USD",
      "category": "Office Equipment &#x26; Supplies" }'
</code></pre>

Upon success, the operation should return the created Expense object as JSON (as well as print out, on the server-side, the content formatted in Turtle):

{% tabs %}
{% tab title="Returned Expense Object" %}

```json
{
    "identifier": "https://storage.inrupt.com/your-root-container/expenses/20230315/expense2",
    "merchantProvider": "Example Supply Store",
    "expenseDate": "2023-03-15T00:00:00.000+00:00",
    "description": "Monitor",
    "amount": 300,
    "currency": "USD",
    "category": "Office Equipment & Supplies",
    "rdftype": "https://schema.org/Invoice"
}
```

{% endtab %}

{% tab title="Content Formatted as Turtle" %}

```turtle
<https://storage.inrupt.com/your-root-container/expenses/20230315/expense2>
     a                              <https://schema.org/Invoice> ;
     <https://schema.org/purchaseDate>
             "2023-03-15T00:00:00Z"^^<http://www.w3.org/2001/XMLSchema#dateTime> ;
     <https://schema.org/category>  "Office Equipment & Supplies" ;
     <https://schema.org/description>
             "Monitor" ;
     <https://schema.org/priceCurrency>
             "USD" ;
     <https://schema.org/provider>  "Example Supply Store" ;
     <https://schema.org/totalPrice>
             "300"^^<http://www.w3.org/2001/XMLSchema#decimal> .
```

{% endtab %}
{% endtabs %}

See also [CRUD Module](/sdk/java-sdk/crud-data.md).

### Delete the Expense RDF Resource

To delete the resource from your Pod, issue the following **`DELETE`** request, <mark style="color:red;">**substituting**</mark> your root container :

```sh
curl -X DELETE http://localhost:8080/api/expenses/delete\?resourceURL\=https://storage.inrupt.com/your-root-container/expenses/20230315/expense2
```

{% hint style="info" %}
Tip\
If you encounter a **`ForbiddenException`** , double check that you have substituted **`your-root-container`** in the command.
{% endhint %}

To verify, issue a **`GET`** request to the **`http://localhost:8080/api/expenses/get`** endpoint:

```sh
curl -X GET http://localhost:8080/api/expenses/get\?resourceURL\=https://storage.inrupt.com/your-root-container/expenses/20230315/expense2
```

The operation should error with a **`NotFoundException`** .

See also [CRUD Module](/sdk/java-sdk/crud-data.md).


---

# 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://docs.inrupt.com/sdk/java-sdk/tutorial/step4.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.
