# 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](https://docs.inrupt.com/sdk/java-sdk/tutorial/prerequisites "mention")) 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-data](https://docs.inrupt.com/sdk/java-sdk/crud-data "mention").

### 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-data](https://docs.inrupt.com/sdk/java-sdk/crud-data "mention").

### 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-data](https://docs.inrupt.com/sdk/java-sdk/crud-data "mention").

### 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-data](https://docs.inrupt.com/sdk/java-sdk/crud-data "mention").
