# HTTP server

> Build an HTTP API in Langoost with http.serve and a handler function that receives method, path, query, and body, and returns a string response.

# HTTP server

Langoost has a built-in HTTP server. Call `http.serve(port, handler)` and each
incoming request runs your handler in its own **isolated VM** — a private stack
and output buffer per request, so concurrent requests never share mutable state.

## A minimal server

The handler receives up to four arguments — `method`, `path`, `query`, `body` —
and returns a string:

```goost
import http
import strings
import json

fn handle(method: string, path: string, query: string, body: string): string {
    if path == "/health" {
        return "{\"status\": \"ok\"}"
    }

    if path == "/echo" && method == "POST" {
        return body
    }

    if path == "/greet" {
        let name = "World"
        if strings.contains(query, "name=") {
            let parts = strings.splitN(query, "name=", 2)
            name = parts[1]
        }
        let data: json = {message: "Hello"}
        return json.setString(data, "message", "Hello, " + name + "!")
    }

    return "404 Not Found"
}

http.serve(8080, handle)
```

## Response format

- **Plain string** → HTTP `200` with that body.
- **Status prefix** → start the string with a 3-digit code and a space to set
  the status: `"404 Not Found"`, `"500 Internal Server Error"`,
  `"201 " + json.stringify(resource)`.
- **Content-Type** is detected automatically: responses starting with `{` or
  `[` are sent as `application/json`; everything else as
  `text/plain; charset=utf-8`.

## Isolation & shared state

Because each request runs in its own VM, there is no shared mutable state by
default — which is what makes requests safe to run concurrently. When you do
need to share data across requests, use the global key-value store in
`runtime.core`:

```goost
import runtime

runtime.core.share("visits", "0")
let n = toInt(runtime.core.fetch("visits"))
runtime.core.share("visits", toString(n + 1))
```

## HTTP client

The same `http` module is also a client for talking to other services:

```goost
import http

let body = http.get("https://api.example.com/users")

let resp = http.request("GET", "https://api.example.com/me", "", [
    "Authorization: Bearer my-token",
    "Accept: application/json"
])
```

See the **[concurrency](/docs/concurrency)** guide for background work and the
`thread` module.