Skip to content

Commit

Permalink
Update Hello World example with named wildcard example
Browse files Browse the repository at this point in the history
Signed-off-by: Daniel Widdis <[email protected]>
  • Loading branch information
dbwiddis committed Sep 6, 2022
1 parent fea6ebc commit a2c127f
Show file tree
Hide file tree
Showing 5 changed files with 186 additions and 16 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,34 +13,43 @@
import org.opensearch.rest.RestResponse;
import org.opensearch.sdk.ExtensionRestHandler;

import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.util.List;

import static java.util.Collections.singletonList;
import static org.opensearch.rest.RestRequest.Method.GET;
import static org.opensearch.rest.RestRequest.Method.PUT;
import static org.opensearch.rest.RestStatus.BAD_REQUEST;
import static org.opensearch.rest.RestStatus.NOT_FOUND;
import static org.opensearch.rest.RestStatus.OK;
import static org.opensearch.rest.RestStatus.INTERNAL_SERVER_ERROR;

/**
* Sample REST Handler (REST Action). Extension REST handlers must implement {@link ExtensionRestHandler}.
*/
public class RestHelloAction implements ExtensionRestHandler {

private static final String GREETING = "Hello, World!";
private static final String GREETING = "Hello, %s!";
private String worldName = "World";

@Override
public List<Route> routes() {
return singletonList(new Route(GET, "/hello"));
return List.of(new Route(GET, "/hello"), new Route(PUT, "/hello/{name}"));
}

@Override
public RestResponse handleRequest(Method method, String uri) {
if (Method.GET.equals(method) && "/hello".equals(uri)) {
return new BytesRestResponse(OK, GREETING);
return new BytesRestResponse(OK, String.format(GREETING, worldName));
} else if (Method.PUT.equals(method) && uri.startsWith("/hello/")) {
String name = uri.substring("/hello/".length());
try {
worldName = URLDecoder.decode(name, StandardCharsets.UTF_8);
} catch (IllegalArgumentException e) {
return new BytesRestResponse(BAD_REQUEST, e.getMessage());
}
return new BytesRestResponse(OK, "Updated the world's name to " + worldName);
}
return new BytesRestResponse(
INTERNAL_SERVER_ERROR,
"Extension REST action improperly configured to handle " + method.name() + " " + uri
);
return new BytesRestResponse(NOT_FOUND, "Extension REST action improperly configured to handle " + method.name() + " " + uri);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
{

This comment has been minimized.

Copy link
@owaiskazi19

owaiskazi19 Sep 7, 2022

Member

For my understanding. How are we using this json file and where exactly?

This comment has been minimized.

Copy link
@dbwiddis

dbwiddis Sep 7, 2022

Author Member

This comment has been minimized.

Copy link
@dbwiddis

dbwiddis Sep 7, 2022

Author Member

Paste the JSON here to see what it looks like: https://editor.swagger.io/

This comment has been minimized.

Copy link
@owaiskazi19

owaiskazi19 Sep 7, 2022

Member

Should we document this somewhere?

This comment has been minimized.

Copy link
@dbwiddis

dbwiddis Sep 7, 2022

Author Member

Should we document this somewhere?

Yes. I don't know where, though. It'll be part of the catalog likely? I just wanted to get started now for when we eventually need it.

For now, the JSON (or YAML) is documentation per OpenAPI spec and intended as an example for external extension authors, so just reminding them they need to document their API is a good thing.

This comment has been minimized.

Copy link
@dbwiddis

dbwiddis Sep 7, 2022

Author Member

As far as "where" and in what format, I'm tracking OS Issue 3090 (linked above) and don't think we should put too much effort in until that's resoved.

This comment has been minimized.

Copy link
@owaiskazi19

owaiskazi19 Sep 7, 2022

Member

Do you think we should add the swagger link and the json file path in DEVELOPER_GUIDE for anyone to get the visual treat of what exactly this json looks like?

This comment has been minimized.

Copy link
@owaiskazi19

owaiskazi19 Sep 7, 2022

Member

In the future we will definitely have our swagger with more and more APIs :)

This comment has been minimized.

Copy link
@dbwiddis

dbwiddis Sep 7, 2022

Author Member

Heh. I hesitate to pick one choice. "OpenAPI Viewer" gives many options, and none yet do I see where you can include the URL in the URL to auto-load them. There is an OpenAPI extension for Visual Studio Code, there are multiple plugins for Eclipse, and it's built in to IntelliJ IDEA.

So I think providing the JSON is good enough. :)

This comment has been minimized.

Copy link
@dbwiddis

dbwiddis Sep 7, 2022

Author Member
"openapi": "3.0.3",
"info": {
"title": "Hello World",
"description": "This is a sample Hello World extension.",
"license": {
"name": "Apache 2.0",
"url": "http://www.apache.org/licenses/LICENSE-2.0.html"
},
"version": "1.0.0-SNAPSHOT"
},
"tags": [
{
"name": "hello",
"description": "Worldly Greetings"
}
],
"paths": {
"/hello": {
"get": {
"tags": [
"hello"
],
"summary": "Greet the world",
"description": "Traditional greeting",
"responses": {
"200": {
"description": "Successful operation",
"content": {
"text/plain; charset=utf-8": {
"examples": {
"Default Response": {
"value": "Hello, World!"
}
}
}
}
},
"400": {
"description": "Syntax Error in URI"
},
"404": {
"description": "Improper REST action configuration"
}
}
}
},
"/hello/{name}": {
"put": {
"tags": [
"hello"
],
"summary": "Update world name",
"description": "Rename the world",
"parameters": [
{
"name": "name",
"in": "path",
"description": "a new name for the world",
"required": true,
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "Successful operation",
"content": {
"text/plain; charset=utf-8": {
"examples": {
"Default Response": {
"value": "Updated the world's name to OpenSearch"
}
}
}
}
},
"400": {
"description": "Syntax Error in URI"
},
"404": {
"description": "Improper REST action configuration"
}
}
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
openapi: 3.0.3
info:
title: Hello World
description: This is a sample Hello World extension.
license:
name: Apache 2.0
url: http://www.apache.org/licenses/LICENSE-2.0.html
version: 1.0.0-SNAPSHOT
tags:
- name: hello
description: Worldly Greetings
paths:
/hello:
get:
tags:
- hello
summary: Greet the world
description: Traditional greeting
responses:
'200':
description: Successful operation
content:
text/plain; charset=utf-8:
examples:
Default Response:
value: Hello, World!
'400':
description: Syntax Error in URI
'404':
description: Improper REST action configuration
/hello/{name}:
put:
tags:
- hello
summary: Update world name
description: Rename the world
parameters:
- name: name
in: path
description: a new name for the world
required: true
schema:
type: string
responses:
'200':
description: Successful operation
content:
text/plain; charset=utf-8:
examples:
Default Response:
value: Updated the world's name to OpenSearch
'400':
description: Syntax Error in URI
'404':
description: Improper REST action configuration
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.opensearch.rest.RestHandler.Route;
import org.opensearch.rest.RestRequest.Method;
import org.opensearch.sdk.Extension;
import org.opensearch.sdk.ExtensionRestHandler;
import org.opensearch.sdk.ExtensionSettings;
Expand Down Expand Up @@ -44,9 +43,7 @@ public void testExtensionRestHandlers() {
List<ExtensionRestHandler> extensionRestHandlers = extension.getExtensionRestHandlers();
assertEquals(1, extensionRestHandlers.size());
List<Route> routes = extensionRestHandlers.get(0).routes();
assertEquals(1, routes.size());
assertEquals(Method.GET, routes.get(0).getMethod());
assertEquals("/hello", routes.get(0).getPath());
assertEquals(2, routes.size());
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,11 @@ public void setUp() throws Exception {
@Test
public void testRoutes() {
List<Route> routes = restHelloAction.routes();
assertEquals(1, routes.size());
assertEquals(2, routes.size());
assertEquals(Method.GET, routes.get(0).getMethod());
assertEquals("/hello", routes.get(0).getPath());
assertEquals(Method.PUT, routes.get(1).getMethod());
assertEquals("/hello/{name}", routes.get(1).getPath());
}

@Test
Expand All @@ -49,13 +51,31 @@ public void testHandleRequest() {
assertEquals("Hello, World!", responseStr);

response = restHelloAction.handleRequest(Method.PUT, "/hello");
assertEquals(RestStatus.INTERNAL_SERVER_ERROR, response.status());
assertEquals(RestStatus.NOT_FOUND, response.status());
assertEquals(BytesRestResponse.TEXT_CONTENT_TYPE, response.contentType());
responseStr = new String(BytesReference.toBytes(response.content()), StandardCharsets.UTF_8);
assertTrue(responseStr.contains("PUT"));

response = restHelloAction.handleRequest(Method.PUT, "/hello/Passing+Test");
assertEquals(RestStatus.OK, response.status());
assertEquals(BytesRestResponse.TEXT_CONTENT_TYPE, response.contentType());
responseStr = new String(BytesReference.toBytes(response.content()), StandardCharsets.UTF_8);
assertEquals("Updated the world's name to Passing Test", responseStr);

response = restHelloAction.handleRequest(Method.GET, "/hello");
assertEquals(RestStatus.OK, response.status());
assertEquals(BytesRestResponse.TEXT_CONTENT_TYPE, response.contentType());
responseStr = new String(BytesReference.toBytes(response.content()), StandardCharsets.UTF_8);
assertEquals("Hello, Passing Test!", responseStr);

response = restHelloAction.handleRequest(Method.PUT, "/hello/Bad%Request");
assertEquals(RestStatus.BAD_REQUEST, response.status());
assertEquals(BytesRestResponse.TEXT_CONTENT_TYPE, response.contentType());
responseStr = new String(BytesReference.toBytes(response.content()), StandardCharsets.UTF_8);
assertTrue(responseStr.contains("Illegal hex characters in escape (%) pattern"));

response = restHelloAction.handleRequest(Method.GET, "/goodbye");
assertEquals(RestStatus.INTERNAL_SERVER_ERROR, response.status());
assertEquals(RestStatus.NOT_FOUND, response.status());
assertEquals(BytesRestResponse.TEXT_CONTENT_TYPE, response.contentType());
responseStr = new String(BytesReference.toBytes(response.content()), StandardCharsets.UTF_8);
assertTrue(responseStr.contains("/goodbye"));
Expand Down

0 comments on commit a2c127f

Please sign in to comment.