Stream: beginners

Topic: Roc web server


view this post on Zulip Chris Vouga (Jul 30 2024 at 05:17):

How does one read request headers while using the simple webserver platform?

main : Request -> Task Response []
main = \req ->

    date = Utc.now! |> Utc.toIso8601Str
    Stdout.line! "$(date) $(Http.methodToStr req.method) $(req.url)"

    isHxRequest = Bool.true

    if isHxRequest then
        routeHx req
    else
        routeReq req

I want to check if the incoming request has "Hx-Request": "true" header.

I've checked the web server examples and web server docs but didn't find anything
https://github.com/roc-lang/basic-webserver/tree/main/examples
https://roc-lang.github.io/basic-webserver/Http/#Header

view this post on Zulip Luke Boswell (Jul 30 2024 at 05:22):

Yeah, unfortunately there is a bug preventing the generated docs from displaying the inner parts.

You can see the relevant impl in the platform package here

Basically you can use req.headers which will be a List { name : Str, value : List U8 }.

In the next update the value is changed to a Str, but that's the current API

view this post on Zulip Chris Vouga (Jul 30 2024 at 05:27):

@Luke Boswell That worked. Thank you

main : Request -> Task Response []
main = \req ->

    date = Utc.now! |> Utc.toIso8601Str
    Stdout.line! "$(date) $(Http.methodToStr req.method) $(req.url)"

    isHxRequest = List.any req.headers (\header -> header.name == "hx-request")

    headerKeys = List.map req.headers (\header -> header.name) |> \s -> Str.joinWith s ", "
    Stdout.line! headerKeys

    if isHxRequest then
        routeHx req
    else
        routeReq req

view this post on Zulip Luke Boswell (Jul 30 2024 at 05:32):

I also made a quick example just to check it out myself

app [main] {
    pf: platform "https://github.com/roc-lang/basic-webserver/releases/download/0.6.0/LQS_Avcf8ogi1SqwmnytRD4SMYiZ4UcRCZwmAjj1RNY.tar.gz",
}

import pf.Task exposing [Task]
import pf.Http exposing [Request, Response]

main : Request -> Task Response []
main = \req ->

    hxRequest = req.headers |> getHeader "hx-request"

    when hxRequest is
        Ok value ->
            Task.ok { status: 200, headers: [], body: Str.toUtf8 "Found, got value $(value)\n" }
        Err NotFound ->
            Task.ok { status: 400, headers: [], body: Str.toUtf8 "Bad request, got headers $(Inspect.toStr req.headers)\n" }


getHeader : List {name: Str, value: Str}, Str -> Result Str [NotFound]
getHeader = \headers, search ->
    List.keepOks headers \header ->
        if header.name == search then
            Ok header.value
        else
            Err NotFound
    |> List.first
    |> Result.mapErr \ListWasEmpty -> NotFound
$ curl --header "HX-Request: true" localhost:8000

Found, got value true

view this post on Zulip Luke Boswell (Jul 30 2024 at 05:34):

I'm running on latest main though. I'm not sure if the nightly works with basic-webserver 0.6.0, it may require the TESTING nightly. Just in case you try and run this and it breaks

view this post on Zulip Chris Vouga (Jul 30 2024 at 05:42):

@Luke Boswell Thank you for the help.
Another problem I'm having is I'm looking to deploy a roc webserver to https://railway.app/ using a Dockerfile.

I haven't been able to create a working dockerfile for a roc webserver yet.

Is there anywhere online where I can find a starter dockerfile for roc webserver? Any resources for this?

view this post on Zulip Luke Boswell (Jul 30 2024 at 06:13):

I had something I shared recently in https://roc.zulipchat.com/#narrow/stream/304902-show-and-tell/topic/basic-webserver.20docker.20container/near/440962511

view this post on Zulip Luke Boswell (Jul 30 2024 at 06:15):

If you improve on that I'd love to know how.

In theory we should be able to build a much smaller final image, but I haven't spent the time to really map out what the roc binary requires to run ok.

view this post on Zulip Luke Boswell (Jul 30 2024 at 06:22):

One thing that might be worth exploring is the use of https://nixpacks.com/docs
It looks like that is what railway uses, and the best support for basic-webserver is using our nix flake -- as that is what is most thoroughly tested in our CI.

view this post on Zulip Luke Boswell (Jul 30 2024 at 06:23):

I'm not sure how to set all this up. I'm basically a complete nix beginner... I just know how to run nix develop and nix flake update and that's about the limit of my knowledge rn.

view this post on Zulip Chris Vouga (Jul 30 2024 at 18:34):

@Luke Boswell That dockerfile you gave worked for me. Its working in railway.app now. Thank you!

I just had to tweak somethings to match my project structure

# Builder state using the roclang/nightly-ubuntu-latest image
FROM roclang/nightly-debian-bookworm as builder

# Copy the source code
COPY ./src /src

# Build the roc app
RUN ["roc", "build", "/src/Main.roc"]

# Check if the binary is present
RUN ["ls", "/src/Main"]

# Use a smaller image for running the app
FROM bitnami/minideb:bookworm as final

# Set environment variables
ENV ROC_BASIC_WEBSERVER_HOST=0.0.0.0
ENV ROC_BASIC_WEBSERVER_PORT=8000

# Copy the binary from the builder container
COPY --from=builder /src/Main .

# Run the app binary
CMD ["./Main"]
# Makefile

# Image name
IMAGE_NAME = roc-app

# Build the Docker image
build:
    docker build --platform linux/amd64 -t $(IMAGE_NAME) .

# Run the Docker container
run:
    docker run --platform linux/amd64 --rm $(IMAGE_NAME)

view this post on Zulip Luke Boswell (Jul 31 2024 at 09:57):

@Chris Vouga -- I'm thinking about how we might capture this and share it for others in future.

I'm wondering where you would expect to find this next time you come along to do this with basic-webserver?

Like would an example in https://www.roc-lang.org/examples be helpful?

Or would an example with a Dockerfile and some instructions in the basic-webserver repo be more helpful?

Or maybe even a blog post that is linked from those places?

view this post on Zulip Chris Vouga (Jul 31 2024 at 19:29):

@Luke Boswell Any of those places would be great. The best place would be within the basic web server docs. A section on deploying. The current docs look auto generated and more of an API reference so it may be out place there.


Last updated: Jul 05 2025 at 12:14 UTC