mirror of
https://github.com/fnproject/fn.git
synced 2022-10-28 21:29:17 +03:00
Docs on writing functions and the functions format. (#203)
* WIP on writing functions and the functions format. * Added more docs on writing functions. * Running on windows docs. * Linked README to writing.md * Minor fixes from PR feedback.
This commit is contained in:
@@ -1,7 +1,8 @@
|
||||
|
||||
# IronFunctions Documentation
|
||||
|
||||
* [IronFunctions Options](api.md)
|
||||
* [IronFunctions Run Options](options.md)
|
||||
* [Writing Functions](function-format.md)
|
||||
* [API Reference](https://app.swaggerhub.com/api/iron/functions/)
|
||||
* [Running in Production](production.md)
|
||||
* [Databases](databases/README.md)
|
||||
@@ -12,3 +13,4 @@
|
||||
* [Triggers](triggers.md)
|
||||
* [Extending IronFunctions](extending.md)
|
||||
* [Docker Configuration](docker.md)
|
||||
* [Function Format](function-format.md)
|
||||
|
||||
108
docs/function-format.md
Normal file
108
docs/function-format.md
Normal file
@@ -0,0 +1,108 @@
|
||||
# Open Function Format
|
||||
|
||||
This document will describe the details of how a function works, inputs/outputs, etc.
|
||||
|
||||
## Input
|
||||
|
||||
### STDIN and Environment Variables
|
||||
|
||||
While wanting to keep things simple, flexible and expandable, we decided to go back to the basics, using Unix input and output. Standard in is easy to use in any
|
||||
language and doesn't require anything extra. It also allows streaming input so we can do things like keeping a container running some time and stream
|
||||
requests into the container.
|
||||
|
||||
Configuration values, environment information and other things will be passed in through environment variables.
|
||||
|
||||
### Input Formats
|
||||
|
||||
The goals of the input format are the following:
|
||||
|
||||
* Very easy to use and parse
|
||||
* Streamable for increasing performance (more than one call per container execution)
|
||||
* Ability to build higher level abstractions on top (ie: Lambda syntax compatible)
|
||||
|
||||
The format is still up for discussion and in order to move forward and remain flexible, it's likely we will just allow different input formats and the
|
||||
function creator can decide what they want, on a per function basis. Default being the simplest format to use.
|
||||
|
||||
#### Default Input Format
|
||||
|
||||
The default input format is simply the request body itself plus some environment variables. For instance, if someone were to post a JSON body, the unmodified body would
|
||||
be sent in via STDIN.
|
||||
|
||||
Pros:
|
||||
|
||||
* Very simple to use
|
||||
|
||||
Cons:
|
||||
|
||||
* Not streamable
|
||||
|
||||
#### HTTP/1 Input Format (Not implemented)
|
||||
|
||||
`--input-format http`
|
||||
|
||||
HTTP format could be a good option as it is in very common use obviously, most languages have some semi-easy way to parse it, and it's streamable. The basic format
|
||||
is:
|
||||
|
||||
```
|
||||
REQUEST LINE
|
||||
HEADER
|
||||
BLANK LINE
|
||||
BODY
|
||||
```
|
||||
|
||||
The header keys and values would be populated with information about the function call such as the request URL and query parameters.
|
||||
|
||||
Body length is determined by the [Content-Length](https://tools.ietf.org/html/rfc7230#section-3.3.3) header, which is mandatory.
|
||||
|
||||
Pros:
|
||||
|
||||
* Streamable
|
||||
* Common format
|
||||
|
||||
Cons:
|
||||
|
||||
* Requires a parsing library or fair amount of code to parse headers properly
|
||||
* Double parsing - headers + body (if body is to be parsed, such as json)
|
||||
|
||||
#### JSON/HTTP Input Format (Not implemented)
|
||||
|
||||
`--input-format json-http`
|
||||
|
||||
The idea here is to keep the HTTP base structure, but make it a bit easier to parse by making the `request line` and `headers` a JSON struct.
|
||||
Eg:
|
||||
|
||||
```
|
||||
{
|
||||
"request_url":"http://....",
|
||||
"params": {
|
||||
"blog_name": "yeezy"
|
||||
}
|
||||
}
|
||||
BLANK LINE
|
||||
BODY
|
||||
```
|
||||
|
||||
Pros:
|
||||
|
||||
* Streamable
|
||||
* Easy to parse headers
|
||||
|
||||
Cons:
|
||||
|
||||
* New, unknown format
|
||||
|
||||
## Output
|
||||
|
||||
### STDOUT
|
||||
|
||||
For synchronous: True to form, whatever is written to standard out is returned as the response. If you want to return some JSON output, just write it directly to STDOUT.
|
||||
|
||||
TODO: How to change response headers? Perhaps a similar style as input? Headers, then body. Default headers can be defined on the route and overridden on output.
|
||||
|
||||
For asynchronous: STDOUT will be written to /dev/null until [further notice](https://github.com/iron-io/functions/issues/173). We do not want to write this
|
||||
to the logs now, then change it later, otherwise people will start to depend on it.
|
||||
|
||||
### STDERR
|
||||
|
||||
Standard error is reserved for logging, like it was meant to be. Anything you output to STDERR will show up in the logs. And if you use a log
|
||||
collector like logspout, you can collect those logs in a central location. See [logging](logging.md).
|
||||
@@ -1,7 +1,4 @@
|
||||
|
||||
|
||||
|
||||
## IronFunctions Config Options
|
||||
# IronFunctions Configuration Options
|
||||
|
||||
When starting IronFunctions, you can pass in the following configuration variables as environment variables. Use `-e VAR_NAME=VALUE` in
|
||||
docker run. For example:
|
||||
@@ -39,5 +36,4 @@ docker run -e VAR_NAME=VALUE ...
|
||||
<td>LOG_LEVEL</td>
|
||||
<td>Set to `DEBUG` to enable debugging. Default is INFO.</td>
|
||||
</tr>
|
||||
|
||||
</table>
|
||||
9
docs/windows.md
Normal file
9
docs/windows.md
Normal file
@@ -0,0 +1,9 @@
|
||||
# Running on Windows
|
||||
|
||||
Windows doesn't support Docker in Docker so you'll change the run command to the following:
|
||||
|
||||
```sh
|
||||
docker run --rm --name functions -it -v /var/run/docker.sock:/var/run/docker.sock -v $PWD/data:/app/data -p 8080:8080 iron/functions
|
||||
```
|
||||
|
||||
Then everything should work as normal.
|
||||
81
docs/writing.md
Normal file
81
docs/writing.md
Normal file
@@ -0,0 +1,81 @@
|
||||
# Writing Functions
|
||||
|
||||
This will give you the basic overview of writing base level functions. You can also use higher level abstractions that make it easier such
|
||||
as [lambda](lambda.md).
|
||||
|
||||
## Code
|
||||
|
||||
The most basic code layout in any language is as follows, this is pseudo code and is not meant to run.
|
||||
|
||||
```ruby
|
||||
# Read and parse from STDIN
|
||||
body = JSON.parse(STDIN)
|
||||
|
||||
# Do something
|
||||
return_struct = doSomething(body)
|
||||
|
||||
# Respond if sync:
|
||||
STDOUT.write(JSON.generate(return_struct))
|
||||
# or update something if async
|
||||
db.update(return_struct)
|
||||
```
|
||||
|
||||
## Inputs
|
||||
|
||||
Inputs are provided through standard input and environment variables. We'll just talk about the default input format here, but you can find others [here](function-format.md).
|
||||
To read in the function body, just read from STDIN.
|
||||
|
||||
You will also have access to a set of environment variables.
|
||||
|
||||
* REQUEST_URL - the full URL for the request
|
||||
* ROUTE - the matched route
|
||||
* METHOD - the HTTP method for the request
|
||||
* CONFIG_X - any configuration values you've set for the Application or the Route. Replace X with the upper cased name of the config variable you set.
|
||||
* HEADER_X - the HTTP headers that were set for this request. Replace X with the upper cased name of the header and replace dashes in the header with underscores.
|
||||
|
||||
Warning: these may change before release.
|
||||
|
||||
## Logging
|
||||
|
||||
Standard out is where you should write response data for synchronous functions. Standard error
|
||||
is where you should write for logging, as [it was intended](http://www.jstorimer.com/blogs/workingwithcode/7766119-when-to-use-stderr-instead-of-stdout).
|
||||
|
||||
So to write output to logs, simply log to STDERR. Here are some examples in a few languages.
|
||||
|
||||
In Go, simply use the [log](https://golang.org/pkg/log/) package, it writes to STDERR by default.
|
||||
|
||||
```go
|
||||
log.Println("hi")
|
||||
```
|
||||
|
||||
In Node.js:
|
||||
|
||||
```node
|
||||
console.error("hi");
|
||||
```
|
||||
|
||||
[More details for Node.js here](http://stackoverflow.com/a/27576486/105562).
|
||||
|
||||
In Ruby:
|
||||
|
||||
```ruby
|
||||
STDERR.puts("hi")
|
||||
```
|
||||
|
||||
## Packaging
|
||||
|
||||
Packaging a function is essentially just creating a Docker image for your function with an ENTRYPOINT.
|
||||
|
||||
The basic Dockerfile for most languages is something like this:
|
||||
|
||||
```
|
||||
# Choose base image
|
||||
FROM iron/go
|
||||
# Set th working directory
|
||||
WORKDIR /function
|
||||
# Add your binary or code to the working directory
|
||||
ADD hello /function/
|
||||
# Set what will run when a container is started for this image
|
||||
ENTRYPOINT ["./hello"]
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user