Leonardo Losoviz
Creator of Gato GraphQL, and contributor to several online magazines, including Smashing Magazine and CSS Tricks.
Presentation for apidays Singapore 2025
Gato GraphQL - Founder
(eg: write post content)
(eg: store in DB)
GraphQL
(server)
JS
(client)
Example 1:
(eg: write post content)
(eg: store in DB)
GraphQL
(server)
GraphQL query
Example 1:
(eg: posts)
(eg: rewrite)
(eg: store again in DB)
GraphQL
(1st request)
GraphQL
(2nd request)
JS
(client)
Example 2:
(eg: posts)
(eg: rewrite)
(eg: store again in DB)
GraphQL
(1 request)
GraphQL query
Example 2:
(skip to 1:46)
Eg: translate content via field translate, or directive @translate
query {
post(id: 1) {
content
}
translate(to: "es", text: "Some text to translate")
}
Issue: How to translate the post content?
query {
post(id: 1) {
content @translate(to: "es")
}
}
Issue: How to store again the translated content?
@export
[RFC] exporting variables between queries
query FetchContent {
post(id: 1) {
content @export(as: "postContent")
}
}
query AdaptContent @depends(on: "FetchContent") {
translate(to: "es", text: $postContent) @export(as: "adaptedPostContent")
}
mutation StoreContent @depends(on: "AdaptContent") {
updatePost(id: 1, content: $adaptedPostContent) {
status
errors {
message
}
post {
content
}
}
}
query FetchAndAdaptData {
post(id: 1) {
content
@translate(to: "es")
@export(as: "adaptedPostContent")
}
}
mutation StoreContent @depends(on: "FetchAndAdaptData") {
updatePost(id: 1, content: $adaptedPostContent) {
status
errors {
message
}
post {
content
}
}
}
@export
sendChatGPTRequest: String!
{
"id": "chatcmpl-B9MHDbslfkBeAs8l4bebGdFOJ6PeG",
"object": "chat.completion",
"created": 1741570283,
"model": "gpt-4o-2024-08-06",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "The image shows a wooden boardwalk path running through a lush green field or meadow. The sky is bright blue with some scattered clouds, giving the scene a serene and peaceful atmosphere. Trees and shrubs are visible in the background.",
"refusal": null,
"annotations": []
},
"logprobs": null,
"finish_reason": "stop"
}
],
"usage": {
"prompt_tokens": 1117,
"completion_tokens": 46,
"total_tokens": 1163,
"prompt_tokens_details": {
"cached_tokens": 0,
"audio_tokens": 0
},
"completion_tokens_details": {
"reasoning_tokens": 0,
"audio_tokens": 0,
"accepted_prediction_tokens": 0,
"rejected_prediction_tokens": 0
}
},
"service_tier": "default",
"system_fingerprint": "fp_fc9f1d7035"
}
query FetchData {
post(id: 1) {
content
@export(as: "prompt")
}
}
query AdaptData($openAIAPIKey: String!) @depends(on: "FetchData") {
sendChatGPTRequest(input: {
apiKey: $openAIAPIKey,
model: "gpt-4o",
messages: [
{
role: "system",
content: "You are a language translator"
},
{
role: "user",
content: $prompt
}
]
}) @export(as: "adaptedPostContent")
}
mutation StoreContent @depends(on: "AdaptData") {
updatePost(id: 1, content: $adaptedPostContent) {
status
errors {
message
}
post {
content
}
}
}
Issue: How to generate the prompt, combining static + dynamic data?
@prepend
: Create the prompt combining static + dynamic dataquery FetchData {
post(id: 1) {
content
@prepend(text: "Please translate from English to Spanish: ")
@export(as: "prompt")
}
}
query AdaptData($openAIAPIKey: String!) @depends(on: "FetchData") {
sendChatGPTRequest(input: {
apiKey: $openAIAPIKey,
model: "gpt-4o",
messages: [
{
role: "system",
content: "You are a language translator"
},
{
role: "user",
content: $prompt
}
]
}) @export(as: "adaptedPostContent")
}
mutation StoreContent @depends(on: "AdaptData") {
updatePost(id: 1, content: $adaptedPostContent) {
status
errors {
message
}
post {
content
}
}
}
jsonHTTPRequest: JSON!
(Different APIs return responses with different structures)
{
"content": [
{
"text": "Hi! My name is Claude.",
"type": "text"
}
],
"id": "msg_013Zva2CMHLNnXjNJJKqJ2EF",
"model": "claude-3-7-sonnet-20250219",
"role": "assistant",
"stop_reason": "end_turn",
"stop_sequence": null,
"type": "message",
"usage": {
"input_tokens": 2095,
"output_tokens": 503
}
}
query FetchData {
post(id: 1) {
content
@prepend(text: "Please translate from English to Spanish: ")
@export(as: "prompt")
}
}
query AdaptData($openAIAPIKey: String!) @depends(on: "FetchData") {
jsonHTTPRequest(input: {
url: "https://api.openai.com/v1/chat/completions",
method: POST,
options: {
auth: {
password: $openAIAPIKey
},
json: {
model: "gpt-4o",
messages: [
{
role: "system",
content: "You are a language translator"
},
{
role: "user",
content: $prompt
}
]
}
}
})
# This will not work, as this is a JSON, not a String
@export(as: "adaptedPostContent")
}
mutation StoreContent @depends(on: "AdaptData") {
updatePost(id: 1, content: $adaptedPostContent) {
status
errors {
message
}
post {
content
}
}
}
Issue: How to navigate and extract the actual data?
@underJSONObjectProperty
: Navigate the response to the desired entryquery FetchData {
post(id: 1) {
content
@prepend(text: "Please translate from English to Spanish: ")
@export(as: "prompt")
}
}
query AdaptData($openAIAPIKey: String!) @depends(on: "FetchData") {
chatGPTResponse: jsonHTTPRequest(input: {
url: "https://api.openai.com/v1/chat/completions",
method: POST,
options: {
auth: {
password: $openAIAPIKey
},
json: {
model: "gpt-4o",
messages: [
{
role: "system",
content: "You are a language translator"
},
{
role: "user",
content: $prompt
}
]
}
}
})
@underJSONObjectProperty(by: { key: "choices.0.message.content" })
@export(as: "adaptedPostContent")
}
mutation StoreContent @depends(on: "AdaptData") {
updatePost(id: 1, content: $adaptedPostContent) {
status
errors {
message
}
post {
content
}
}
}
@export
)Presentation for apidays Singapore 2025
Gato GraphQL - Founder
By Leonardo Losoviz
Presentation for apidays Singapore 2025
Creator of Gato GraphQL, and contributor to several online magazines, including Smashing Magazine and CSS Tricks.