Step 3: ExpenseController Class#
For the WebService in this tutorial, the ExpenseController
defines
the endpoints for the various Read and Write (CRUD) operations.
Create the ExpenseController
Class#
Tip
Various aspects related to CRUD operations with the Inrupt Client Libraries are noted as comments in the code. For more details, see CRUD.
In the src/main/java/com/example/gettingstarted/
directory,
create ExpenseController.java
file with the content below:
package com.example.gettingstarted;
import com.inrupt.client.Request;
import com.inrupt.client.Response;
import com.inrupt.client.auth.Session;
import com.inrupt.client.openid.OpenIdSession;
import com.inrupt.client.solid.SolidSyncClient;
import com.inrupt.client.webid.WebIdProfile;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.server.ResponseStatusException;
import java.io.PrintWriter;
import java.net.URI;
import java.util.Set;
@RequestMapping("/api")
@RestController
public class ExpenseController {
/**
* Note 1: Authenticated Session
* Using the client credentials, create an authenticated session.
*/
final Session session = OpenIdSession.ofClientCredentials(
URI.create(System.getenv("MY_SOLID_IDP")),
System.getenv("MY_SOLID_CLIENT_ID"),
System.getenv("MY_SOLID_CLIENT_SECRET"),
System.getenv("MY_AUTH_FLOW"));
/**
* Note 2: SolidSyncClient
* Instantiates a synchronous client for the authenticated session.
* The client has methods to perform CRUD operations.
*/
final SolidSyncClient client = SolidSyncClient.getClient().session(session);
private final PrintWriter printWriter = new PrintWriter(System.out, true);
/**
* Note 3: SolidSyncClient.read()
* Using the SolidSyncClient client.read() method, reads the user's WebID Profile document and returns the Pod URI(s).
*/
@GetMapping("/pods")
public Set<URI> getPods(@RequestParam(value = "webid", defaultValue = "") String webID) {
printWriter.println("ExpenseController:: getPods");
try (final var profile = client.read(URI.create(webID), WebIdProfile.class)) {
return profile.getStorage();
}
}
/**
* Note 4: SolidSyncClient.create()
* Using the SolidSyncClient client.create() method,
* - Saves the Expense as an RDF resource to the location specified in the Expense.identifier field.
*/
@PostMapping(path = "/expenses/create")
public String createExpense(@RequestBody Expense newExpense) {
printWriter.println("ExpenseController:: createExpense");
client.create(newExpense);
return getResourceAsTurtle(String.valueOf(newExpense.getIdentifier()));
}
/**
* Note 5: SolidSyncClient.read()
* Using the SolidSyncClient client.read() method,
* - Reads the RDF resource into the Expense class.
*/
@GetMapping("/expenses/get")
public Expense getExpense(@RequestParam(value = "resourceURL", defaultValue = "") String resourceURL) {
printWriter.println("ExpenseController:: getExpense");
try (var resource = client.read(URI.create(resourceURL), Expense.class)) {
return resource;
} catch (Exception e) {
e.printStackTrace();
throw new ResponseStatusException(HttpStatus.NOT_FOUND);
}
}
/**
* Note 6: SolidSyncClient.update()
* Using the SolidSyncClient client.update() method,
* - Updates the Expense resource.
*/
@PutMapping("/expenses/update")
public String updateExpense(@RequestBody Expense expense) {
printWriter.println("ExpenseController:: updateExpense");
client.update(expense);
return getResourceAsTurtle(String.valueOf(expense.getIdentifier()));
}
/**
* Note 7: SolidSyncClient.delete()
* Using the SolidSyncClient client.delete() method,
* - Deletes the resource located at the resourceURL.
*/
@DeleteMapping("/expenses/delete")
public void deleteExpense(@RequestParam(value = "resourceURL") String resourceURL) {
printWriter.println("ExpenseController:: deleteExpense");
try {
client.delete(URI.create(resourceURL));
// Alternatively, you can specify an Expense object to the delete method.
// The delete method deletes the Expense recorde located in the Expense.identifier field.
// For example: client.delete(new Expense(URI.create(resourceURL)));
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* Note 8: Build and issue custom GET Request
* - Use Inrupt's Request builder to create a GET Request to get the resource as MIME-type "text/turtle".
* - Use SolidSyncClient.send() to send the Request and return the response body.
*/
@GetMapping("/resource/get")
public String getResourceAsTurtle(@RequestParam(value = "resourceURL", defaultValue = "") String resourceURL) {
Request request = Request.newBuilder()
.uri(URI.create(resourceURL))
.header("Accept", "text/turtle")
.GET()
.build();
Response<String> response = client.send(
request,
Response.BodyHandlers.ofString());
return response.body();
}
}
In the src/main/kotlin/com/example/gettingstarted/
directory, create an ExpenseController.kt
Kotlin class with the
following content:
package com.example.gettingstarted
import com.inrupt.client.Request
import com.inrupt.client.Response
import com.inrupt.client.openid.OpenIdSession
import com.inrupt.client.solid.SolidSyncClient
import com.inrupt.client.webid.WebIdProfile
import org.springframework.http.HttpStatus
import org.springframework.web.bind.annotation.*
import org.springframework.web.server.ResponseStatusException
import java.io.PrintWriter
import java.net.URI
@RequestMapping("/api")
@RestController
class ExpenseController {
/**
* Note 1: Authenticated Session
* Using the client credentials, create an authenticated session.
*/
val session = OpenIdSession.ofClientCredentials(
URI.create(System.getenv("MY_SOLID_IDP")),
System.getenv("MY_SOLID_CLIENT_ID"),
System.getenv("MY_SOLID_CLIENT_SECRET"),
System.getenv("MY_AUTH_FLOW")
)
/**
* Note 2: SolidSyncClient
* Instantiates a synchronous client for the authenticated session.
* The client has methods to perform CRUD operations.
*/
val client = SolidSyncClient.getClient().session(session)
private val printWriter = PrintWriter(System.out, true)
/**
* Note 3: SolidSyncClient.read()
* Using the SolidSyncClient client.read() method, reads the user's WebID Profile document and returns the Pod URI(s).
*/
@GetMapping("/pods")
fun getPods(@RequestParam(value = "webid", defaultValue = "") webID: String): Set<URI> {
printWriter.println("ExpenseController:: getPods")
client.read(URI.create(webID), WebIdProfile::class.java).use { profile -> return profile.storage }
}
/**
* Note 4: SolidSyncClient.create()
* Using the SolidSyncClient client.create() method,
* - Saves the Expense as an RDF resource to the location specified in the Expense.identifier field.
*/
@PostMapping("/expenses/create")
fun createExpense(@RequestBody newExpense: Expense): String {
printWriter.println("ExpenseController:: createExpense")
client.create(newExpense)
return getResourceAsTurtle(newExpense.identifier.toString())
}
/**
* Note 5: SolidSyncClient.read()
* Using the SolidSyncClient client.read() method,
* - Reads the RDF resource into the Expense class.
*/
@GetMapping("/expenses/get")
fun getExpense(
@RequestParam(
value = "resourceURL", defaultValue = ""
) resourceURL: String
): Expense {
printWriter.println("ExpenseController:: getExpense")
try {
client.read(
URI.create(resourceURL), Expense::class.java
).use { resource -> return resource }
} catch (e: Exception) {
e.printStackTrace()
throw ResponseStatusException(HttpStatus.NOT_FOUND)
}
}
/**
* Note 6: SolidSyncClient.update()
* Using the SolidSyncClient client.update() method,
* - Updates the Expense resource.
*/
@PutMapping("/expenses/update")
fun updateExpense(@RequestBody expense: Expense): String {
printWriter.println("ExpenseController:: updateExpense")
client.update(expense)
return getResourceAsTurtle(expense.identifier.toString())
}
/**
* Note 7: SolidSyncClient.delete()
* Using the SolidSyncClient client.delete() method,
* - Deletes the resource located at the resourceURL.
*/
@DeleteMapping("/expenses/delete")
fun deleteExpense(@RequestParam(value = "resourceURL") resourceURL: String) {
printWriter.println("ExpenseController:: deleteExpense")
try {
client.delete(URI.create(resourceURL))
// Alternatively, you can specify an Expense object to the delete method.
// The delete method deletes the Expense recorde located in the Expense.identifier field.
// For example: client.delete(new Expense(URI.create(resourceURL)));
} catch (e: Exception) {
e.printStackTrace()
}
}
/**
* Note 8: Build and issue custom GET Request
* - Use Inrupt's Request builder to create a GET Request to get the resource as MIME-type "text/turtle".
* - Use SolidSyncClient.send() to send the Request and return the response body.
*/
@GetMapping("/resource/get")
fun getResourceAsTurtle(
@RequestParam(
value = "resourceURL", defaultValue = ""
) resourceURL: String
): String {
val request = Request.newBuilder().uri(URI.create(resourceURL)).header("Accept", "text/turtle").GET().build()
val response = client.send(
request, Response.BodyHandlers.ofString()
)
return response.body()
}
}