Skip to content

Commit

Permalink
Mcpods 6507 get all handlers or by ID (#88)
Browse files Browse the repository at this point in the history
* move up one level for shared usage

* move up one level for shared usage

* optimize import

* api implementation

* add tests
  • Loading branch information
gunplar authored Nov 10, 2023
1 parent 01063f8 commit 12287c2
Show file tree
Hide file tree
Showing 7 changed files with 221 additions and 44 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,9 @@
*/
package com.here.naksha.app.service.http.apis;

import static com.here.naksha.app.service.http.tasks.EventHandlerApiTask.EventHandlerApiReqType.CREATE_HANDLER;

import com.here.naksha.app.service.http.NakshaHttpVerticle;
import com.here.naksha.app.service.http.tasks.EventHandlerApiTask;
import com.here.naksha.app.service.http.tasks.EventHandlerApiTask.EventHandlerApiReqType;
import io.vertx.ext.web.Router;
import io.vertx.ext.web.RoutingContext;
import io.vertx.ext.web.openapi.RouterBuilder;
Expand All @@ -40,18 +39,28 @@ public EventHandlerApi(@NotNull NakshaHttpVerticle verticle) {
@Override
public void addOperations(@NotNull RouterBuilder rb) {
rb.operation("createHandler").handler(this::createEventHandler);
rb.operation("getHandlers").handler(this::getEventHandlers);
rb.operation("getHandlerById").handler(this::getEventHandlerById);
}

@Override
public void addManualRoutes(@NotNull Router router) {}

private void createEventHandler(final @NotNull RoutingContext routingContext) {
startHandlerApiTask(EventHandlerApiReqType.CREATE_HANDLER, routingContext);
}

private void getEventHandlers(final @NotNull RoutingContext routingContext) {
startHandlerApiTask(EventHandlerApiReqType.GET_ALL_HANDLERS, routingContext);
}

private void getEventHandlerById(final @NotNull RoutingContext routingContext) {
startHandlerApiTask(EventHandlerApiReqType.GET_HANDLER_BY_ID, routingContext);
}

private void startHandlerApiTask(EventHandlerApiReqType reqType, RoutingContext routingContext) {
new EventHandlerApiTask<>(
CREATE_HANDLER,
verticle,
naksha(),
routingContext,
verticle.createNakshaContext(routingContext))
reqType, verticle, naksha(), routingContext, verticle.createNakshaContext(routingContext))
.start();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,9 @@
import com.here.naksha.lib.core.models.geojson.implementation.XyzFeature;
import com.here.naksha.lib.core.models.geojson.implementation.XyzFeatureCollection;
import com.here.naksha.lib.core.models.payload.XyzResponse;
import com.here.naksha.lib.core.models.storage.ErrorResult;
import com.here.naksha.lib.core.models.storage.ReadResult;
import com.here.naksha.lib.core.models.storage.Result;
import com.here.naksha.lib.core.models.storage.WriteResult;
import com.here.naksha.lib.core.models.storage.*;
import com.here.naksha.lib.core.storage.IReadSession;
import com.here.naksha.lib.core.storage.IWriteSession;
import io.vertx.ext.web.RoutingContext;
import java.util.ArrayList;
import java.util.Iterator;
Expand Down Expand Up @@ -188,4 +187,16 @@ protected AbstractApiTask(
XyzError.EXCEPTION,
"Unsupported result type : " + wrResult.getClass().getSimpleName());
}

protected Result executeReadRequestFromSpaceStorage(ReadFeatures readRequest) {
try (final IReadSession reader = naksha().getSpaceStorage().newReadSession(context(), false)) {
return reader.execute(readRequest);
}
}

protected Result executeWriteRequestFromSpaceStorage(WriteFeatures<?> writeRequest) {
try (final IWriteSession writer = naksha().getSpaceStorage().newWriteSession(context(), true)) {
return writer.execute(writeRequest);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,16 @@
*/
package com.here.naksha.app.service.http.tasks;

import static com.here.naksha.lib.core.NakshaAdminCollection.EVENT_HANDLERS;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.here.naksha.app.service.http.NakshaHttpVerticle;
import com.here.naksha.lib.core.INaksha;
import com.here.naksha.lib.core.NakshaAdminCollection;
import com.here.naksha.lib.core.NakshaContext;
import com.here.naksha.lib.core.models.XyzError;
import com.here.naksha.lib.core.models.naksha.EventHandler;
import com.here.naksha.lib.core.models.payload.XyzResponse;
import com.here.naksha.lib.core.models.storage.Result;
import com.here.naksha.lib.core.models.storage.WriteFeatures;
import com.here.naksha.lib.core.storage.IWriteSession;
import com.here.naksha.lib.core.models.storage.*;
import com.here.naksha.lib.core.util.json.Json;
import com.here.naksha.lib.core.util.storage.RequestHelper;
import com.here.naksha.lib.core.view.ViewDeserialize;
Expand All @@ -38,6 +38,8 @@

public class EventHandlerApiTask<T extends XyzResponse> extends AbstractApiTask<XyzResponse> {

private static final String HANDLER_ID_PATH_KEY = "handlerId";

private static final Logger logger = LoggerFactory.getLogger(EventHandlerApiTask.class);

private final @NotNull EventHandlerApiReqType reqType;
Expand Down Expand Up @@ -68,6 +70,8 @@ protected void init() {}
try {
return switch (reqType) {
case CREATE_HANDLER -> executeCreateHandler();
case GET_ALL_HANDLERS -> executeGetHandlers();
case GET_HANDLER_BY_ID -> executeGetHandlerById();
default -> executeUnsupported();
};
} catch (Exception ex) {
Expand All @@ -79,19 +83,38 @@ protected void init() {}

private @NotNull XyzResponse executeCreateHandler() throws Exception {
// Read request JSON
EventHandler newHandler = null;
final EventHandler newHandler = handlerFromRequestBody();
final WriteFeatures<EventHandler> writeRequest =
RequestHelper.createFeatureRequest(EVENT_HANDLERS, newHandler, false);
// persist new handler in Admin DB (if doesn't exist already)
final Result writeResult = executeWriteRequestFromSpaceStorage(writeRequest);
return transformWriteResultToXyzFeatureResponse(writeResult, EventHandler.class);
}

private @NotNull XyzResponse executeGetHandlers() {
// Create ReadFeatures Request to read all handlers from Admin DB
final ReadFeatures request = new ReadFeatures(EVENT_HANDLERS);
// Submit request to NH Space Storage
final Result rdResult = executeReadRequestFromSpaceStorage(request);
// transform ReadResult to Http FeatureCollection response
return transformReadResultToXyzCollectionResponse(rdResult, EventHandler.class);
}

private @NotNull XyzResponse executeGetHandlerById() {
// Create ReadFeatures Request to read the handler with the specific ID from Admin DB
final String handlerId = routingContext.pathParam(HANDLER_ID_PATH_KEY);
final ReadFeatures request = new ReadFeatures(EVENT_HANDLERS).withPropertyOp(POp.eq(PRef.id(), handlerId));
// Submit request to NH Space Storage
final Result rdResult = executeReadRequestFromSpaceStorage(request);
return transformReadResultToXyzFeatureResponse(rdResult, EventHandler.class);
}

private @NotNull EventHandler handlerFromRequestBody() throws JsonProcessingException {
try (final Json json = Json.get()) {
final String bodyJson = routingContext.body().asString();
newHandler = json.reader(ViewDeserialize.User.class)
return json.reader(ViewDeserialize.User.class)
.forType(EventHandler.class)
.readValue(bodyJson);
}
// persist new handler in Admin DB (if doesn't exist already)
try (final IWriteSession writeSession = naksha().getSpaceStorage().newWriteSession(context(), true)) {
final WriteFeatures<EventHandler> writeRequest =
RequestHelper.createFeatureRequest(NakshaAdminCollection.EVENT_HANDLERS, newHandler, false);
final Result writeResult = writeSession.execute(writeRequest);
return transformWriteResultToXyzFeatureResponse(writeResult, EventHandler.class);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,6 @@
import com.here.naksha.lib.core.models.storage.ReadFeatures;
import com.here.naksha.lib.core.models.storage.Result;
import com.here.naksha.lib.core.models.storage.WriteFeatures;
import com.here.naksha.lib.core.storage.IReadSession;
import com.here.naksha.lib.core.storage.IWriteSession;
import com.here.naksha.lib.core.util.json.Json;
import com.here.naksha.lib.core.util.storage.RequestHelper;
import com.here.naksha.lib.core.view.ViewDeserialize;
Expand Down Expand Up @@ -103,43 +101,31 @@ protected void init() {}
} else {
final WriteFeatures<Storage> updateStorageReq =
RequestHelper.updateFeatureRequest(STORAGES, storageFromBody);
final Result updateStorageResult = executeWriteRequest(updateStorageReq);
final Result updateStorageResult = executeWriteRequestFromSpaceStorage(updateStorageReq);
return transformWriteResultToXyzFeatureResponse(updateStorageResult, Storage.class);
}
}

private @NotNull XyzResponse executeGetStorages() {
final ReadFeatures request = new ReadFeatures(STORAGES);
final Result rdResult = executeReadRequest(request);
final Result rdResult = executeReadRequestFromSpaceStorage(request);
return transformReadResultToXyzCollectionResponse(rdResult, Storage.class);
}

private @NotNull XyzResponse executeGetStorageById() {
final String storageId = routingContext.pathParam(STORAGE_ID_PATH_KEY);
final ReadFeatures request = new ReadFeatures(STORAGES).withPropertyOp(POp.eq(PRef.id(), storageId));
final Result rdResult = executeReadRequest(request);
final Result rdResult = executeReadRequestFromSpaceStorage(request);
return transformReadResultToXyzFeatureResponse(rdResult, Storage.class);
}

private @NotNull XyzResponse executeCreateStorage() throws JsonProcessingException {
final Storage newStorage = storageFromRequestBody();
final WriteFeatures<Storage> wrRequest = RequestHelper.createFeatureRequest(STORAGES, newStorage, false);
final Result wrResult = executeWriteRequest(wrRequest);
final Result wrResult = executeWriteRequestFromSpaceStorage(wrRequest);
return transformWriteResultToXyzFeatureResponse(wrResult, Storage.class);
}

private Result executeWriteRequest(WriteFeatures<Storage> writeRequest) {
try (final IWriteSession writer = naksha().getSpaceStorage().newWriteSession(context(), true)) {
return writer.execute(writeRequest);
}
}

private Result executeReadRequest(ReadFeatures readRequest) {
try (final IReadSession reader = naksha().getSpaceStorage().newReadSession(context(), false)) {
return reader.execute(readRequest);
}
}

private @NotNull Storage storageFromRequestBody() throws JsonProcessingException {
try (final Json json = Json.get()) {
final String bodyJson = routingContext.body().asString();
Expand Down
76 changes: 74 additions & 2 deletions here-naksha-app-service/src/main/resources/static/openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ paths:
type: string
responses:
'200':
$ref: '#/components/responses/StoragesResponse'
$ref: '#/components/responses/StorageResponse'
'401':
$ref: '#/components/responses/ErrorResponse401'
'403':
Expand Down Expand Up @@ -193,6 +193,60 @@ paths:
$ref: '#/components/responses/ErrorResponse504'
'513':
$ref: '#/components/responses/ErrorResponse513'
get:
tags:
- Manage Event Handlers
summary: List event handlers
description: Lists the event handlers, which the current authenticated user has access to.
operationId: getHandlers
responses:
'200':
$ref: '#/components/responses/HandlersResponse'
'401':
$ref: '#/components/responses/ErrorResponse401'
'403':
$ref: '#/components/responses/ErrorResponse403'
'429':
$ref: '#/components/responses/ErrorResponse429'
'500':
$ref: '#/components/responses/ErrorResponse500'
'502':
$ref: '#/components/responses/ErrorResponse502'
'504':
$ref: '#/components/responses/ErrorResponse504'
'513':
$ref: '#/components/responses/ErrorResponse513'
'/hub/handlers/{handlerId}':
get:
tags:
- Manage Event Handlers
summary: Get the event handler with the specific ID.
description: Return the handler detail corresponding to the given ID if the current authenticated user has access to.
operationId: getHandlerById
parameters:
- name: handlerId
in: path
description: ID of event handler to fetch
required: true
schema:
type: string
responses:
'200':
$ref: '#/components/responses/HandlerResponse'
'401':
$ref: '#/components/responses/ErrorResponse401'
'403':
$ref: '#/components/responses/ErrorResponse403'
'429':
$ref: '#/components/responses/ErrorResponse429'
'500':
$ref: '#/components/responses/ErrorResponse500'
'502':
$ref: '#/components/responses/ErrorResponse502'
'504':
$ref: '#/components/responses/ErrorResponse504'
'513':
$ref: '#/components/responses/ErrorResponse513'
'/hub/spaces/{spaceId}/features':
get:
tags:
Expand Down Expand Up @@ -652,6 +706,24 @@ components:
className: "com.here.naksha.lib.handlers.DefaultStorageHandler"
properties:
storageId: "ID"
HandlersResponse:
description: The list of event handlers.
content:
application/json:
schema:
items:
$ref: '#/components/schemas/EventHandler'
type: array
examples:
response:
value:
- id: "um-mod-dev"
type: "EventHandler"
title: "Storage Handler for UniMap Moderation Dev Storage"
description: "Default Naksha Storage Handler for operations on UniMap Moderation Dev Storage"
className: "com.here.naksha.lib.handlers.DefaultStorageHandler"
properties:
storageId: "ID"
schemas:
Error:
type: object
Expand Down Expand Up @@ -1011,4 +1083,4 @@ components:
format: int64
readOnly: true
type: integer
additionalProperties: true
additionalProperties: true
Original file line number Diff line number Diff line change
Expand Up @@ -395,6 +395,72 @@ void tc0102_testCreateHandlerMissingClassName() throws Exception {
assertEquals(streamId, getHeader(response, HDR_STREAM_ID), "StreamId mismatch");
}

@Test
@Order(3)
void tc0120_testGetHandlerById() throws Exception {
// Test API : GET /hub/handlers/{handlerId}
// 1. Load test data
final String expectedBodyPart = loadFileOrFail("TC0100_createEventHandler/response_create_1.json");
final String streamId = UUID.randomUUID().toString();

// 2. Perform REST API call
final HttpRequest request = HttpRequest.newBuilder(stdHttpRequest, (k, v) -> true)
.uri(new URI(NAKSHA_HTTP_URI + "hub/handlers/test-handler"))
.GET()
.header(HDR_STREAM_ID, streamId)
.build();
final HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());

// 3. Perform assertions
assertEquals(200, response.statusCode(), "ResCode mismatch");
JSONAssert.assertEquals(
"Expecting handler response", expectedBodyPart, response.body(), JSONCompareMode.LENIENT);
assertEquals(streamId, getHeader(response, HDR_STREAM_ID), "StreamId mismatch");
}

@Test
@Order(3)
void tc0121_testGetHandlerByWrongId() throws Exception {
// Test API : GET /hub/handlers/{handlerId}
// 1. Load test data
final String streamId = UUID.randomUUID().toString();

// 2. Perform REST API call
final HttpRequest request = HttpRequest.newBuilder(stdHttpRequest, (k, v) -> true)
.uri(new URI(NAKSHA_HTTP_URI + "hub/handlers/not-real-handler"))
.GET()
.header(HDR_STREAM_ID, streamId)
.build();
final HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());

// 3. Perform assertions
assertEquals(404, response.statusCode(), "ResCode mismatch");
assertEquals(streamId, getHeader(response, HDR_STREAM_ID), "StreamId mismatch");
}

@Test
@Order(3)
void tc0140_testGetHandlers() throws Exception {
// Test API : GET /hub/handlers
// 1. Load test data
final String expectedBodyPart = loadFileOrFail("TC0140_getHandlers/response.json");
final String streamId = UUID.randomUUID().toString();

// 2. Perform REST API call
final HttpRequest request = HttpRequest.newBuilder(stdHttpRequest, (k, v) -> true)
.uri(new URI(NAKSHA_HTTP_URI + "hub/handlers"))
.GET()
.header(HDR_STREAM_ID, streamId)
.build();
final HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());

// 3. Perform assertions
assertEquals(200, response.statusCode(), "ResCode mismatch");
JSONAssert.assertEquals(
"Expecting previously created handler", expectedBodyPart, response.body(), JSONCompareMode.LENIENT);
assertEquals(streamId, getHeader(response, HDR_STREAM_ID), "StreamId mismatch");
}

@Test
@Order(4)
void tc0300_testCreateFeaturesWithNewIds() throws Exception {
Expand Down
Loading

0 comments on commit 12287c2

Please sign in to comment.