Skip to content

Commit

Permalink
[API] some refactors
Browse files Browse the repository at this point in the history
  • Loading branch information
andrzejo committed Feb 28, 2024
1 parent 3d7b1cd commit 20e8805
Show file tree
Hide file tree
Showing 7 changed files with 167 additions and 70 deletions.
18 changes: 15 additions & 3 deletions src/main/java/pl/andrzejo/aspm/api/ApiIndex.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,14 @@
import pl.andrzejo.aspm.App;
import pl.andrzejo.aspm.utils.AppFiles;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static org.apache.commons.lang.StringUtils.trimToEmpty;
import static org.apache.commons.lang.text.StrSubstitutor.replace;

public class ApiIndex {
Expand All @@ -32,11 +35,18 @@ public String getHtml(List<AppApiService.Endpoint> endpoints) {
map.put("APP", App.Name);
map.put("VERSION", App.Version.getVer());
map.put("VERSION_DATE", App.Version.getDate());
map.put("BUILD_YEAR", getYear(App.Version.getDate()));
map.put("URL", App.GitHubUrl);
map.put("ENDPOINTS", endpointsHtml);
return replace(html, map);
}

private String getYear(String date) {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
LocalDateTime dateTime = LocalDateTime.parse(date, formatter);
return String.valueOf(dateTime.getYear());
}

private String getEndpointsHtml(List<AppApiService.Endpoint> endpoints) {
return endpoints.stream().map(this::getEndpointHtml).collect(Collectors.joining());
}
Expand All @@ -53,10 +63,12 @@ private Map<String, String> getReplacements(AppApiService.Endpoint endpoint) {
String href = SimpleHttpServer.getAddress() + suffix;
map.put("HREF", href);
map.put("PATH", suffix);
map.put("DESC", endpoint.getDesc());
AppApiService.EndpointDescription description = endpoint.getDescription();
map.put("DESC", trimToEmpty(description.getDesc()));
map.put("QUERY", trimToEmpty(description.getQueryParams()));
String curl = "curl -X " + endpoint.getMethod().name().toUpperCase() + " " + href;
if (endpoint.getMethod() != SimpleHttpServer.Method.Get && endpoint.getBodyExample() != null) {
curl += String.format(" -d '%s' ", endpoint.getBodyExample());
if (endpoint.getMethod() != SimpleHttpServer.Method.Get && description.getBodyExample() != null) {
curl += String.format(" -d '%s' ", description.getBodyExample());
}
map.put("CMD", curl);
return map;
Expand Down
187 changes: 141 additions & 46 deletions src/main/java/pl/andrzejo/aspm/api/AppApiService.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
package pl.andrzejo.aspm.api;

import org.apache.commons.lang.BooleanUtils;
import org.apache.commons.lang.StringUtils;
import pl.andrzejo.aspm.eventbus.ApplicationEventBus;
import pl.andrzejo.aspm.eventbus.events.api.commands.ApiCloseDeviceEvent;
import pl.andrzejo.aspm.eventbus.events.api.commands.ApiExecuteCommand;
Expand All @@ -18,13 +19,13 @@
import pl.andrzejo.aspm.serial.SerialPorts;
import pl.andrzejo.aspm.service.SerialHandlerService;
import pl.andrzejo.aspm.utils.OsInfo;
import pl.andrzejo.aspm.utils.StrUtil;

import java.util.ArrayList;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;

import static org.apache.commons.lang.StringUtils.contains;
import static pl.andrzejo.aspm.api.SimpleHttpServer.Method.Get;
import static pl.andrzejo.aspm.api.SimpleHttpServer.Method.Post;
import static pl.andrzejo.aspm.factory.BeanFactory.instance;
Expand All @@ -45,17 +46,66 @@ public static String getRootEndpointAddress() {

public void start() {
SimpleHttpServer server = instance(SimpleHttpServer.class);
setupEndpoint(server, Post, "/api/device/open", this::handleOpen,
"Open device. Specify device in request body. If device is not specified opens first selected.",
getBodyExample());
setupEndpoint(server, Post, "/api/device/close", this::handleClose, "Close device.");
setupEndpoint(server, Get, "/api/device/status", this::handleStatus, "Get device status.");
setupEndpoint(server, Get, "/api/device/list", this::handleDevices, "Get available devices.");
builder()
.method(Post)
.path("/api/device/open")
.handler(this::handleOpen)
.description("Open device. Specify device in request body. If device is not specified opens first selected.")
.bodyExample(getBodyExample())
.build(server);

builder()
.method(Post)
.path("/api/device/close")
.handler(this::handleClose)
.description("Close device.")
.build(server);

builder()
.method(Post)
.path("/api/device/status")
.handler(this::handleStatus)
.description("Get device status.")
.build(server);

builder()
.method(Get)
.path("/api/device/list")
.handler(this::handleDevices)
.description("Get available devices.")
.build(server);

builder()
.method(Get)
.path("/api/window/focus")
.handler(this::handleWindowFocus)
.description("Bring app window to top.")
.build(server);

builder()
.method(Post)
.path("/api/monitor/clear")
.handler(this::handleMonitorOutputClear)
.description("Clear monitor output.")
.build(server);

builder()
.method(Get)
.path("/api/monitor/output")
.handler(this::handleGetMonitorOutput)
.description("Get monitor output.")
.queryParams("with_messages")
.build(server);

builder()
.method(Get)
.handler(this::handleRoot)
.description("Get endpoints.")
.build(server);
}

setupEndpoint(server, Post, "/api/window/focus", this::handleWindowFocus, "Bring app window to top.");
setupEndpoint(server, Post, "/api/monitor/clear", this::handleMonitorOutputClear, "Clear monitor output.");
setupEndpoint(server, Get, "/api/monitor/output", this::handleGetMonitorOutput, "Get monitor output. Optional add ?with_messages parameters for full output.");
setupEndpoint(server, Get, null, this::handleRoot, "Get endpoints.");
private Builder builder() {
return new Builder();
}

private static String getBodyExample() {
Expand All @@ -65,29 +115,6 @@ private static String getBodyExample() {
return "/dev/ttyUSB0";
}

private void setupEndpoint(SimpleHttpServer server,
SimpleHttpServer.Method method,
String path,
Function<Request, String> handler,
String desc,
String bodyExample) {
endpoints.add(new Endpoint(method, path, desc, bodyExample));
server.addEndpoint(method, path, (request) -> {
if (method == Post) {
eventBus.post(new ApiExecuteCommand(path, request.getBody()));
}
return handler.apply(request);
});
}

private void setupEndpoint(SimpleHttpServer server,
SimpleHttpServer.Method method,
String path,
Function<Request, String> handler,
String desc) {
setupEndpoint(server, method, path, handler, desc, null);
}

private String handleRoot(Request request) {
return apiIndex.getHtml(endpoints);
}
Expand All @@ -98,7 +125,7 @@ private String handleMonitorOutputClear(Request request) {
}

private String handleGetMonitorOutput(Request request) {
boolean withMessages = StrUtil.contains(request.getRequestURI().getQuery(), "with_messages");
boolean withMessages = contains(request.getRequestURI().getQuery(), "with_messages");
List<Object> objects = eventBus.postForResult(new GetMonitorOutputEvent(withMessages));
return objects.stream().map(Object::toString).collect(Collectors.joining());
}
Expand Down Expand Up @@ -128,33 +155,101 @@ private String handleDevices(Request request) {
return String.join("\n", list);
}

public static class Endpoint {
private final String path;
public static class EndpointDescription {
private final String desc;
private final String bodyExample;

public String getQueryParams() {
return queryParams;
}

public String getBodyExample() {
return bodyExample;
}

public String getDesc() {
return desc;
}

private final String queryParams;

public EndpointDescription(String desc, String bodyExample, String queryParams) {
this.desc = desc;
this.bodyExample = bodyExample;
this.queryParams = queryParams;
}
}

public static class Endpoint {
private final String path;
private final EndpointDescription description;
private final SimpleHttpServer.Method method;

public Endpoint(SimpleHttpServer.Method method, String path, String desc, String bodyExample) {
public Endpoint(SimpleHttpServer.Method method, String path, EndpointDescription description) {
this.method = method;
this.path = path;
this.desc = desc;
this.bodyExample = bodyExample;
this.description = description;
}

public String getPath() {
return path;
}

public String getDesc() {
return desc;
}

public SimpleHttpServer.Method getMethod() {
return method;
}

public String getBodyExample() {
return bodyExample;
public EndpointDescription getDescription() {
return description;
}
}

private class Builder {
private String path;
private SimpleHttpServer.Method method;
private String description;
private String bodyExample;
private String queryParams;
private Function<Request, String> handler;

public Builder path(String path) {
this.path = path;
return this;
}

public Builder method(SimpleHttpServer.Method method) {
this.method = method;
return this;
}

public Builder handler(Function<Request, String> handler) {
this.handler = handler;
return this;
}

public Builder description(String description) {
this.description = description;
return this;
}

public Builder bodyExample(String bodyExample) {
this.bodyExample = bodyExample;
return this;
}

public Builder queryParams(String queryParams) {
this.queryParams = queryParams;
return this;
}

public void build(SimpleHttpServer server) {
endpoints.add(new Endpoint(method, path, new EndpointDescription(description, bodyExample, queryParams)));
server.addEndpoint(method, path, (request) -> {
if (method == Post) {
eventBus.post(new ApiExecuteCommand(path, request.getBody()));
}
return handler.apply(request);
});
}
}
}
17 changes: 0 additions & 17 deletions src/main/java/pl/andrzejo/aspm/utils/StrUtil.java

This file was deleted.

7 changes: 6 additions & 1 deletion src/main/resources/api/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@
width: 200px;
}

.query {
width: 200px;
}

.desc {
width: 450px;
}
Expand Down Expand Up @@ -111,14 +115,15 @@ <h3> API endpoints:</h3>
<div class="header">
<div class="method">Method</div>
<div class="path">Path</div>
<div class="query">Query params</div>
<div class="desc">Description</div>
<div class="curl">Curl command</div>
</div>
${ENDPOINTS}
</div>
</div>
<div class="footer">
<div>Copyright © Andrzej Oczkowicz 2022</div>
<div>Copyright © Andrzej Oczkowicz ${BUILD_YEAR}</div>
<div><a href="${URL}" target="_blank">${URL}</a></div>
</div>
</body>
Expand Down
3 changes: 2 additions & 1 deletion src/main/resources/api/method.get.html
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<div class="item">
<div class="method get"><span>GET</span></div>
<div class="path"><a href="${HREF}">${PATH}</a></div>
<div class="query">${QUERY}</div>
<div class="desc">${DESC}</div>
<div class="curl"><span>${CMD}</span></div>
</div>
</div>
3 changes: 2 additions & 1 deletion src/main/resources/api/method.post.html
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<div class="item">
<div class="method post"><span>POST</span></div>
<div class="path">${PATH}</div>
<div class="query">${QUERY}</div>
<div class="desc">${DESC}</div>
<div class="curl"><span>${CMD}</span></div>
</div>
</div>
2 changes: 1 addition & 1 deletion src/test/java/pl/andrzejo/aspm/api/ApiIndexTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ void shouldGetApiIndex() {
//given
ApiIndex index = new ApiIndex();
List<AppApiService.Endpoint> endpoints = Collections.singletonList(
new AppApiService.Endpoint(Post, "/api/endpoint", "Some endpoint.", "BODY")
new AppApiService.Endpoint(Post, "/api/endpoint", new AppApiService.EndpointDescription("", "BODY", ""))
);

//when
Expand Down

0 comments on commit 20e8805

Please sign in to comment.