Take Action on Behalf of a User
Introduction
In this tutorial, you'll use a lambda connector to add custom business logic to your application that takes action on behalf of a user.
This tutorial should take about five minutes.
Step 1. Initialize a new local DDN project
ddn supergraph init lambda-tutorial --with-promptql
Step 2. Initialize the lambda connector
- TypeScript
- Python
- Go
ddn connector init my_ts -i
- Select
hasura/nodejs
from the list of connectors. - Choose a port (press enter to accept the default recommended by the CLI).
If you open the app/connector/my_ts
directory, you'll see the functions.ts
file generated by the CLI; this will be
the entrypoint for your connector.
ddn connector init my_python -i
- Select
hasura/python
from the list of connectors. - Choose a port (press enter to accept the default recommended by the CLI).
If you open the app/connector/my_python
directory, you'll see the functions.py
file generated by the CLI; this will
be the entrypoint for your connector.
ddn connector init my_go -i
- Select
hasura/go
from the list of connectors. - Choose a port (press enter to accept the default recommended by the CLI).
If you open the app/connector/my_go
directory, you'll see Go files in the functions
folder; these will serve as the
entrypoint for your connector.
Step 3. Add custom logic
- TypeScript
- Python
- Go
cd app/connector/my_ts && npm install
/*
* This interface defines the structure of the response object returned by the
* function that acts on behalf of a user. It includes a success status and a message.
* The success status is a boolean indicating whether the operation was
* successful or not.
*/
interface UserActionResponse {
success: boolean;
message: string;
}
/*
* This function simulates taking an action on behalf of a user. It logs the request made by the user
* and returns a response object indicating the success status and a message.
*
* @param {string} request - What the user wants to do
* @returns {UserActionResponse} - The response object containing success status and message
*/
export function takeActionOnBehalfOfUser(request: string): UserActionResponse {
// In a real application, you'd replace this with your custom business logic
console.log(`Taking action on behalf of user`);
return {
success: true,
message: `Successfully took action on user's behalf: ${request}`,
};
}
from hasura_ndc import start
from hasura_ndc.function_connector import FunctionConnector
from pydantic import BaseModel, Field
from hasura_ndc.errors import UnprocessableContent
from typing import Annotated
connector = FunctionConnector()
class UserActionArguments(BaseModel):
request: Annotated[str, Field(description="What the user wants to do")]
class UserActionResponse(BaseModel):
success: bool
message: str
@connector.register_mutation
def take_action_on_behalf_of_user(args: UserActionArguments) -> UserActionResponse:
# In a real application, you'd replace this with business logic
print("Taking action on behalf of user")
return UserActionResponse(
success=True,
message=f"Successfully took action on user's behalf: {args.request}"
)
if __name__ == "__main__":
start(connector)
package functions
import (
"context"
"fmt"
"hasura-ndc.dev/ndc-go/types"
)
// TakeActionArguments represents the input arguments for a user action.
type TakeActionArguments struct {
Request string `json:"request"`
}
// TakeActionResponse represents the response after performing a user action.
type TakeActionResponse struct {
Success bool `json:"success"`
Message string `json:"message"`
}
// ProcedureTakeActionOnBehalfOfUser simulates taking an action for the user.
func ProcedureTakeActionOnBehalfOfUser(
ctx context.Context,
state *types.State,
args *TakeActionArguments,
) (*TakeActionResponse, error) {
// In a real application, you'd replace this with your custom business logic
fmt.Println("Taking action on behalf of user")
return &TakeActionResponse{
Success: true,
Message: fmt.Sprintf("Successfully took action on user's behalf: %s", args.Request),
}, nil
}
Step 4. Introspect the source file(s)
- TypeScript
- Python
- Go
ddn connector introspect my_ts
# alternatively, use ddn command add my_ts "*" for bulk adds
ddn command add my_ts take_action_on_behalf_of_user
ddn connector introspect my_python
# alternatively, use ddn command add my_python "*" for bulk adds
ddn command add my_python take_action_on_behalf_of_user
ddn connector introspect my_go
# alternatively, use ddn command add my_go "*" for bulk adds
ddn command add my_go take_action_on_behalf_of_user
The command introspected your connector's entrypoint, identified functions with their argument and return types, and
generated Hasura metadata for each. Look for take_action_on_behalf_of_user.hml
to see the CLI-generated metadata.
We highly recommend adding a description
to the command object referenced above. Why?
PromptQL's performance is improved by providing more context; if you guide its understanding of what a particular function does and how it should be used in the application, you'll get better results.
Step 5. Create a new build and test
ddn supergraph build local
ddn run docker-start
ddn console --local
You can now navigate to the PromptQL Playground and use your custom business logic.

Next steps
While not wholly necessary, you can create explicit relationships between your custom business logic and existing types from other datasources. Typically, PromptQL can pick up on the context of how to use your business logic in conjunction with your data, but you can always improve its understanding by creating a relationship object.