Every language
11 implementations, copy-ready. One at a time with syntax highlighting, or all inline.
JSJavaScript
const res = await fetch('https://api.example.com/users', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ name: 'Ada', role: 'admin' }),
});
if (!res.ok) {
// 4xx/5xx bodies carry the reason — read them
throw new Error(`HTTP ${res.status}: ${await res.text()}`);
}
const created = await res.json();
console.log(created.id);fetch never serializes objects — JSON.stringify is on you, always. Setting the header is on you too.
TSTypeScript
interface User {
id: string;
name: string;
}
const res = await fetch('https://api.example.com/users', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ name: 'Ada', role: 'admin' }),
});
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const created = (await res.json()) as User; // trust, not a check
console.log(created.name);Same as JavaScript plus a cast for the response. For untrusted APIs, decode through a schema library instead of as.
GoGo
package main
import (
"bytes"
"encoding/json"
"fmt"
"net/http"
)
func main() {
payload, _ := json.Marshal(map[string]string{"name": "Ada", "role": "admin"})
res, err := http.Post("https://api.example.com/users",
"application/json", bytes.NewReader(payload))
if err != nil {
panic(err)
}
defer res.Body.Close()
var created struct {
ID string `json:"id"`
Name string `json:"name"`
}
if res.StatusCode >= 400 {
panic(fmt.Sprintf("HTTP %d", res.StatusCode))
}
if err := json.NewDecoder(res.Body).Decode(&created); err != nil {
panic(err)
}
fmt.Println(created.ID)
}http.Post is the one-liner; the anonymous struct decodes a one-off response shape without a named type. Production: add a context (see the timeout recipe).
RsRust
use serde::Serialize;
use serde_json::Value;
#[derive(Serialize)]
struct NewUser<'a> {
name: &'a str,
role: &'a str,
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let created: Value = reqwest::Client::new()
.post("https://api.example.com/users")
.json(&NewUser { name: "Ada", role: "admin" }) // sets the header too
.send()
.await?
.error_for_status()?
.json()
.await?;
println!("{}", created["id"]);
Ok(())
}.json() serializes AND sets Content-Type. Value is the sketch type — derive Deserialize on a real struct in production code.
PHPPHP
$ctx = stream_context_create([
'http' => [
'method' => 'POST',
'header' => "Content-Type: application/json\r\n",
'content' => json_encode(['name' => 'Ada', 'role' => 'admin']),
'timeout' => 5,
'ignore_errors' => true, // make 4xx/5xx bodies readable
],
]);
$body = file_get_contents('https://api.example.com/users', false, $ctx);
$created = json_decode($body, true, flags: JSON_THROW_ON_ERROR);
echo $created['id'];ignore_errors => true turns HTTP errors into readable bodies instead of a warning plus false. JSON_THROW_ON_ERROR — the default silent null is a classic bug.
PyPython
import httpx
response = httpx.post(
'https://api.example.com/users',
json={'name': 'Ada', 'role': 'admin'}, # serializes + sets the header
timeout=5.0,
)
response.raise_for_status()
created = response.json()
print(created['id'])json= and data= are different dials: json= sends application/json, data= form-encodes. Mixing them up is the #1 httpx/requests bug.
C#C#
using System.Net.Http.Json; // PostAsJsonAsync lives here
using var client = new HttpClient();
var response = await client.PostAsJsonAsync(
"https://api.example.com/users",
new { Name = "Ada", Role = "admin" });
response.EnsureSuccessStatusCode();
var created = await response.Content.ReadFromJsonAsync<User>();
Console.WriteLine(created?.Id);
record User(string Id, string Name);System.Net.Http.Json is the rare stdlib that does the whole task in one call: serialize, header, POST, deserialize the response.
JvJava
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://api.example.com/users"))
.timeout(Duration.ofSeconds(5))
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(
"{\"name\":\"Ada\",\"role\":\"admin\"}"))
.build();
HttpResponse<String> response = HttpClient.newHttpClient()
.send(request, HttpResponse.BodyHandlers.ofString());
if (response.statusCode() >= 400) {
throw new IllegalStateException("HTTP " + response.statusCode());
}
System.out.println(response.body());The JDK has no JSON parser — the hand-written string is the honest stdlib answer. Real code serializes and parses with Jackson or Gson.
SwSwift
import Foundation
struct NewUser: Codable { let name: String; let role: String }
struct User: Codable { let id: String; let name: String }
var request = URLRequest(url: URL(string: "https://api.example.com/users")!)
request.httpMethod = "POST"
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.httpBody = try JSONEncoder().encode(NewUser(name: "Ada", role: "admin"))
let (data, response) = try await URLSession.shared.data(for: request)
guard let http = response as? HTTPURLResponse,
(200..<300).contains(http.statusCode) else {
throw URLError(.badServerResponse)
}
let created = try JSONDecoder().decode(User.self, from: data)
print(created.id)Codable covers both directions. JSONEncoder/JSONDecoder are value types you can configure — keyDecodingStrategy .convertFromSnakeCase for snake_case APIs.
KtKotlin
import kotlinx.serialization.Serializable
import kotlinx.serialization.json.Json
import java.net.URI
import java.net.http.HttpClient
import java.net.http.HttpRequest
import java.net.http.HttpResponse
import java.time.Duration
@Serializable
data class NewUser(val name: String, val role: String)
@Serializable
data class User(val id: String, val name: String)
val payload = Json.encodeToString(NewUser("Ada", "admin"))
val request = HttpRequest.newBuilder()
.uri(URI.create("https://api.example.com/users"))
.timeout(Duration.ofSeconds(5))
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(payload))
.build()
val response = HttpClient.newHttpClient()
.send(request, HttpResponse.BodyHandlers.ofString())
check(response.statusCode() < 400) { "HTTP ${response.statusCode()}" }
val created = Json.decodeFromString<User>(response.body())
println(created.id)kotlinx.serialization is the Kotlin-native (de)serializer — compile-time generated, no reflection. The HTTP layer is still java.net.http.
RbRuby
require 'net/http'
require 'json'
require 'uri'
uri = URI('https://api.example.com/users')
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
request = Net::HTTP::Post.new(uri.request_uri,
'Content-Type' => 'application/json')
request.body = { name: 'Ada', role: 'admin' }.to_json
response = http.request(request)
raise "HTTP #{response.code}" unless response.is_a?(Net::HTTPSuccess)
created = JSON.parse(response.body)
puts created['id']Net::HTTP leaves both serialization and the header to you. Rails has to_json on tap; plain Ruby needs require 'json'.