Skip to content

Commit

Permalink
Merge pull request #3693 from MoShizzle/arbitrary-request
Browse files Browse the repository at this point in the history
feat: arbitrary http request action
  • Loading branch information
abuaboud committed Jan 18, 2024
2 parents bc92d3e + b887451 commit da5e53e
Show file tree
Hide file tree
Showing 5 changed files with 137 additions and 6 deletions.
31 changes: 31 additions & 0 deletions docs/developers/piece-reference/custom-api-calls.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
---
title: "Enable Custom API Calls"
description: "Learn how to enable custom API calls for your pieces"
icon: 'circle-3'
---

Custom API Calls allow the user to send a request to a specific endpoint if no action has been implemented for it. This will show in the actions list of the piece as `Custom API Call`.

To enable this action for a piece, you need to call the `createCustomApiCallAction` in your actions array.

## Example

The example below implements the action for the OpenAI piece. The OpenAI piece uses a `Bearer token` authorization header to identify the user sending the request.

```typescript
actions: [
...yourActions,
createCustomApiCallAction({
// The auth object defined in the piece
auth: openaiAuth,
// The base URL for the API
baseUrl: 'https://api.openai.com/v1',
// Mapping the auth object to the needed authorization headers
authMapping: (auth: PieceAuthProperty) => {
return {
'Authorization': `Bearer ${auth}`
}
}
})
]
```
2 changes: 1 addition & 1 deletion packages/pieces/common/package.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"name": "@activepieces/pieces-common",
"version": "0.2.5",
"version": "0.2.6",
"type": "commonjs"
}
93 changes: 92 additions & 1 deletion packages/pieces/common/src/lib/helpers/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { OAuth2PropertyValue } from "@activepieces/pieces-framework";
import { OAuth2PropertyValue, PieceAuthProperty, Property, createAction } from "@activepieces/pieces-framework";
import { HttpError, HttpHeaders, HttpMethod, HttpRequest, QueryParams, httpClient } from "../http";
import { assertNotNullOrUndefined } from "@activepieces/shared";

export const getAccessTokenOrThrow = (auth: OAuth2PropertyValue | undefined): string => {
const accessToken = auth?.access_token;
Expand All @@ -10,3 +12,92 @@ export const getAccessTokenOrThrow = (auth: OAuth2PropertyValue | undefined): st
return accessToken;
};

export function createCustomApiCallAction({ auth, baseUrl, authMapping }: {
auth?: PieceAuthProperty,
baseUrl: string,
authMapping?: (auth: PieceAuthProperty) => HttpHeaders
}) {
return createAction({
name: 'custom_api_call',
displayName: 'Custom API Call',
description: 'Send a custom API call to a specific endpoint',
auth: auth ? auth : undefined,
props: {
url: Property.ShortText({
displayName: 'URL',
description: 'The endpoint to use. For example, `/models`',
required: true,
}),
method: Property.StaticDropdown({
displayName: 'Method',
required: true,
options: {
options: Object.values(HttpMethod).map(v => {
return {
label: v,
value: v,
}
})
}
}),
headers: Property.Object({
displayName: 'Headers',
description: 'Authorization headers are injected automatically from your connection.',
required: true,
}),
queryParams: Property.Object({
displayName: 'Query Parameters',
required: true,
}),
body: Property.Json({
displayName: 'Body',
required: false,
}),
failsafe: Property.Checkbox({
displayName: 'No Error on Failure',
required: false,
}),
timeout: Property.Number({
displayName: 'Timeout (in seconds)',
required: false,
}),
},

run: async (context) => {
const { method, url, headers, queryParams, body, failsafe, timeout } =
context.propsValue;

assertNotNullOrUndefined(method, 'Method');
assertNotNullOrUndefined(url, 'URL');

let headersValue = headers as HttpHeaders;
if (authMapping) {
headersValue = {
...headersValue,
...authMapping(context.auth as PieceAuthProperty)
}
}

const request: HttpRequest<Record<string, unknown>> = {
method,
url: `${baseUrl}${url}`,
headers: headersValue,
queryParams: queryParams as QueryParams,
timeout: timeout ? timeout * 1000 : 0,
};

if (body) {
request.body = body;
}

try {
return await httpClient.sendRequest(request);
} catch (error) {
if (failsafe) {
return (error as HttpError).errorMessage()
}
throw error;
}
}
})
}
2 changes: 1 addition & 1 deletion packages/pieces/openai/package.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{
"name": "@activepieces/piece-openai",
"version": "0.3.14"
"version": "0.3.15"
}
15 changes: 12 additions & 3 deletions packages/pieces/openai/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { PieceAuth, createPiece } from '@activepieces/pieces-framework';
import { PieceAuth, PieceAuthProperty, createPiece } from '@activepieces/pieces-framework';
import { askOpenAI } from './lib/actions/send-prompt';
import { transcribeAction } from './lib/actions/transcriptions';
import { translateAction } from './lib/actions/translation';
import { AuthenticationType, HttpMethod, httpClient } from '@activepieces/pieces-common';
import { AuthenticationType, HttpMethod, createCustomApiCallAction, httpClient } from '@activepieces/pieces-common';
import { generateImage } from './lib/actions/generate-image';
import { visionPrompt } from './lib/actions/vision-prompt';
import { textToSpeech } from './lib/actions/text-to-speech';
Expand Down Expand Up @@ -59,7 +59,16 @@ export const openai = createPiece({
textToSpeech,
transcribeAction,
translateAction,
createCustomApiCallAction({
auth: openaiAuth,
baseUrl: 'https://api.openai.com/v1',
authMapping: (auth: PieceAuthProperty) => {
return {
'Authorization': `Bearer ${auth}`
}
}
})
],
authors: ['aboudzein', 'creed983', 'astorozhevsky', 'Salem-Alaa', 'MoShizzle'],
triggers: []
triggers: [],
});

0 comments on commit da5e53e

Please sign in to comment.