Skip to main content

Overview

The HTTPRequest node provides an easy way to make HTTP and HTTPS requests to web servers and REST APIs. It supports GET, POST, PUT, DELETE, and other HTTP methods, along with file downloads and uploads.
HTTPRequest uses HTTPClient internally and provides a simpler, node-based interface for common HTTP operations.

Basic HTTP Request

GET Request

func _ready():
    # Create HTTP request node
    var http_request = HTTPRequest.new()
    add_child(http_request)
    http_request.request_completed.connect(_on_request_completed)
    
    # Perform GET request
    var error = http_request.request("https://api.example.com/data")
    if error != OK:
        push_error("An error occurred in the HTTP request.")

func _on_request_completed(result, response_code, headers, body):
    if result != HTTPRequest.RESULT_SUCCESS:
        push_error("Request failed")
        return
    
    if response_code != 200:
        push_error("HTTP error: " + str(response_code))
        return
    
    # Parse response
    var json = JSON.new()
    json.parse(body.get_string_from_utf8())
    var response = json.get_data()
    
    print("Response: ", response)
public override void _Ready()
{
    // Create HTTP request node
    var httpRequest = new HttpRequest();
    AddChild(httpRequest);
    httpRequest.RequestCompleted += OnRequestCompleted;
    
    // Perform GET request
    Error error = httpRequest.Request("https://api.example.com/data");
    if (error != Error.Ok)
    {
        GD.PushError("An error occurred in the HTTP request.");
    }
}

private void OnRequestCompleted(long result, long responseCode, string[] headers, byte[] body)
{
    if (result != (long)HttpRequest.Result.Success)
    {
        GD.PushError("Request failed");
        return;
    }
    
    if (responseCode != 200)
    {
        GD.PushError($"HTTP error: {responseCode}");
        return;
    }
    
    // Parse response
    var json = new Json();
    json.Parse(body.GetStringFromUtf8());
    var response = json.GetData();
    
    GD.Print("Response: ", response);
}
Always check both the result (network operation status) and response_code (HTTP status) before processing the response.

POST Request

Send data to a server:
func send_post_request():
    var http_request = HTTPRequest.new()
    add_child(http_request)
    http_request.request_completed.connect(_on_post_completed)
    
    # Prepare POST data
    var data = {
        "username": "player123",
        "score": 1000,
        "level": 5
    }
    
    var json = JSON.new()
    var body = json.stringify(data)
    
    # Set headers
    var headers = ["Content-Type: application/json"]
    
    # Send POST request
    var error = http_request.request(
        "https://api.example.com/scores",
        headers,
        HTTPClient.METHOD_POST,
        body
    )
    
    if error != OK:
        push_error("Failed to send POST request")

func _on_post_completed(result, response_code, headers, body):
    if result == HTTPRequest.RESULT_SUCCESS and response_code == 201:
        print("Score submitted successfully!")
    else:
        print("Failed to submit score: ", response_code)
private void SendPostRequest()
{
    var httpRequest = new HttpRequest();
    AddChild(httpRequest);
    httpRequest.RequestCompleted += OnPostCompleted;
    
    // Prepare POST data
    var data = new Godot.Collections.Dictionary
    {
        { "username", "player123" },
        { "score", 1000 },
        { "level", 5 }
    };
    
    var json = new Json();
    string body = json.Stringify(data);
    
    // Set headers
    string[] headers = { "Content-Type: application/json" };
    
    // Send POST request
    Error error = httpRequest.Request(
        "https://api.example.com/scores",
        headers,
        HttpClient.Method.Post,
        body
    );
    
    if (error != Error.Ok)
    {
        GD.PushError("Failed to send POST request");
    }
}

private void OnPostCompleted(long result, long responseCode, string[] headers, byte[] body)
{
    if (result == (long)HttpRequest.Result.Success && responseCode == 201)
    {
        GD.Print("Score submitted successfully!");
    }
    else
    {
        GD.Print($"Failed to submit score: {responseCode}");
    }
}

HTTP Methods

MethodPurposeExample Use Case
GETRetrieve dataGet player leaderboard
POSTCreate resourceSubmit new score
PUTUpdate resourceUpdate player profile
DELETEDelete resourceDelete save file
PATCHPartial updateUpdate single field
HEADGet headers onlyCheck file size
# PUT request
http_request.request(
    "https://api.example.com/users/123",
    headers,
    HTTPClient.METHOD_PUT,
    json_body
)

# DELETE request
http_request.request(
    "https://api.example.com/users/123",
    headers,
    HTTPClient.METHOD_DELETE
)

File Downloads

Download files from a URL:
func download_file():
    var http_request = HTTPRequest.new()
    add_child(http_request)
    http_request.request_completed.connect(_on_download_completed)
    
    # Set download file path
    http_request.download_file = "user://downloaded_image.png"
    
    # Start download
    var error = http_request.request("https://example.com/image.png")
    if error != OK:
        push_error("Failed to start download")

func _on_download_completed(result, response_code, headers, body):
    if result == HTTPRequest.RESULT_SUCCESS:
        print("File downloaded successfully!")
        
        # Load the downloaded image
        var image = Image.new()
        image.load("user://downloaded_image.png")
        var texture = ImageTexture.create_from_image(image)

Download Progress

var http_request: HTTPRequest

func _ready():
    http_request = HTTPRequest.new()
    add_child(http_request)
    http_request.download_file = "user://large_file.zip"
    http_request.request("https://example.com/large_file.zip")

func _process(delta):
    if http_request:
        var downloaded = http_request.get_downloaded_bytes()
        var total = http_request.get_body_size()
        
        if total > 0:
            var progress = float(downloaded) / float(total) * 100.0
            print("Download progress: ", progress, "%")
Files are downloaded to the specified path. Use user:// for writable user directory.

Custom Headers

Add authentication and custom headers:
# API key authentication
var headers = [
    "Authorization: Bearer YOUR_API_KEY",
    "Content-Type: application/json",
    "User-Agent: GodotGame/1.0"
]

http_request.request(
    "https://api.example.com/protected",
    headers,
    HTTPClient.METHOD_GET
)

Basic Authentication

var username = "user"
var password = "pass"
var auth_string = username + ":" + password
var auth_bytes = auth_string.to_utf8_buffer()
var auth_base64 = Marshalls.raw_to_base64(auth_bytes)

var headers = [
    "Authorization: Basic " + auth_base64
]

http_request.request(
    "https://api.example.com/protected",
    headers,
    HTTPClient.METHOD_GET
)

Response Handling

Status Codes

func _on_request_completed(result, response_code, headers, body):
    match response_code:
        200:  # OK
            print("Success")
        201:  # Created
            print("Resource created")
        204:  # No Content
            print("Success, no content returned")
        400:  # Bad Request
            push_error("Invalid request")
        401:  # Unauthorized
            push_error("Authentication required")
        403:  # Forbidden
            push_error("Access denied")
        404:  # Not Found
            push_error("Resource not found")
        500:  # Internal Server Error
            push_error("Server error")
        503:  # Service Unavailable
            push_error("Service temporarily unavailable")
        _:
            push_error("Unexpected response code: " + str(response_code))

Parsing JSON

func parse_json_response(body: PackedByteArray):
    var json = JSON.new()
    var error = json.parse(body.get_string_from_utf8())
    
    if error != OK:
        push_error("Failed to parse JSON: " + json.get_error_message())
        return null
    
    return json.get_data()

func _on_request_completed(result, response_code, headers, body):
    var data = parse_json_response(body)
    
    if data and data.has("players"):
        for player in data["players"]:
            print("Player: ", player["name"], " Score: ", player["score"])

Request Configuration

Timeout

var http_request = HTTPRequest.new()
http_request.timeout = 10.0  # 10 second timeout
add_child(http_request)

Redirects

var http_request = HTTPRequest.new()
http_request.max_redirects = 5  # Follow up to 5 redirects
add_child(http_request)

GZIP Compression

var http_request = HTTPRequest.new()
http_request.accept_gzip = true  # Accept compressed responses (default: true)
add_child(http_request)

Body Size Limit

var http_request = HTTPRequest.new()
http_request.body_size_limit = 1024 * 1024 * 10  # 10 MB limit
add_child(http_request)

HTTPS/TLS

For secure connections:
# Use custom TLS options
var tls_options = TLSOptions.client()
http_request.set_tls_options(tls_options)

# Make HTTPS request
http_request.request("https://secure.example.com/api")
Always use HTTPS for sensitive data like authentication tokens and user information.

REST API Example

Complete REST API integration:
extends Node

const API_URL = "https://api.example.com"
var api_token = ""

func login(username: String, password: String):
    var http_request = HTTPRequest.new()
    add_child(http_request)
    http_request.request_completed.connect(_on_login_completed)
    
    var data = {"username": username, "password": password}
    var body = JSON.stringify(data)
    var headers = ["Content-Type: application/json"]
    
    http_request.request(
        API_URL + "/login",
        headers,
        HTTPClient.METHOD_POST,
        body
    )

func _on_login_completed(result, response_code, headers, body):
    if response_code == 200:
        var json = JSON.new()
        json.parse(body.get_string_from_utf8())
        var data = json.get_data()
        
        api_token = data["token"]
        print("Login successful!")
        
        # Now make authenticated requests
        get_user_profile()

func get_user_profile():
    var http_request = HTTPRequest.new()
    add_child(http_request)
    http_request.request_completed.connect(_on_profile_loaded)
    
    var headers = [
        "Authorization: Bearer " + api_token,
        "Content-Type: application/json"
    ]
    
    http_request.request(
        API_URL + "/user/profile",
        headers,
        HTTPClient.METHOD_GET
    )

func _on_profile_loaded(result, response_code, headers, body):
    if response_code == 200:
        var json = JSON.new()
        json.parse(body.get_string_from_utf8())
        var profile = json.get_data()
        
        print("User: ", profile["name"])
        print("Level: ", profile["level"])
        print("XP: ", profile["xp"])

func update_score(score: int):
    var http_request = HTTPRequest.new()
    add_child(http_request)
    http_request.request_completed.connect(_on_score_updated)
    
    var data = {"score": score}
    var body = JSON.stringify(data)
    var headers = [
        "Authorization: Bearer " + api_token,
        "Content-Type: application/json"
    ]
    
    http_request.request(
        API_URL + "/scores",
        headers,
        HTTPClient.METHOD_POST,
        body
    )

func _on_score_updated(result, response_code, headers, body):
    if response_code == 201:
        print("Score updated successfully!")

Error Handling

func _on_request_completed(result, response_code, headers, body):
    match result:
        HTTPRequest.RESULT_SUCCESS:
            # Check HTTP status code
            if response_code >= 200 and response_code < 300:
                handle_success(body)
            else:
                handle_http_error(response_code, body)
        
        HTTPRequest.RESULT_CHUNKED_BODY_SIZE_MISMATCH:
            push_error("Chunked transfer error")
        
        HTTPRequest.RESULT_CANT_CONNECT:
            push_error("Cannot connect to server")
        
        HTTPRequest.RESULT_CANT_RESOLVE:
            push_error("Cannot resolve hostname")
        
        HTTPRequest.RESULT_CONNECTION_ERROR:
            push_error("Connection error")
        
        HTTPRequest.RESULT_TLS_HANDSHAKE_ERROR:
            push_error("TLS handshake failed")
        
        HTTPRequest.RESULT_NO_RESPONSE:
            push_error("No response from server")
        
        HTTPRequest.RESULT_BODY_SIZE_LIMIT_EXCEEDED:
            push_error("Response too large")
        
        HTTPRequest.RESULT_TIMEOUT:
            push_error("Request timed out")
        
        _:
            push_error("Unknown error: " + str(result))

Best Practices

Always use HTTPS when transmitting passwords, tokens, or personal information.
Check both network errors and HTTP status codes. Provide user feedback for failures.
Use shorter timeouts for quick requests, longer for file downloads. Default of 0 means no timeout.
HTTPRequest is asynchronous by default. Never use synchronous HTTP calls in production.
Respect API rate limits. Implement exponential backoff for retries.

See Also

Networking Overview

Learn about multiplayer networking

Low-Level Networking

Understand ENet and WebSocket

Build docs developers (and LLMs) love