My game makes various HTTP requests to a REST server that I have running.
Is there a best practice to managing a ton of different endpoints that can be hit? Should I re-use the same HTTPRequest
object to make each request, or should I create a new one for each endpoint?
This is what I have set up right now:
extends Node
# This will be replaced with config later
const SERVER_URL = "http://127.0.0.1:3030"
signal current_user_request_completed(user: User)
signal create_game_request_completed(gameId: String)
# https://docs.godotengine.org/en/stable/classes/class_httprequest.html#class-httprequest
@onready var current_user_http_request: HTTPRequest = HTTPRequest.new()
@onready var create_game_http_request: HTTPRequest = HTTPRequest.new()
func _ready():
add_child(current_user_http_request)
current_user_http_request.request_completed.connect(_current_user_http_request_completed)
add_child(create_game_http_request)
create_game_http_request.request_completed.connect(_create_game_http_request_completed)
func _get_headers():
var headers = PackedStringArray()
headers.append("Authorization: Bearer " + AuthHandler.get_authorization_header())
return headers
func start_current_user_request():
current_user_http_request.request(SERVER_URL + "/user", _get_headers())
func start_create_game_request(gameName: String):
var headers = _get_headers()
headers.append("Content-Type: application/json")
var body = JSON.stringify({"name": gameName})
create_game_http_request.request(SERVER_URL + "/games", headers, HTTPClient.METHOD_POST, body)
func _current_user_http_request_completed(_result, _response_code, _headers, body):
var response = JSON.parse_string(body.get_string_from_utf8())
# TODO error handling :)
current_user_request_completed.emit(User.new(response.id, response.email, response.username))
func _create_game_http_request_completed(_result, _response_code, _headers, body):
var response = JSON.parse_string(body.get_string_from_utf8())
# TODO error handling :)
create_game_request_completed.emit(response.id)
This is an autoload script, so whenever I want to make an HTTP request I do:
func _create_game():
var gameName = game_name_input.text
Server.create_game_request_completed.connect(_on_create_game_request_completed)
Server.start_create_game_request(gameName)
func _on_create_game_request_completed(gameId: String):
print(gameId)
I can see a lot of upsides to this:
- Ability to make different requests in parallel (since each one is its own
HTTPRequest
object) - Easy to pass parameters into the requests (abstraction over
HTTPRequest
) - Easy to listen for the request in multiple spots
But, some downsides as well:
- Unwieldy. Adding a new endpoint request to the client is a lot of work!
- Lots of
HTTPRequest
nodes being added to the scene when it loads (maybe this is fine since they aren't doing anything unless started? I couldn't see myself having more than maybe 15 of these)
I've poked around some other libraries, like godot-engine.supabase
, and they have a pretty robust system for handling multiple different requests using the same HTTPRequest
, but I'm not sure if I want to set up something that intricate (it's pretty difficult to grok without reading a ton of code) https://github.com/supabase-community/godot-engine.supabase/blob/c1c9016756f49e36e2fba85b9c9e61e066afa982/addons/supabase/Database/database_task.gd