api
Call an API or run a REST server
Schema
Schema
package api
Method: *"GET" | "POST" | "PUT" | "DELETE" | "OPTIONS" | "HEAD" | "CONNECT" | "TRACE" | "PATCH"
Call: {
@task(api.Call)
req: {
method: Method
host: string
path: string | *""
auth?: string
headers?: [string]: string
query?: [string]: string
form?: [string]: string
data?: string | {...}
timeout?: string
// curl?: string
retry?: {
count: int | *3
timer: string | *"6s"
codes: [...int]
}
}
// filled by task
resp: {
status: string
statusCode: int
body: *{} | bytes | string
header: [string]: string | [...string]
trailer: [string]: string | [...string]
}
}
Serve: {
@task(api.Serve)
port: string
quitMailbox: string
routes: [...{
// @flow() is needed to run sub-tasks per request, which is more typical
// you can omit if you only need to reshape the data with CUE code
// filled by hof/flow on each request
req: {
method: Method
url: string
headers: [string]: string
query: [string]: string
body: bytes | string | *{} // assumed json body if object
}
// any tasks you may need to convert the req -> resp
// these will be run after the `req` fields has been filled
// you construct the resp value which is sent back to the client
// (todo, make this include headers, code, etc
// for now, this is a value which will be turned into a JSON body for the response
resp: {
status: int
// one of, if none -> NoContent
json?: {}
html?: string
body?: string
}
}]
}
Example: api.Call
api.Call example
exec hof flow flow.cue
cmp stdout golden.stdout
-- flow.cue --
package hof
import "encoding/json"
pick: {
args: cow: string
}
tasks: [string]: {
Out: _
...
}
tasks: {
@flow()
call: {
@task(api.Call)
req: {
host: "https://postman-echo.com"
// method: "GET"
path: "/get"
query: {
cow: "moo"
}
}
resp: {
body: _
statusCode: 200
}
}
mask: {
@task(st.Mask)
val: call.resp.body
mask: { headers: "x-amzn-trace-id": string }
}
out: { text: json.Indent(json.Marshal(mask.out), "", " ") +"\n" } @task(os.Stdout)
}
-- golden.stdout --
{
"args": {
"cow": "moo"
},
"headers": {
"x-forwarded-proto": "https",
"x-forwarded-port": "443",
"host": "postman-echo.com",
"accept-encoding": "gzip",
"user-agent": "Go-http-client/2.0"
},
"url": "https://postman-echo.com/get?cow=moo"
}
Example: api.Serve
api.Call example
exec hof flow ./in.cue
-- in.cue --
import "encoding/json"
@flow()
config: {
port: "2323"
}
init: {
m: { "mailbox": "quit", buf: 2, done: _ } @task(csp.Chan)
}
run: {
@task(api.Serve)
dep: init.m.done
quitMailbox: "quit"
port: config.port
routes: {
"/hello": {
method: "GET"
resp: {
status: 200
body: "hallo chat!"
}
}
"/echo": {
method: ["get", "post"]
req: _
// resp: req.query
resp: json: req.query.cow
}
"/pipe": {
@flow()
req: _
r: { filename: req.query.filename[0], contents: string } @task(os.ReadFile)
j: json.Unmarshal(r.contents)
resp: {
status: 200
json: j
}
}
}
}
msg: {
@task(os.Stdout)
text: "server has shutdown\n"
dep: run.done
}
call: {
wait: {
@task(os.Sleep)
duration: "1s"
done: _
}
do: {
@dummy()
@task(api.Call)
dep: wait.done
resp: body: string
req: {
host: "http://localhost:\(config.port)"
method: "GET"
path: "/hello"
query: {
cow: "moo"
}
}
}
say: {
@task(os.Stdout)
text: do.resp.body
}
}
stop: {
wait: {
@task(os.Sleep)
duration: "2s"
done: _
}
send: {
@task(csp.Send)
dep: wait.done
"mailbox": "quit"
val: "quit"
}
}