From a80611bd9a7c6aab02cdfc776ed7beacd2e90ca6 Mon Sep 17 00:00:00 2001 From: Yoshio Terada Date: Mon, 3 Jul 2023 17:23:00 +0900 Subject: [PATCH] Java: Http skill Added (#1712) Added HttpSkill for Java ### Motivation and Context Based on the [http_skill.py](https://github.com/microsoft/semantic-kernel/blob/main/python/semantic_kernel/core_skills/http_skill.py) I implemented the Http Skill by using Mono of Project Reactor. And I implemented the Test code with Mock. ### Description ### Contribution Checklist - [ ] The code builds clean without any errors or warnings - [ ] The PR follows SK Contribution Guidelines (https://github.com/microsoft/semantic-kernel/blob/main/CONTRIBUTING.md) - [ ] The code follows the .NET coding conventions (https://learn.microsoft.com/dotnet/csharp/fundamentals/coding-style/coding-conventions) verified with `dotnet format` - [ ] All unit tests pass, and I have added new tests where possible - [ ] I didn't break anyone :smile: --- java/semantickernel-core-skills/pom.xml | 1 - .../semantickernel/coreskills/HttpSkill.java | 99 +++++++++++++++++++ .../coreskills/HttpSkillTest.java | 72 ++++++++++++++ 3 files changed, 171 insertions(+), 1 deletion(-) create mode 100644 java/semantickernel-core-skills/src/main/java/com/microsoft/semantickernel/coreskills/HttpSkill.java create mode 100644 java/semantickernel-core-skills/src/test/java/com/microsoft/semantickernel/coreskills/HttpSkillTest.java diff --git a/java/semantickernel-core-skills/pom.xml b/java/semantickernel-core-skills/pom.xml index 788c3bc9d7..5ba1f4df9c 100644 --- a/java/semantickernel-core-skills/pom.xml +++ b/java/semantickernel-core-skills/pom.xml @@ -35,5 +35,4 @@ test - diff --git a/java/semantickernel-core-skills/src/main/java/com/microsoft/semantickernel/coreskills/HttpSkill.java b/java/semantickernel-core-skills/src/main/java/com/microsoft/semantickernel/coreskills/HttpSkill.java new file mode 100644 index 0000000000..fd368c7a87 --- /dev/null +++ b/java/semantickernel-core-skills/src/main/java/com/microsoft/semantickernel/coreskills/HttpSkill.java @@ -0,0 +1,99 @@ +// Copyright (c) Microsoft. All rights reserved. +package com.microsoft.semantickernel.coreskills; + +import com.azure.core.http.HttpClient; +import com.azure.core.http.HttpMethod; +import com.azure.core.http.HttpRequest; +import com.azure.core.http.HttpResponse; + +import reactor.core.publisher.Mono; + +/** + * A skill that provides HTTP functionality. + * + *

Usage: + * + *

Usage: kernel.importSkill(new HttpSkill(), "http"); + * + *

Examples: + * + *

{{http.getAsync $url}} + * + *

{{http.postAsync $url}} + * + *

{{http.putAsync $url}} + * + *

{{http.deleteAsync $url}} + */ +public class HttpSkill { + + private final HttpClient httpClient; + + public HttpSkill() { + this.httpClient = HttpClient.createDefault(); + } + + public HttpSkill(HttpClient httpClient) { + this.httpClient = httpClient; + } + + /** + * Sends an HTTP GET request to the specified URI and returns body as a string. + * + * @param url The URI to send the request to. + * @return The response body as a string. + */ + public Mono getAsync(String url) { + if (url == null || url.isEmpty()) { + return Mono.error(new IllegalArgumentException("url cannot be `null` or empty")); + } + HttpRequest request = new HttpRequest(HttpMethod.GET, url); + return httpClient.send(request).flatMap(response -> response.getBodyAsString()); + } + + /** + * Sends an HTTP POST request to the specified URI and returns body as a string. + * + * @param url The URI to send the request to. + * @param body The response body as a string. + * @return + */ + public Mono postAsync(String url, String body) { + if (url == null || url.isEmpty()) { + return Mono.error(new IllegalArgumentException("url cannot be `null` or empty")); + } + HttpRequest request = new HttpRequest(HttpMethod.POST, url); + request.setBody(body); + return httpClient.send(request).flatMap(response -> response.getBodyAsString()); + } + + /** + * Sends an HTTP PUT request to the specified URI and returns body as a string. + * + * @param url The URI to send the request to. + * @param body The response body as a string. + * @return + */ + public Mono putAsync(String url, String body) { + if (url == null || url.isEmpty()) { + return Mono.error(new IllegalArgumentException("url cannot be `null` or empty")); + } + HttpRequest request = new HttpRequest(HttpMethod.PUT, url); + request.setBody(body); + return httpClient.send(request).flatMap(response -> response.getBodyAsString()); + } + + /** + * Sends an HTTP DELETE request to the specified URI and returns body as a string. + * + * @param url The URI to send the request to. + * @return The response body as a string. + */ + public Mono deleteAsync(String url) { + if (url == null || url.isEmpty()) { + return Mono.error(new IllegalArgumentException("url cannot be `null` or empty")); + } + HttpRequest request = new HttpRequest(HttpMethod.DELETE, url); + return httpClient.send(request).flatMap(response -> Mono.just(response)); + } +} diff --git a/java/semantickernel-core-skills/src/test/java/com/microsoft/semantickernel/coreskills/HttpSkillTest.java b/java/semantickernel-core-skills/src/test/java/com/microsoft/semantickernel/coreskills/HttpSkillTest.java new file mode 100644 index 0000000000..219f5599ae --- /dev/null +++ b/java/semantickernel-core-skills/src/test/java/com/microsoft/semantickernel/coreskills/HttpSkillTest.java @@ -0,0 +1,72 @@ +// Copyright (c) Microsoft. All rights reserved. +package com.microsoft.semantickernel.coreskills; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.when; + +import com.azure.core.http.HttpClient; +import com.azure.core.http.HttpRequest; +import com.azure.core.http.HttpResponse; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import reactor.core.publisher.Mono; +import reactor.test.StepVerifier; + +public class HttpSkillTest { + + private HttpSkill httpSkill; + + @Mock private HttpClient httpClient; + + @Mock private HttpResponse httpResponse; + + @BeforeEach + public void setUp() { + MockitoAnnotations.openMocks(this); + httpSkill = new HttpSkill(httpClient); + } + + @Test + public void testGetAsync() { + String url = "https://example.com"; + String responseBody = "Response body"; + when(httpResponse.getBodyAsString()).thenReturn(Mono.just(responseBody)); + when(httpClient.send(any(HttpRequest.class))).thenReturn(Mono.just(httpResponse)); + Mono responseMono = httpSkill.getAsync(url); + StepVerifier.create(responseMono).expectNext(responseBody).verifyComplete(); + } + + @Test + public void testPostAsync() { + String url = "https://example.com"; + String body = "{\"key\": \"value\"}"; + String responseBody = "Response body"; + when(httpResponse.getBodyAsString()).thenReturn(Mono.just(responseBody)); + when(httpClient.send(any(HttpRequest.class))).thenReturn(Mono.just(httpResponse)); + Mono responseMono = httpSkill.postAsync(url, body); + StepVerifier.create(responseMono).expectNext(responseBody).verifyComplete(); + } + + @Test + public void testPutAsync() { + String url = "https://example.com"; + String body = "{\"key\": \"value\"}"; + String responseBody = "Response body"; + when(httpResponse.getBodyAsString()).thenReturn(Mono.just(responseBody)); + when(httpClient.send(any(HttpRequest.class))).thenReturn(Mono.just(httpResponse)); + Mono responseMono = httpSkill.putAsync(url, body); + StepVerifier.create(responseMono).expectNext(responseBody).verifyComplete(); + } + + @Test + public void testDeleteAsync() { + String url = "https://example.com"; + when(httpClient.send(any(HttpRequest.class))).thenReturn(Mono.just(httpResponse)); + Mono responseMono = httpSkill.deleteAsync(url); + StepVerifier.create(responseMono).expectNext(httpResponse).verifyComplete(); + } +}