Building an "Add Destination" Connection Form
This guide demonstrates building a dynamic "Add Destination" form to allow your users to test & connect their destinations.
Step 1: [Server side] Set up scoped auth token generation
In your backend, build an API endpoint that makes a POST
to https://api.prequel.co/actions/generate-scoped-auth-token
to request to generate a scoped auth token from the Prequel API. Be sure to pass your API Key as a header (X-API-KEY
) in the request as well as the desired API version (X-Prequel-Api-Version
). Your API endpoint should return the scoped token that was returned from the Prequel API.
Note: If you are using a self-hosted deployment or a non-US deployment, replace api.prequel.co
with the appropriate host.
POST request body
This request body is for the API Version 2023-12-01
. Your POST
request body should have the following structure:
Parameter | Type | Notes |
---|---|---|
application_origin | string | The application host for your React app that will be making requests to the Prequel API using the generated scoped auth token. |
recipient_id | string | The Recipient ID for your customer. This value should be derived in your backend from a server-side token or your preferred method to associate user sessions with Recipient IDs. |
destination | Object | This is the Destination object sent from the Prequel React hooks. You can perform any validation on the object that you wish and send it on to the Prequel API. |
Example request body
{
"application_origin": "app.example.co",
"recipient_id": "1abc234d-efg5-6h7i-j8k9-012345lm6nop",
"destination": <destination_object>
}
Getting the Recipient ID
The recipient_id
is Prequel's unique identifier for the recipient to which the destination is being added. In your system, there is a separate identifier for that customer. You can either you can look them up using the API or track Prequel's recipient UUIDs in your system.
POST response body
The POST
response body will have the following structure:
Parameter | Type | Notes |
---|---|---|
scoped_token | string | The scoped auth token generated for the specific destination context supplied in the request. |
Example response body
{
"scoped_token": "eyJhb..."
}
Note: scoped auth tokens have a TTL of one hour.
Step 2: [Client side] Set up fetchToken
calls
fetchToken
callsIn your frontend, define a set of fetchToken
functions. These functions will consume various inputs (see examples below) and query the API endpoint you built in Step 1 to generate auth tokens required by the Prequel API. These fetchToken
functions will be used as parameters to and called by Prequel's React hooks.
There are two fetchToken
types you will need to implement, depending on the hooks you use:
export type FetchAuthToken = () => Promise<string>;
export type FetchAuthTokenWithDestination = (d: PreparedDestination) => Promise<string>;
Example: FetchAuthToken
FetchAuthToken
Required by: useModels
, useProducts
hooks
This function contains an empty request body (as should your subsequent request to the Prequel API) because there is no relevant customer-specific scoping required for the fetching of your organization's models and products.
const fetchToken: (d: PreparedDestination) => Promise<string> = (destination) =>
fetch(`https://api.example.co/generate-auth-token`, {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: {},
})
.then((response: Response) => response.json())
.then((body) => body.scoped_token)
.catch((reason) => {
console.error(reason);
});
Example: FetchAuthTokenWithDestination
FetchAuthTokenWithDestination
Required by: useCreateDestination
, useTestConnection
hooks
This function passes a destination object as the request body (in addition to - not in place of - to subsequent requests to the Prequel API) so that the generated token can be appropriately scoped to a specific destination.
const fetchTokenWithDestination: (d: PreparedDestination) => Promise<string> = (destination) =>
fetch(`https://api.example.co/generate-auth-token`, {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(destination),
})
.then((response: Response) => response.json())
.then((body) => body.scoped_token)
.catch((reason) => {
console.error(reason);
});
Step 3: [Client side] Install Prequel React hooks
Install the @prequel/react
package from npm.
npm install @prequel/react@latest
Step 4: [Client side] Render the form
In your frontend, define a DestinationForm
component. The component will leverage the useDestination
hook and the useDestinationForm
hook to render a dynamic form that can be used to test & add a new destination. A brief example is show below. See our sample React app for a more comprehensive implementation.
const DestinationForm = () => {
const formRef = useRef<HTMLFormElement>(null);
const [destination, setDestination] = useDestination({
name: "Customer A Snowflake Destination", // Readable name for the destination
});
const destinationForm = useDestinationForm(
destination,
PREQUEL_ORG_ID, // the UUID for your organization in Prequel
true, // Optional (default false): hide any non-user facing fields like "name"
PREQUEL_HOST, // Optional (default api.prequel.co): the host url of your Prequel API
"snowflake" // Optional (default undefined): vendor to filter the form to
);
const createDestination = useCreateDestination(
fetchTokenWithDestination, // the fetchToken function you created in step 2
"app.example.co", // the origin of your React app (used to allow CORS)
PREQUEL_HOST // the host url of your Prequel API
);
// This is the PreparedDestination you can pass to testConnection and createDestination
const preparedDestination = useMemo(
() => prepareDestinationWithForm(destination, destinationForm),
[destination, destinationForm]
);
if (!destinationForm) {
return (
<div className="d-flex justify-content-center">
<Spinner animation="border" role="status">
<span className="visually-hidden">Loading...</span>
</Spinner>
</div>
);
}
return (
<Form ref={formRef} className="d-flex flex-column" onSubmit={onSubmit}>
{destinationForm.map((section) => (
<Fragment key={section.id}>
<Form.Group>
{/* Render the section title and subtitle... */}
{section.fields.map((field) => {
{/* Render the field... */}
})}
</Form.Group>
</Fragment>
))}
<Button type="submit">Submit form</Button>
</Form>
);
}
Step 5: [Client side] Test and create destinations
Once your form is rendering as desired, you should augment form functionality to test a destination connection before creating that destination. It's recommended that you only allow users to create destinations that are connecting successfully. You can leverage the useTestConnection
hook as demonstrated below. See our sample React app for a more comprehensive implementation.
const TestConnectionComponent = ({ preparedDestination }) => {
const [testRunning, setTestRunning] = useState(false);
const [testResult, setTestResult] = useState<string | null>(null);
const testConnection = useTestConnection(
fetchTokenWithDestination, // the fetchToken function you created in step 2
"app.example.co", // the origin of your React app (used to allow CORS)
PREQUEL_HOST // the host url of your Prequel API
);
async function testDestinationConnection() {
setTestRunning(true);
setTestResult("Testing new connection...");
const { data, message } = await testConnection(preparedDestination);
if (data) {
setTestResult("Connection test successful.");
} else {
setTestResult(message);
}
setTestRunning(false);
}
return (
<div>
{/* Render connection information as desired... */}
</div>
)
}
Updated 7 months ago