-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #84 from MisterGC/better-webaccess
Wrapper for ClayWebAccess which allows declaring HTTP endpoints and generates a client JS object using the declaration (incl. dedicated Sandbox).
- Loading branch information
Showing
6 changed files
with
418 additions
and
19 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
// (c) Clayground Contributors - MIT License, see "LICENSE" file | ||
|
||
import QtQuick | ||
import Clayground.Network | ||
|
||
// Component that generates an easy to use API based on provided | ||
// endpoint and authorization configuration. | ||
Item { | ||
id: _clayHttpClient | ||
|
||
// END POINT CONFIGURATION | ||
|
||
// There is only one base URL per client | ||
// this allows keeping the (relative) URLs in the endpoints short | ||
// Example: https://acme.com/products | ||
property string baseUrl: "" | ||
|
||
// Endpoints, each entry with the following structure: | ||
// {HTTP_METHOD} {urlWithPathAndQueryParams} [{nameOfJsonBody}] | ||
// Example: GET flyingObjects/{type} {aerodynamicRequirements} | ||
// This will generate a method with client.api.flyingObjects("ufo", "{friction: low}"} | ||
property var endpoints: ({}) | ||
|
||
// Object which contains all the methods based on the baseUrl and | ||
// end point configuration. | ||
property var api: ({}) | ||
|
||
|
||
// AUTHENTICATION/AUTHORIZATION | ||
// TODO Add support for basic auth and API keys | ||
|
||
// When using Bearer Authentication | ||
// Syntax: {token} | ||
property string bearerToken: "" | ||
|
||
|
||
// RESULT REPORTING | ||
|
||
// method has been executed successfully | ||
signal reply(int requestId, int returnCode, string text); | ||
|
||
// an error happened during execution | ||
signal error(int requestId, int returnCode, string text); | ||
|
||
|
||
onBaseUrlChanged: _updateServiceAccess() | ||
onEndpointsChanged: _updateServiceAccess() | ||
|
||
ClayWebAccess { | ||
id: _webAccess | ||
onReply: (reqId, returnCode, result) => { | ||
_clayHttpClient.reply(reqId, returnCode, result) | ||
} | ||
onError: (reqId, returnCode, result) => { | ||
_clayHttpClient.error(reqId, returnCode, result) | ||
} | ||
} | ||
|
||
function _updateServiceAccess() { | ||
_clayHttpClient.api = {}; | ||
|
||
var authString = ""; | ||
if (_clayHttpClient.bearerToken !== "") { | ||
authString = "Bearer " + _clayHttpClient.bearerToken; | ||
} | ||
|
||
for (var endpoint in _clayHttpClient.endpoints) { | ||
var parts = _clayHttpClient.endpoints[endpoint].split(' '); | ||
var httpMethod = parts[0].toUpperCase(); | ||
var endpointUrl = parts[1]; | ||
var jsonName = parts.length > 2 ? parts[2] : ""; | ||
|
||
// Ensure that every function has its relevant argument | ||
// values otherwise all would just reference the last | ||
// values of endpointUrl, httpMethod and jsonName | ||
(function(endpointUrl, httpMethod, jsonName) { | ||
_clayHttpClient.api[endpoint] = function() { | ||
var url = _clayHttpClient.baseUrl + "/" + endpointUrl; | ||
var args = Array.prototype.slice.call(arguments); | ||
url = url.replace(/\{.*?\}/g, function() { | ||
return args.shift(); | ||
}); | ||
switch (httpMethod) { | ||
case "GET": | ||
return _webAccess.get(url, authString); | ||
case "POST": | ||
var json = jsonName !== "" && args.length ? args[args.length - 1] : ""; | ||
if (typeof json == "object" && json !== null && !Array.isArray(json)) | ||
json = JSON.stringify(json); | ||
return _webAccess.post(url, json, authString); | ||
} | ||
} | ||
})(endpointUrl, httpMethod, jsonName); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,128 @@ | ||
// (c) Clayground Contributors - MIT License, see "LICENSE" file | ||
|
||
import QtQuick | ||
import QtQuick.Controls | ||
import Clayground.Network | ||
|
||
Rectangle { | ||
anchors.fill: parent | ||
color: "black" | ||
|
||
ClayHttpClient | ||
{ | ||
id: openAi | ||
|
||
baseUrl: "https://api.openai.com" | ||
endpoints: ({ | ||
complete: "POST v1/chat/completions {chat}" | ||
}) | ||
// TODO: Change path to a file which contains the API key | ||
// or put env.{my-variable-name} if it should be read from a | ||
// env variable | ||
bearerToken: "file:///path/to/bearer_token.txt" | ||
|
||
onReply: (requestId, returnCode, text) => { | ||
const reply = JSON.parse(text); | ||
text = reply.choices[0].message.content; | ||
messageModel.append({"source": "ChatAi", "message": text}); | ||
} | ||
onError: (requestId, returnCode, text) => {txt.text = text; } | ||
|
||
function complete(message) | ||
{ | ||
let client = openAi.api; | ||
const requestObj = { | ||
model: "gpt-3.5-turbo", | ||
messages: [{ | ||
role: "user", | ||
content: message | ||
}] | ||
}; | ||
let requestId = client.complete(requestObj); | ||
} | ||
|
||
Component.onCompleted: { | ||
// TODO: Activate if you want to see the chat API | ||
// in action, don't forget to reference a valid | ||
// Bearer token. | ||
// complete("What is the meaning of life?"); | ||
} | ||
} | ||
|
||
ClayHttpClient | ||
{ | ||
id: jsonPlaceholder | ||
|
||
baseUrl: "https://jsonplaceholder.typicode.com" | ||
endpoints: ({ | ||
pubPost: "POST posts {data}", | ||
getPost: "GET posts/{postId}" | ||
}) | ||
|
||
onReply: (requestId, returnCode, text) => {txt.text = text; } | ||
onError: (requestId, returnCode, text) => {txt.text = text; } | ||
|
||
function demo() { | ||
let client = jsonPlaceholder.api; | ||
let requestId = client.pubPost(JSON.stringify({"hohoh": "world"})); | ||
//Hint: There are already 100 posts, 101 is the newly added one | ||
requestId = client.getPost(101); | ||
} | ||
|
||
Component.onCompleted: { | ||
// TODO: Uncomment to see the placeholder api in action | ||
// demo() | ||
} | ||
} | ||
|
||
ListView { | ||
id: messageList | ||
anchors.fill: parent | ||
anchors.margins: 10 | ||
anchors.bottomMargin: 50 | ||
|
||
model: ListModel { | ||
id: messageModel | ||
} | ||
|
||
delegate: Rectangle { | ||
width: messageList.width | ||
height: messageText.implicitHeight + 10 | ||
color: index % 2 === 0 ? "#303030" : "#4d4d4d" | ||
|
||
Text { | ||
id: messageText | ||
color: "white" | ||
width: parent.width - 10 | ||
anchors.centerIn: parent | ||
text: model.source + ": " + model.message | ||
wrapMode: Text.Wrap | ||
} | ||
} | ||
} | ||
|
||
TextField { | ||
id: messageField | ||
anchors.bottom: parent.bottom | ||
width: parent.width | ||
placeholderText: "Enter message" | ||
color: "white" | ||
|
||
onAccepted: { | ||
messageModel.append({"source": "You", "message": text}); | ||
openAi.complete(text); | ||
text = ""; | ||
messageList.positionViewAtEnd(); | ||
} | ||
} | ||
|
||
Text { | ||
id: txt | ||
width: parent.width * .75 | ||
wrapMode: Text.WordWrap | ||
anchors.centerIn: parent | ||
color: "white" | ||
font.family: "Monospace" | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.