Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature api component handles path param #78

Merged
merged 5 commits into from
Apr 16, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
44 changes: 38 additions & 6 deletions command/cmd/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ func findNext(node map[string]interface{}) (name string, content interface{}, ne
data := node["data"].(map[string]interface{})

if name == "API" {
content = map[string]interface{}{"method": data["method"], "url": data["url"], "cached": data["cached"], "cacheTime": data["cacheTime"]}
content = map[string]interface{}{"method": data["method"], "headers": data["headers"], "cached": data["cached"], "cacheTime": data["cacheTime"]}
} else if name == "MySQL" || name == "PostgreSQL" {
content = map[string]interface{}{"host": data["host"], "port": data["port"], "user": data["user"], "db": data["db"], "cached": data["cached"], "cacheTime": data["cacheTime"]}
} else if name == "SQLite" {
Expand Down Expand Up @@ -210,20 +210,23 @@ func contentBuilder(contents map[int]map[string]map[string]interface{}) func(req
for k, v := range c[i] {
if v["name"] == "API" {
content := v["content"].(map[string]interface{})
url := fmt.Sprintf("%v", content["url"])
headers := fmt.Sprintf("%v", content["headers"])
cached := fmt.Sprintf("%v", content["cached"])
method := fmt.Sprintf("%v", content["method"])
url := ""
query := ""
for _, v1 := range c[i+1] {
if v1["parent"] == k {
if v1["name"] != "DummyJSON" {
if v1["name"] == "URL" || v1["name"] == "URLWithPathParam" {
url = v1["content"].(string)
} else if v1["name"] != "DummyJSON" {
query = v1["content"].(string)
}
}
}

if cached == "true" {
v, ok := gache.Get(url+query)
v, ok := gache.Get(url + query)
if ok {
apiResponses = append(apiResponses, apiResponse{method, url, "cached"})
c[i][k]["content"] = v
Expand All @@ -232,18 +235,28 @@ func contentBuilder(contents map[int]map[string]map[string]interface{}) func(req
}

req, _ := http.NewRequest(method, url, nil)
if(query != ""){
if query != "" {
params := request.URL.Query()
tmp := map[string]string{}
err := json.Unmarshal([]byte(query), &tmp)
if err != nil {
log.Fatal(err)
}
for k, v := range tmp {
params.Add(k,v)
params.Add(k, v)
}
req.URL.RawQuery = params.Encode()
}
if headers != "" {
tmp := map[string]string{}
err := json.Unmarshal([]byte(headers), &tmp)
if err != nil {
log.Fatal(err)
}
for k, v := range tmp {
req.Header.Set(k, v)
}
}
resp, err := client.Do(req)
if err == nil && resp.StatusCode >= 400 {
apiResponses = append(apiResponses, apiResponse{method, url, strconv.Itoa(resp.StatusCode)})
Expand Down Expand Up @@ -278,6 +291,25 @@ func contentBuilder(contents map[int]map[string]map[string]interface{}) func(req
}
}
c[i][k]["content"] = res
} else if v["name"] == "URLWithPathParam" {
unformattedURL := v["content"].(string)
pathParams := ""
for _, v1 := range c[i+1] {
if v1["parent"] == k {
pathParams = v1["content"].(string)
}
}
if pathParams != "" {
tmp := map[string]string{}
err := json.Unmarshal([]byte(pathParams), &tmp)
if err != nil {
log.Fatal(err)
}
for k, v := range tmp {
unformattedURL = strings.ReplaceAll(unformattedURL, ":"+k, v)
}
}
c[i][k]["content"] = unformattedURL
} else if v["name"] == "Request" {
content := v["content"].(map[string]interface{})
requestType := fmt.Sprintf("%v", content["type"])
Expand Down
10 changes: 8 additions & 2 deletions ui/src/rete.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ import HistoryPlugin from "rete-history-plugin";

import { JsonComponent } from "./rete/components/input/JsonComponent";
import { DummyJsonComponent } from "./rete/components/input/DummyJsonComponent";
import { UrlComponent } from "./rete/components/input/UrlComponent";
import { UrlWithPathParamComponent } from "./rete/components/input/UrlWithPathParamComponent";
import { HtmlComponent } from "./rete/components/input/HtmlComponent";
import { SqlComponent } from "./rete/components/input/SqlComponent";
import { TemplateComponent } from "./rete/components/template/TemplateComponent";
Expand Down Expand Up @@ -58,6 +60,8 @@ export async function createEditor(container) {
rawHtmlSocket.combineWith(stringSocket);
// sql
const sqlSocket = new Rete.Socket("SQL value");
// url
const urlSocket = new Rete.Socket("URL value");

// 利用可能なコンポーネント一覧
const components = [
Expand All @@ -66,16 +70,18 @@ export async function createEditor(container) {
new JsonManagerComponent(jsonSocket),
new JsonComponent(rawJsonSocket),
new DummyJsonComponent(dummyJsonSocket),
new UrlComponent(urlSocket),
new UrlWithPathParamComponent(urlSocket, jsonSocket),
new HtmlComponent(rawHtmlSocket),
new TemplateComponent(jsonSocket, templateSocket, htmlSocket),
new HandlebarsComponent(handlebarsSocket),
new PugComponent(pugSocket),
new SqlComponent(sqlSocket),
new ApiComponent(jsonSocket, dummyJsonSocket),
new ApiComponent(jsonSocket, dummyJsonSocket, urlSocket),
new MySQLComponent(jsonSocket, dummyJsonSocket, sqlSocket),
new PostgreSQLComponent(jsonSocket, dummyJsonSocket, sqlSocket),
new SQLiteComponent(jsonSocket, dummyJsonSocket, sqlSocket),
new RequestComponent(jsonSocket),
new RequestComponent(jsonSocket, dummyJsonSocket),
new RedirectEndpointComponent(),
];

Expand Down
20 changes: 12 additions & 8 deletions ui/src/rete/components/ApiComponent.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import Rete from "rete";
import { TextControl } from "../controls/TextControl";
import { TextAreaControl } from "../controls/TextAreaControl";
import { BooleanControl } from "../controls/BooleanControl";
import { NumControl } from "../controls/NumControl";
import { DefaultNode } from "../nodes/DefaultNode";
Expand All @@ -8,23 +8,26 @@ import { SelectControl } from "../controls/SelectControl";
export class ApiComponent extends Rete.Component {
path = ["New"];

constructor(jsonSocket, dummyJsonSocket) {
constructor(jsonSocket, dummyJsonSocket, urlSocket) {
super("API");
this.data.component = DefaultNode; // optional
this.jsonSocket = jsonSocket;
this.dummyJsonSocket = dummyJsonSocket;
this.urlSocket = urlSocket;
}

builder(node) {
const queryInput = new Rete.Input("query", "Query (JSON)", this.jsonSocket);
const dummyJsonInput = new Rete.Input(
"json",
"Output (DummyJSON)",
"Expected (DummyJSON)",
this.dummyJsonSocket
);
const urlInput = new Rete.Input("url", "URL", this.urlSocket);
const out = new Rete.Output("json", "JSON", this.jsonSocket);

return node
.addInput(urlInput)
.addInput(queryInput)
.addInput(dummyJsonInput)
.addControl(
Expand All @@ -38,13 +41,13 @@ export class ApiComponent extends Rete.Component {
])
)
.addControl(
new TextControl(
new TextAreaControl(
this.editor,
"url",
"headers",
node,
false,
"URL",
"https://example.com/bar"
"Headers",
'{"KEY":"VALUE"}'
)
)
.addControl(
Expand Down Expand Up @@ -72,7 +75,8 @@ export class ApiComponent extends Rete.Component {
worker(node, inputs, outputs) {
outputs.query = inputs.query.length ? inputs.query[0] : node.data.query;
outputs.json = inputs.json.length ? inputs.json[0] : node.data.json;
outputs.url = node.data.url;
outputs.url = inputs.url.length ? inputs.url[0] : node.data.url;
outputs.headers = node.data.headers;
outputs.cached = node.data.cached;

this.editor.nodes
Expand Down
2 changes: 1 addition & 1 deletion ui/src/rete/components/MySQLComponent.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export class MySQLComponent extends Rete.Component {
builder(node) {
const dummyJsonInput = new Rete.Input(
"json",
"Output (DummyJSON)",
"Expected (DummyJSON)",
this.dummyJsonSocket
);
const out = new Rete.Output("json", "JSON", this.jsonSocket);
Expand Down
2 changes: 1 addition & 1 deletion ui/src/rete/components/PostgreSQLComponent.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export class PostgreSQLComponent extends Rete.Component {
builder(node) {
const dummyJsonInput = new Rete.Input(
"json",
"Output (DummyJSON)",
"Expected (DummyJSON)",
this.dummyJsonSocket
);
const out = new Rete.Output("json", "JSON", this.jsonSocket);
Expand Down
11 changes: 6 additions & 5 deletions ui/src/rete/components/RequestComponent.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,23 @@ import { SelectControl } from "../controls/SelectControl";
export class RequestComponent extends Rete.Component {
path = ["New"];

constructor(jsonSocket) {
constructor(jsonSocket, dummyJsonSocket) {
super("Request");
this.data.component = DefaultNode; // optional
this.jsonSocket = jsonSocket;
this.dummyJsonSocket = dummyJsonSocket;
}

builder(node) {
const jsonInput = new Rete.Input(
const dummyJsonInput = new Rete.Input(
"json",
"Dummy Output (JSON)",
this.jsonSocket
"Expected (DummyJSON)",
this.dummyJsonSocket
);
const out = new Rete.Output("json", "JSON", this.jsonSocket);

return node
.addInput(jsonInput)
.addInput(dummyJsonInput)
.addControl(
new SelectControl(this.editor, "type", node, false, "Type", [
"QUERY",
Expand Down
2 changes: 1 addition & 1 deletion ui/src/rete/components/SQLiteComponent.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export class SQLiteComponent extends Rete.Component {
builder(node) {
const dummyJsonInput = new Rete.Input(
"json",
"Output (DummyJSON)",
"Expected (DummyJSON)",
this.dummyJsonSocket
);
const out = new Rete.Output("json", "JSON", this.jsonSocket);
Expand Down
2 changes: 1 addition & 1 deletion ui/src/rete/components/input/DummyJsonComponent.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export class DummyJsonComponent extends Rete.Component {
}

builder(node) {
const out = new Rete.Output("json", "JSON", this.socket);
const out = new Rete.Output("json", "DummyJSON", this.socket);

return node
.addControl(new JsonControl(this.editor, "json", node))
Expand Down
23 changes: 23 additions & 0 deletions ui/src/rete/components/input/UrlComponent.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import Rete from "rete";
import { UrlControl } from "../../controls/UrlControl";

export class UrlComponent extends Rete.Component {
path = ["New"];

constructor(socket) {
super("URL");
this.socket = socket;
}

builder(node) {
const out = new Rete.Output("url", "URL", this.socket);

return node
.addControl(new UrlControl(this.editor, "url", node))
.addOutput(out);
}

worker(node, _, outputs) {
outputs.url = node.data.url;
}
}
60 changes: 60 additions & 0 deletions ui/src/rete/components/input/UrlWithPathParamComponent.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import Rete from "rete";
import { UrlWithPathParamControl } from "../../controls/UrlWithPathParamControl";

export class UrlWithPathParamComponent extends Rete.Component {
path = ["New"];

constructor(socket, jsonSocket) {
super("URLWithPathParam");
this.socket = socket;
this.jsonSocket = jsonSocket;
}

builder(node) {
const input = new Rete.Input(
"pathParams",
"PathParams (JSON)",
this.jsonSocket
);
const out = new Rete.Output("url", "URL", this.socket);

return node
.addInput(input)
.addControl(
new UrlWithPathParamControl(this.editor, "unFormattedUrl", node)
)
.addOutput(out);
}

worker(node, inputs) {
const pathParams = inputs.pathParams.length
? inputs.pathParams[0]
: node.data.pathParams;
const { unFormattedUrl } = node.data;

if (
pathParams &&
(unFormattedUrl.startsWith("https://") ||
unFormattedUrl.startsWith("http://"))
) {
const urlElements = unFormattedUrl.split("/");
if (urlElements.length > 3) {
const formatterUrl = `${urlElements[0]}//${urlElements[2]}/${urlElements
.filter((_, i) => i > 2)
.map((v) => {
if (v.startsWith(":")) {
const key = v.slice(1);
return JSON.parse(pathParams)[key] || v;
}
return v;
})
.join("/")}`;

this.editor.nodes
.find((n) => n.id === node.id)
.controls.get("unFormattedUrl")
.setValue(unFormattedUrl, formatterUrl);
}
}
}
}
43 changes: 43 additions & 0 deletions ui/src/rete/controls/EditableUrlComponent.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import React, { useState } from "react";
import Editor from "react-simple-code-editor";
import { highlight, languages } from "prismjs/components/prism-core";
import "prismjs/components/prism-uri";
import "prismjs/themes/prism.css";
import useInterval from "use-interval";

export const EditableUrlComponent = ({ value, onChange }) => {
const [code, setCode] = useState(value);
const [warn, setWarn] = useState(false);
const [stack, setStack] = useState(null);
useInterval(() => {
if (stack !== null) {
import("react-toastify").then(({ toast }) => toast.error(stack));
setStack(null);
}
}, 10000);

return (
<Editor
value={code}
onValueChange={(c) => {
if (c.startsWith("https://") || c.startsWith("http://")) {
setWarn(false);
setStack(null);
} else {
setStack("URL doesn't start with https:// or http://");
setWarn(true);
}
setCode(c);
onChange(c);
}}
highlight={(c) => highlight(c, languages.uri)}
padding={10}
style={{
fontFamily: '"Fira code", "Fira Mono", monospace',
fontSize: 12,
background: warn ? "rgba(255, 0, 80, 0.7)" : "#FFF",
maxWidth: "450px",
}}
/>
);
};