Skip to content

Commit

Permalink
Raytha Functions documentation #187
Browse files Browse the repository at this point in the history
  • Loading branch information
apexdodge committed Apr 7, 2024
1 parent 5e7ade5 commit af0aaed
Show file tree
Hide file tree
Showing 8 changed files with 354 additions and 0 deletions.
154 changes: 154 additions & 0 deletions docfx_project/articles/embeddable_functions_builtinobjects.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
# Built-in Objects for Raytha Functions

Raytha Functions provides you with access to the service layer and other functionality so that you can build more powerful applications.

| Object | Notes |
| ------------------------------ | ------------------|
| API_V1 | API to Raytha's Service Layer |
| CurrentOrganization | Object with access to the current org settings like name, timezone, etc. |
| CurrentUser | Information about the current logged in user |
| Emailer | Send an email from the platform |
| HttpClient | Make an external API call |

## API_V1

API_V1 is set to mirror the functionality offered by the out of the box Headless REST API that you can see at your website's /raytha/api route.

A very basic example usage is shown below.

```
function get(query) {
var response = API_V1.GetContentItems('posts');
return new JsonResult(response);
}
function post(payload, query) {
let bobsValue = payload.find(item => item.Key === "bob").Value[0];
let janesValue = payload.find(item => item.Key === "jane").Value[0];
let content = {
'title': bobsValue,
'tinymce': janesValue
};
let detail_view_template_id = '1vVCcIYeeE-dMQjbYGq_ng';
let result = API_V1.CreateContentItem('posts', false, detail_view_template_id, content);
return new JsonResult(result);
}
```

In the code base, you can find the API in Raytha.Infrastructure > RaythaFunctions > RaythaFunctionApi_V1.cs if you plan to modify the code base and add functions here.

The out of the box function definitions are:

```
//Content items
IQueryResponseDto<ListResultDto<ContentItemDto>> GetContentItems(string contentTypeDeveloperName, string viewId = "", string search = "", string filter = "", string orderBy = "", int pageNumber = 1, int pageSize = 50)
IQueryResponseDto<ListResultDto<DeletedContentItemDto>> GetDeletedContentItems(string contentTypeDeveloperName, string search = "", string orderBy = "", int pageNumber = 1, int pageSize = 50)
IQueryResponseDto<ContentItemDto> GetContentItemById(string contentItemId)
ICommandResponseDto<ShortGuid> CreateContentItem(string contentTypeDeveloperName, bool saveAsDraft, string templateId, IDictionary<string, object> content)
ICommandResponseDto<ShortGuid> EditContentItem(string contentItemId, bool saveAsDraft, IDictionary<string, object> content)
ICommandResponseDto<ShortGuid> EditContentItemSettings(string contentItemId, string templateId, string routePath)
ICommandResponseDto<ShortGuid> UnpublishContentItem(string contentItemId)
ICommandResponseDto<ShortGuid> DeleteContentItem(string contentItemId)
IQueryResponseDto<RouteDto> GetRouteByPath(string routePath)
//Content types
IQueryResponseDto<ListResultDto<ContentTypeDto>> GetContentTypes(string search = "", string orderBy = "", int pageNumber = 1, int pageSize = 50)
IQueryResponseDto<ContentTypeDto> GetContentTypeByDeveloperName(string contentTypeDeveloperName)
//Media items
IQueryResponseDto<ListResultDto<MediaItemDto>> GetMediaItems(string search = "", string orderBy = "", int pageNumber = 1, int pageSize = 50)
IQueryResponseDto<string> GetMediaItemUrlByObjectKey(string objectKey)
//User groups
IQueryResponseDto<ListResultDto<UserGroupDto>> GetUserGroups(string search = "", string orderBy = "", int pageNumber = 1, int pageSize = 50)
IQueryResponseDto<UserGroupDto> GetUserGroupById(string userGroupId)
ICommandResponseDto<ShortGuid> CreateUserGroup(string developerName, string label)
ICommandResponseDto<ShortGuid> EditUserGroup(string userGroupId, string label)
ICommandResponseDto<ShortGuid> DeleteUserGroup(string userGroupId)
//Users
IQueryResponseDto<ListResultDto<UserDto>> GetUsers(string search = "", string orderBy = "", int pageNumber = 1, int pageSize = 50)
IQueryResponseDto<UserDto> GetUserById(string userId)
ICommandResponseDto<ShortGuid> CreateUser(string emailAddress, string firstName, string lastName, bool sendEmail, dynamic userGroups)
ICommandResponseDto<ShortGuid> EditUser(string userId, string emailAddress, string firstName, string lastName, dynamic userGroups)
ICommandResponseDto<ShortGuid> DeleteUser(string userId)
ICommandResponseDto<ShortGuid> ResetPassword(string userId, bool sendEmail, string newPassword)
ICommandResponseDto<ShortGuid> SetIsActive(string userId, bool isActive)
//Templates
IQueryResponseDto<ListResultDto<WebTemplateDto>> GetWebTemplates(string search = "", string orderBy = "", int pageNumber = 1, int pageSize = 50)
IQueryResponseDto<WebTemplateDto> GetWebTemplateById(string webTemplateId)
//Functions
ICommandResponseDto<object> ExecuteRaythaFunction(string developerName, string requestMethod, string queryJson, string payloadJson)
```

## CurrentUser

`CurrentUser` offers the same information that you might find if you are creating a template and are inserting a variable for the CurrentUser object. A good way to see all of the output available for CurrentUser is to run this GET request.

```
function get(query) {
return new JsonResult(CurrentUser);
}
```

Information includes name, email, whether they are authenticated or not, permissions & roles, user groups, if they are an admin, and their authentication method.

## CurrentOrganization

`CurrentOrganization` offers the same information that you might find if you are creating a template and are inserting a variable for the CurrentOrganization object. A good way to see all of the output available for CurrentUser is to run this GET request.

```
function get(query) {
return new JsonResult(CurrentOrganization);
}
```

Information includes available authentication methods, available content types and their field configs, organization name, default SMTP from address, system timezone, and other info.

## Emailer

Raytha gives access to the Emailer, which is the same Emailer used for other email functionality such as resetting password and registration emails. You might find it useful to have access to this emailer for scenarios such as sending an email when you receive a form submission into a `post()`.

You need to provide the subject line, content, email of recipient, and reply-to information, which you could also grab from `CurrentOrganization.SmtpDefaultFromName` and `CurrentOrganization.SmtpDefaultFromAddress` if you prefer.

You provide this information to `EmailMessage.From(subject, content, recipientEmail, fromEmail, fromName)`;

You then use `Emailer.SendEmail(emailMsg)` to send the email out. See the example below.

```
function post(payload, query) {
var emailMsg = EmailMessage.From("Test subject", "Test content", "test@test.com", "me@test.com", "me");
Emailer.SendEmail(emailMsg);
return new JsonResult({ success: true });
}
```

## HttpClient

Making api calls to external services is an essential part of any application. Raytha provides a wrapper over .NET's HttpClient. The wrapper includes a method for each of the main HTTP methods.

```
Get(string url, IDictionary<string, object> headers = null)
Post(string url, IDictionary<string, object> headers = null, IDictionary<string, object> body = null, bool json = true)
Put(string url, IDictionary<string, object> headers = null, IDictionary<string, object> body = null, bool json = true)
Delete(string url, IDictionary<string, object> headers = null)
```

The example below is a sample for making an API call to api2pdf.com's API for generating a PDF file.

```
function get(query) {
var payload = {
"html": "<p>Hello World</p>"
};
var headers = {
"Authorization": "YOUR-API-KEY-HERE"
};
var response = HttpClient.Post("https://v2.api2pdf.com/chrome/pdf/html", headers=headers, body=payload);
result = JSON.parse(response);
return new RedirectResult(result.FileUrl);
}
```

139 changes: 139 additions & 0 deletions docfx_project/articles/embeddable_functions_httprequest.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
# Http Request Trigger Type for Raytha Functions

## The Structure

When you create a Raytha Function with an `Http Request` trigger, this automatically creates an endpoint that is accessible at the following URL pattern:

> /raytha/functions/execute/{developerName}
The developer name is specified when you create the function in the Raytha platform.

<img class="inline-img" src="../images/functions_developername.png" />

At this endpoint, you can submit GET and POST requests so long as you keep the structure of the functions that are provided to you in boilerplate fashion. This means you need to implement `get(query)` and `post(payload, query)`

The default code provided to you is the following:

```
/** The following classes are available:
* API_V1
* CurrentOrganization
* CurrentUser
* Emailer
* HttpClient
*/
/**
* Receives a get request at /raytha/functions/execute/{developerName}
* @param {IQueryCollection} query Passed in from .NET's Request.Query
* @returns {object} of type JsonResult, HtmlResult, RedirectResult, or StatusCodeResult
*/
function get(query) {
return new JsonResult({ success: true });
//example 1: return new HtmlResult("<p>Hello World</p>");
//example 2: return new RedirectResult("https://raytha.com");
//example 3: return new StatusCodeResult(404, "Not Found");
}
/**
* Receives a post request at /raytha/functions/execute/{developerName}
* @param {IFormCollection} payload Passed in from .NET's Request.Form
* @param {IQueryCollection} query Passed in from .NET's Request.Query
* @returns {object} of type JsonResult, HtmlResult, RedirectResult, or StatusCodeResult
*/
function post(payload, query) {
return new JsonResult({ success: true });
//example 1: return new HtmlResult("<p>Hello World</p>");
//example 2: return new RedirectResult("https://raytha.com");
//example 3: return new StatusCodeResult(404, "Not Found");
}
```

## Return types

When you return from the `get` or `post` functions, Raytha is expecting an object of one of the following types:

* `JsonResult(object)`
* `HtmlResult(string: html)`
* `RedirectResult(string: url)`
* `StatusCodeResult(int: status_code, string: message)`

The above section includes commented out examples of each.

## GET endpoint

If you receive a GET request, Raytha will run the `get(query)` function. The paramater provided here will populate with a collection of query parameters that were provided as part of the request. For example, `/raytha/functions/execute/myfunction?bob=1&jane=2` will come through in query parameter like so:

```
[
{
"Key": "bob",
"Value": [
"1"
]
},
{
"Key": "jane",
"Value": [
"2"
]
}
]
```

A good way to test is to simply return the object back out in a JsonResult like so:

```
function get(query) {
return new JsonResult(query);
}
```

To pull the values out in the example above, you can use standard javascript.

```
function get(query) {
let bobsValue = query.find(item => item.Key === "bob").Value[0];
let janesValue = query.find(item => item.Key === "jane").Value[0];
return new JsonResult({
'Bob': bobsValue,
'Jane': janesValue
});
}
```

## POST endpoint

Everything from the `GET endpoint` above applies to the POST endpoint as well, with the only difference being that there is a payload object which includes the body of the request, for situations such as receiving a form submission or posted JSON.

If a Request.Form was submitted, `payload` outputs in a similar manner:

```
[
{
"Key": "bob",
"Value": [
"1"
]
},
{
"Key": "jane",
"Value": [
"2"
]
}
]
Otherwise, if you posted JSON, it will pass it through.
```

<img class="inline-img" src="../images/functions_httppost.png" />

## Next

To get the real value out of Raytha Functions, you pair the above with the built-in objects and API layer that is made accessible to you.

[Learn how to make use of built-in objects](/articles/embeddable_functions_builtinobjects.html).



50 changes: 50 additions & 0 deletions docfx_project/articles/embeddable_functions_intro.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# Embed Functions Inside Raytha with Custom Code

## Introduction to Raytha Functions

Raytha Functions are a way to write custom code in the administrator portal of Raytha to add functionality to your application. Use cases for this include but are not limited to:

* Create your own custom api endpoints
* Accept form submissions and save response
* Send an email out of the platform
* Make an external HTTP call and return and/or save result
* [Coming Soon] Webhooks trigger functionality
* [Coming Soon] Timer trigger functionality

In a way, it is effectively writing "code behind" directly into the platform.

<img class="inline-img" src="../images/functions_sidebar.png" />

## Writing code behind

When you write code for a Raytha Function there are few items you need to be aware of.

* <strong>Write your code in javascript.</strong> The code is compiled and run using Microsoft's ClearScript engine which works with V8 implementation of javascript. This gives you access to basic engine javascript.
* <strong>Triggers.</strong> Functions are triggered by some action. You select the trigger type when you create the function.
* <strong>Built-in objects.</strong> The javascript by itself would not be of much use if you did not have layer of access to the database and other core functionality.

## Triggers

Raytha Functions are triggered by some action. You select the trigger type when you create the function.

<img class="inline-img" src="../images/functions_triggertype.png" />

Triggers come with boilerplate code that the ClearScript engine runs when necessary. Click the link below to learn how to write code for each trigger type.

* [Http Request](/articles/embeddable_functions_httprequest.html)
* [Coming Soon] Timer
* [Coming Soon] Webhook

## Built-in Objects

To provide valuable functionality to you while you write Raytha Functions, the following objects are included in the ClearScript engine that you can call.

| Object | Notes |
| ------------------------------ | ------------------|
| API_V1 | API to Raytha's Application Layer |
| CurrentOrganization | Object with access to the current org settings like name, timezone, etc. |
| CurrentUser | Information about the current logged in user |
| Emailer | Send an email from the platform |
| HttpClient | Make an external API call |

[Learn how to make use of these objects](/articles/embeddable_functions_builtinobjects.html).
11 changes: 11 additions & 0 deletions docfx_project/articles/toc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,17 @@
- name: OData in Templates
href: templates_odata.md

- name: Raytha Functions
items:
- name: Intro
href: embeddable_functions_intro.md

- name: Http Request Trigger
href: embeddable_functions_httprequest.md

- name: Built-in Objects
href: embeddable_functions_builtinobjects.md

- name: Background tasks
href: background_tasks.md

Expand Down
Binary file added docfx_project/images/functions_developername.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docfx_project/images/functions_httppost.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docfx_project/images/functions_sidebar.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docfx_project/images/functions_triggertype.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit af0aaed

Please sign in to comment.