From 6cb9f59461fa63e7df39dba4f0cb8611db885b7d Mon Sep 17 00:00:00 2001 From: Sebastian Date: Tue, 20 Jul 2021 14:01:28 +0200 Subject: [PATCH] More http methods for scripts. --- .../Scripting/Extensions/HttpJintExtension.cs | 53 ++++++-- .../Scripting/JintScriptEngineHelperTests.cs | 113 +++++++++++++++++- .../Operations/Scripting/MockupHttpHandler.cs | 24 +++- 3 files changed, 170 insertions(+), 20 deletions(-) diff --git a/backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/Extensions/HttpJintExtension.cs b/backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/Extensions/HttpJintExtension.cs index 76f0a9f2f..50df4e643 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/Extensions/HttpJintExtension.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/Extensions/HttpJintExtension.cs @@ -7,6 +7,7 @@ using System; using System.Net.Http; +using System.Text; using System.Threading.Tasks; using Jint; using Jint.Native; @@ -18,7 +19,8 @@ namespace Squidex.Domain.Apps.Core.Scripting.Extensions { public sealed class HttpJintExtension : IJintExtension { - private delegate void GetJsonDelegate(string url, Action callback, JsValue? headers = null); + private delegate void HttpJson(string url, Action callback, JsValue? headers = null); + private delegate void HttpJsonWithBody(string url, JsValue post, Action callback, JsValue? headers = null); private readonly IHttpClientFactory httpClientFactory; public HttpJintExtension(IHttpClientFactory httpClientFactory) @@ -28,17 +30,35 @@ namespace Squidex.Domain.Apps.Core.Scripting.Extensions public void ExtendAsync(ExecutionContext context) { - var action = new GetJsonDelegate((url, callback, headers) => GetJson(context, url, callback, headers)); + AddMethod(context, HttpMethod.Get, "getJSON"); + AddMethod(context, HttpMethod.Delete, "deleteJSON"); - context.Engine.SetValue("getJSON", action); + AdBodyMethod(context, HttpMethod.Patch, "patchJSON"); + AdBodyMethod(context, HttpMethod.Post, "postJSON"); + AdBodyMethod(context, HttpMethod.Put, "putJSON"); } - private void GetJson(ExecutionContext context, string url, Action callback, JsValue? headers) + private void AddMethod(ExecutionContext context, HttpMethod method, string name) { - GetJsonAsync(context, url, callback, headers).Forget(); + var action = new HttpJson((url, callback, headers) => + { + RequestAsync(context, method, url, null, callback, headers).Forget(); + }); + + context.Engine.SetValue(name, action); + } + + private void AdBodyMethod(ExecutionContext context, HttpMethod method, string name) + { + var action = new HttpJsonWithBody((url, body, callback, headers) => + { + RequestAsync(context, method, url, body, callback, headers).Forget(); + }); + + context.Engine.SetValue(name, action); } - private async Task GetJsonAsync(ExecutionContext context, string url, Action callback, JsValue? headers) + private async Task RequestAsync(ExecutionContext context, HttpMethod method, string url, JsValue? body, Action callback, JsValue? headers) { if (callback == null) { @@ -46,7 +66,7 @@ namespace Squidex.Domain.Apps.Core.Scripting.Extensions return; } - if (!Uri.IsWellFormedUriString(url, UriKind.Absolute)) + if (!Uri.TryCreate(url, UriKind.Absolute, out var uri)) { context.Fail(new JavaScriptException("URL is not valid.")); return; @@ -58,7 +78,7 @@ namespace Squidex.Domain.Apps.Core.Scripting.Extensions { using (var httpClient = httpClientFactory.CreateClient()) { - using (var request = CreateRequest(url, headers)) + using (var request = CreateRequest(context, method, uri, body, headers)) { using (var response = await httpClient.SendAsync(request, context.CancellationToken)) { @@ -79,14 +99,21 @@ namespace Squidex.Domain.Apps.Core.Scripting.Extensions } } - private static HttpRequestMessage CreateRequest(string url, JsValue? headers) + private static HttpRequestMessage CreateRequest(ExecutionContext context, HttpMethod method, Uri uri, JsValue? body, JsValue? headers) { - if (!Uri.TryCreate(url, UriKind.Absolute, out var uri)) + var request = new HttpRequestMessage(method, uri); + + if (body != null) { - throw new ArgumentException("Url must be an absolute URL"); - } + var serializer = new JsonSerializer(context.Engine); + + var json = serializer.Serialize(body, JsValue.Undefined, JsValue.Undefined)?.ToString(); - var request = new HttpRequestMessage(HttpMethod.Get, uri); + if (json != null) + { + request.Content = new StringContent(json, Encoding.UTF8, "text/json"); + } + } if (headers != null && headers.Type == Types.Object) { diff --git a/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/Scripting/JintScriptEngineHelperTests.cs b/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/Scripting/JintScriptEngineHelperTests.cs index 2c81252fe..233200ffe 100644 --- a/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/Scripting/JintScriptEngineHelperTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/Scripting/JintScriptEngineHelperTests.cs @@ -323,7 +323,7 @@ namespace Squidex.Domain.Apps.Core.Operations.Scripting } [Fact] - public async Task Should_make_json_request() + public async Task Should_make_getJson_request() { var httpHandler = SetupRequest(); @@ -348,7 +348,7 @@ namespace Squidex.Domain.Apps.Core.Operations.Scripting } [Fact] - public async Task Should_make_json_request_with_headers() + public async Task Should_make_getJson_request_with_headers() { var httpHandler = SetupRequest(); @@ -379,6 +379,115 @@ namespace Squidex.Domain.Apps.Core.Operations.Scripting Assert.Equal(expectedResult, result); } + [Fact] + public async Task Should_make_deleteJson_request() + { + var httpHandler = SetupRequest(); + + const string script = @" + var url = 'http://squidex.io'; + + deleteJSON(url, function(result) { + complete(result); + }); + "; + + var vars = new ScriptVars(); + + var result = await sut.ExecuteAsync(vars, script); + + httpHandler.ShouldBeMethod(HttpMethod.Delete); + httpHandler.ShouldBeUrl("http://squidex.io/"); + + var expectedResult = JsonValue.Object().Add("key", 42); + + Assert.Equal(expectedResult, result); + } + + [Fact] + public async Task Should_make_patchJson_request() + { + var httpHandler = SetupRequest(); + + const string script = @" + var url = 'http://squidex.io'; + + var body = { key: 42 }; + + patchJSON(url, body, function(result) { + complete(result); + }); + "; + + var vars = new ScriptVars(); + + var result = await sut.ExecuteAsync(vars, script); + + httpHandler.ShouldBeMethod(HttpMethod.Patch); + httpHandler.ShouldBeUrl("http://squidex.io/"); + httpHandler.ShouldBeBody("{\"key\":42}", "text/json"); + + var expectedResult = JsonValue.Object().Add("key", 42); + + Assert.Equal(expectedResult, result); + } + + [Fact] + public async Task Should_make_postJson_request() + { + var httpHandler = SetupRequest(); + + const string script = @" + var url = 'http://squidex.io'; + + var body = { key: 42 }; + + postJSON(url, body, function(result) { + complete(result); + }); + "; + + var vars = new ScriptVars(); + + var result = await sut.ExecuteAsync(vars, script); + + httpHandler.ShouldBeMethod(HttpMethod.Post); + httpHandler.ShouldBeUrl("http://squidex.io/"); + httpHandler.ShouldBeBody("{\"key\":42}", "text/json"); + + var expectedResult = JsonValue.Object().Add("key", 42); + + Assert.Equal(expectedResult, result); + } + + [Fact] + public async Task Should_make_putJson_request() + { + var httpHandler = SetupRequest(); + + const string script = @" + var url = 'http://squidex.io'; + + var body = { key: 42 }; + + putJSON(url, body, function(result) { + complete(result); + }); + "; + + var vars = new ScriptVars(); + + var result = await sut.ExecuteAsync(vars, script); + + httpHandler.ShouldBeMethod(HttpMethod.Put); + httpHandler.ShouldBeUrl("http://squidex.io/"); + httpHandler.ShouldBeBody("{\"key\":42}", "text/json"); + + var expectedResult = JsonValue.Object().Add("key", 42); + + Assert.Equal(expectedResult, result); + } + private MockupHttpHandler SetupRequest() { var httpResponse = new HttpResponseMessage(HttpStatusCode.OK) diff --git a/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/Scripting/MockupHttpHandler.cs b/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/Scripting/MockupHttpHandler.cs index 68d2e7e05..2b518993a 100644 --- a/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/Scripting/MockupHttpHandler.cs +++ b/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/Scripting/MockupHttpHandler.cs @@ -16,21 +16,29 @@ namespace Squidex.Domain.Apps.Core.Operations.Scripting internal sealed class MockupHttpHandler : HttpMessageHandler { private readonly HttpResponseMessage response; - private HttpRequestMessage madeRequest; + private HttpRequestMessage currentRequest; + private string? currentContent; + private string? currentContentType; public void ShouldBeMethod(HttpMethod method) { - Assert.Equal(method, madeRequest.Method); + Assert.Equal(method, currentRequest.Method); } public void ShouldBeUrl(string url) { - Assert.Equal(url, madeRequest.RequestUri?.ToString()); + Assert.Equal(url, currentRequest.RequestUri?.ToString()); } public void ShouldBeHeader(string key, string value) { - Assert.Equal(value, madeRequest.Headers.GetValues(key).FirstOrDefault()); + Assert.Equal(value, currentRequest.Headers.GetValues(key).FirstOrDefault()); + } + + public void ShouldBeBody(string content, string contentType) + { + Assert.Equal(content, currentContent); + Assert.Equal(contentType, currentContentType); } public MockupHttpHandler(HttpResponseMessage response) @@ -42,7 +50,13 @@ namespace Squidex.Domain.Apps.Core.Operations.Scripting { await Task.Delay(1000, cancellationToken); - madeRequest = request; + currentRequest = request; + + if (request.Content is StringContent body) + { + currentContent = await body.ReadAsStringAsync(); + currentContentType = body.Headers.ContentType?.MediaType; + } return response; }