Stream: beginners

Topic: Declarative Web Server


view this post on Zulip Iuri Brindeiro (Mar 22 2024 at 22:57):

After playing with Roc platform system + .NET (PR merged to the examples repo \o/), I was thinking about how I could implement some sort of type based web api platform that I always wanted to but never figured how to do it with C# or F# due to their lack of type inference.

My goal is to achieve the following syntax or similar:

    main = \routes ->
        routes
        |> mapGet "/"
        |> accepting (intParam "id" |> fromRoute)
        |> producing3 (Ok Todo) BadRequest NotFound
        |> usingHandler getTodos

essentially, this would enforce getTodos to have the following signature:
getTodos : int -> [Ok Todo, BadRequest, NotFound]

This would make documenting the API much simpler with maybe a call like:

   ...
   routes
   |> mapGet "/"
   ...
   |> usingHandler getTodos
   |> usingOpenApi

With the |> usingOpenApi line, the user would have open api (swagger) ready to go. But to do so, I would need to read the [Ok Todo, BadRequest, NotFound] type and convert it to some sort of "schema" that I would transform into a OpenApi specification or anything similar.

My question is: Can I read roc types like values or maybe use a different approach to achieve the above behavior?

view this post on Zulip Anton (Mar 23 2024 at 09:59):

I think you can achieve the desired functionality with abilities, that would allow you to define custom types that have for example a function toSchema.

view this post on Zulip Iuri Brindeiro (Apr 04 2024 at 15:45):

hey @Anton I just had time to take a look at it now.
I'm not sure I understand the use of abilities in this scenario.
Do you mean that the Custom time (in the last example Todo) would have to implement this custom ability with a toSchema function? I didn't want the user to have to define any code besides the actual type.

view this post on Zulip Iuri Brindeiro (Apr 04 2024 at 16:02):

My inspiration came from Haskell Servant, where I can define an API as a type. The only difference here would be that I would define an API with functions.

So, how could I convert a type such as Todo : { description: Str, done: Bool } to, lets say, a json value like

{ "type": {"name": "Todo", "fields": [{"name": "description", "type": "string"}, {"name": "done", "type": "boolean"}]} }

view this post on Zulip Brendan Hansknecht (Apr 04 2024 at 16:19):

Encode with either a custom encoder or the community made Jason encoder should work.

view this post on Zulip Brendan Hansknecht (Apr 04 2024 at 16:19):

Oh, though you want type info, not to encode the actual value. That would definitely be a custom encoder.

view this post on Zulip Iuri Brindeiro (Apr 04 2024 at 16:23):

Yeah, type info, not the actual value.
Ok, I'm gonna take a look at how encoders work, but I presume these are implemented in the platform somehow?

view this post on Zulip Brendan Hansknecht (Apr 04 2024 at 16:24):

No, in roc. https://www.roc-lang.org/builtins/Encode#Encoder

view this post on Zulip Brendan Hansknecht (Apr 04 2024 at 16:25):

Basically the encoder formatting function names give you the type info, so you could ignore the value and just encode type info. For structs still need to use it recursively, but that is no big deal.

view this post on Zulip Brendan Hansknecht (Apr 04 2024 at 16:28):

Oh, I guess if you want the most type info, inspect may technically be better it also knows about sets and dictionaries. We probably should expand encode to know about these types as well, but it doesn't currently.

view this post on Zulip Brendan Hansknecht (Apr 04 2024 at 16:29):

Example implementation in Inspect.roc for inspect (towards bottom of file) and TotallyNotJson.roc for encode. Just search for the files in the repo.

view this post on Zulip Iuri Brindeiro (Apr 04 2024 at 16:45):

Mmmm, inspect sounds and looks like what I want... I'm taking a look at it. Thx @Brendan Hansknecht !

view this post on Zulip Iuri Brindeiro (Apr 05 2024 at 00:34):

Ok, I think I finally understood. It took me a while to understand how abilities work. Probably because I kept imagining them being implemented on the platform and/or the base roc rust compiler code. There are still some things I can’t fully understand but I’ll give it a try. It compiles in my head xD


Last updated: Jul 05 2025 at 12:14 UTC