Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,20 @@
@ConfigurationProperties(prefix = "opensharing")
public class OpenSharingProperties {

/** URL prefix the recipient-facing protocol endpoints are mounted under. */
private String protocolPrefix = "/api/1.0/opensharing";

private final Hosting hosting = new Hosting();
private final Catalog catalog = new Catalog();

public String getProtocolPrefix() {
return protocolPrefix;
}

public void setProtocolPrefix(String protocolPrefix) {
this.protocolPrefix = prefix(protocolPrefix);
}

public Hosting getHosting() {
return hosting;
}
Expand All @@ -17,6 +28,17 @@ public Catalog getCatalog() {
return catalog;
}

/**
* A url prefix without its trailing slash, kept that way here so that everything appending to
* one — a filter's url pattern, an OpenAPI path match, a route the server builds — appends to a
* known shape instead of each trimming first.
*/
private static String prefix(String value) {
return value != null && value.length() > 1 && value.endsWith("/")
? value.substring(0, value.length() - 1)
: value;
}

public static class Hosting {

public enum Mode {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package io.opensharing.http;

import com.fasterxml.jackson.annotation.JsonInclude;
import java.util.List;

/** Paginated list envelope shared by every {@code list} endpoint. */
@JsonInclude(JsonInclude.Include.NON_NULL)
public record ListResponse<T>(List<T> items, String nextPageToken) {

public static <T> ListResponse<T> of(List<T> items) {
return new ListResponse<>(items, null);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package io.opensharing.http;

/**
* Content types the spec requires on successful protocol responses. Both are spelled the way a
* parsed media type renders, so the published API lists each of them once.
*/
public final class ProtocolMediaType {

public static final String JSON_UTF8 = "application/json;charset=utf-8";

private ProtocolMediaType() {}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package io.opensharing.protocol;

import com.fasterxml.jackson.annotation.JsonInclude;
import java.util.Map;

/** A share as returned by {@code GET /shares}. */
@JsonInclude(JsonInclude.Include.NON_NULL)
public record Share(
String name, String id, String displayName, String comment, Map<String, String> properties) {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package io.opensharing.serving;

import io.opensharing.http.ListResponse;
import io.opensharing.http.ProtocolMediaType;
import io.opensharing.protocol.Share;
import java.util.List;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/** Recipient-facing {@code GET /shares}. Persistence and recipient auth come in later slices. */
@RestController
@RequestMapping(
value = "${opensharing.protocol-prefix}/shares",
produces = ProtocolMediaType.JSON_UTF8)
public class SharesController {

@GetMapping
public ListResponse<Share> listShares() {
return ListResponse.of(List.of());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package io.opensharing.serving;

import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

import io.opensharing.http.ProtocolMediaType;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.web.servlet.MockMvc;

@SpringBootTest(
properties = {
"spring.datasource.url=jdbc:h2:mem:list-shares;DB_CLOSE_DELAY=-1",
"opensharing.catalog.type=local",
"opensharing.catalog.local.file=classpath:local-catalog.yml"
})
@AutoConfigureMockMvc
class SharesControllerTest {

@Autowired private MockMvc mvc;

@Test
void listsNoSharesUntilShareStorageExists() throws Exception {
mvc.perform(get("/api/1.0/opensharing/shares"))
.andExpect(status().isOk())
.andExpect(content().contentType(ProtocolMediaType.JSON_UTF8))
.andExpect(jsonPath("$.items").isEmpty());
}
}
Loading