Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/suhay/sandwich-shop
Containerless, Serverless experiment using Go and GraphQL
https://github.com/suhay/sandwich-shop
golang hacktoberfest serverless
Last synced: 19 days ago
JSON representation
Containerless, Serverless experiment using Go and GraphQL
- Host: GitHub
- URL: https://github.com/suhay/sandwich-shop
- Owner: suhay
- License: mit
- Created: 2019-09-19T13:34:32.000Z (about 5 years ago)
- Default Branch: main
- Last Pushed: 2023-03-07T03:28:23.000Z (over 1 year ago)
- Last Synced: 2024-10-12T05:47:31.056Z (about 1 month ago)
- Topics: golang, hacktoberfest, serverless
- Language: Go
- Homepage:
- Size: 139 KB
- Stars: 1
- Watchers: 2
- Forks: 1
- Open Issues: 9
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# Sandwich Shop
## A containerless, serverless experiment using Go and GraphQL*Note! This is purely experimental and not meant for production use.*
The purpose of this experiment is to explore other alternatives to the container-based, serverless pattern. We are hoping this solution will minimize the overhead needed for spinning up a new container on-demand and fully eliminate the idea of a "cold start”.
## Usage
### Build
```bash
gh repo clone suhay/sandwich-shop
cd sandwich-shop
make build
```This will build directly from the source code. The compiled binary will be within the project directory. One benefit of doing it this way is the `.env` file path will default to the project's root. This means you will not need to specify it as an argument.
### Install
```bash
go install github.com/suhay/sandwich-shop@latest
go install github.com/suhay/sandwich-shop/sandwiches/gowich@latest
```Install the latest release of Sandwich Shop. This will add the binary to your `GOPATH`. The benefit of installing vs building is being able to run the binary within any directory. You will, however, need to specify a path to the `.env` file you want to use as an argument. Also, be sure to add `$GOPATH/bin` to your `PATH`,
### Run
```bash
sandwich-shop [--env=] [--port=]
```If you built the application from the source, you will need to execute the binary within the project directory.
| Flag | Description |
| --- | --- |
| --env | Path to a local, or remote .env this process should use for default configurations. |
| --port | The port number to run on. Default: 3002 |## Setting up Shop
Once you have the Sandwich Shop installed, and you have at least one Sandwich ready to go (`gowich` or `nodewich`), the next task is to set up your `.env` files. These can live anywhere and are included as CLI arguments when launching the Shop or Sandwich.
```bash
# .envMONGODB_URL=cluster0.mongodb.net
MONGODB_USER=mango
MONGODB_PASSWD=1234password
JWT_SECRET=1234567890jwtsecretcode
TIMEOUT=60
TENANTS=~/sandwich-shop/tenants
```| Key | Description |
| --- | --- |
| MONGODB_URL | (optional) URL to the mongo database that stores tenant information including the Bearer token. |
| MONGODB_USER | (optional) User for logging into the tenant info database. |
| MONGODB_PASSWD | (optional) Password for the user above. |
| JWT_SECRET | Used for signing a JWT payload while passing it through the shop as an order. This is used to verify the order came through a shop directly and that it was unchanged while in transit. This secret must be identical across all Sandwiches. |
| TIMEOUT | Seconds to wait on the order to complete. |
| TENANTS | The location where your shop tenants are stored. Think of these as project roots, function roots, or user roots of what will be using the Shop. |### Registering a Sandwich
A Sandwich is what will handle the heavy lifting. Each Sandwich can be specialized in running one type of application (Node.js, Golang, Python, etc.), or they can do a mix of them, whichever you'd prefer. There are two ways you can register your Sandwiches. The first way is through a local `sandiwches.json` file. This is the more clunky way to maintain your Sandwich registry, but it cuts out a round trip to a MongoDB. The second way is through a MongoDB collection.
```json
[
{
"_id": "rye",
"name": "Rye",
"host": "http://localhost",
"port": 4006,
"runtimes": [
"node12"
]
},
{
"_id": "ciabatta",
"name": "Ciabatta",
"host": "http://localhost",
"port": 4007,
"runtimes": [
"go1_17",
"node14",
"node16",
"python3"
]
}
]
```| Key | Description |
| --- | --- |
| _id | Sandwich's id |
| name | Human readable names for easily identifying when there is an error. |
| host | URL the Sandwich will be reached by the Sandwich Shop process (how it will receive orders). |
| port | The port on the designated host the Sandwich is reachable on |
| runtimes | An array of runtime identifiers that show what this Sandwich is set to run. |Runtimes must be defined within the GraphQL resolver which means adding one will require a pull request. The above schema can also be stored within a MongoDB collection called `sandwiches` on the `sandwich-shop` database you are using to run this application.
### Gowich
A `Gowich` is a Sandwich written in Go. You may have as many of these running as needed as long as they are all running on separate ports. Each `Gowich` should have a `.env` file supplied to it as a CLI argument.
```bash
# .gowich1.envPORT=3001
TIMEOUT=60
JWT_SECRET=1234567890jwtsecretcode
GO1_13=/usr/local/go/bin/go
TENANTS=/path/to/tenants
```| Key | Description |
| --- | --- |
| PORT | Port to run this Sandwich on. This will be overridden if --port is supplied as a command argument. |
| TIMEOUT | Timeout, in seconds, to wait for an order to finish. |
| JWT_SECRET | Must be the same JWT_SECRET as specified in the Sandwich Shop’s .env variables. This is used to ensure the request was generated and not changed between Sandwich Shop and the Gowich. |
| GO1_13 | Absolute path to the runtime’s executable. |
| TENANTS | Absolute path to tenants directory. |### Running
```bash
gowich [--env=] [--port=]
```| Flag | Description |
| --- | --- |
| --env | Path to a local, or remote .env this process should use for default configurations. |
| --port | The port number to run on. |### Nodewich
A `Nodewich` is a Sandwich written in Node. You may have as many of these running as needed as long as they are all running on separate ports. Each `Nodewich` should have a `.env` file supplied to it as a CLI argument.
```bash
#.nodewich1.envPORT=4001
TIMEOUT=60
JWT_SECRET=1234567890jwtsecretcode
NODE9_10=/path/to/node9
NODE12_7=/path/to/node12
TENANTS=/path/to/tenants
```| Key | Description |
| --- | --- |
| PORT | Port to run this Sandwich on. This will be overridden if --port is supplied as a command argument. |
| TIMEOUT | Timeout, in seconds, to wait for an order to finish. |
| JWT_SECRET | Must be the same JWT_SECRET as specified in the Sandwich Shop’s .env variables. This is used to ensure the request was generated and not changed between Sandwich Shop and the Nodewich. |
| NODE9_10 | Absolute path to the runtime’s executable. |
| TENANTS | Absolute path to tenants directory. |### Running
```bash
nodewich [--env=] [--port=]
```| Flag | Description |
| --- | --- |
| --env | Path to a local, or remote .env this process should use for default configurations. |
| --port | The port number to run on. |### Tenants
Tenants are the buckets where your functional code is placed. Within the `tenant` directory, you will place the different tenant directories. Along with the functions a tenant wishes to run, there also must be an `orders.yml` file to hold the function configurations. There can also either be an optional `.key` file to hold the API key for this particular tenant, or their API key must be stored within the `tenants` collection on your `sandwich-shop` MongoDB database.
```bash
tenants
└── b78682b3-36c8-4759-b8d1-5e62f029a1bc
├── .key (optional)
├── getSandwich.js
├── make_sandwich.go
└── orders.yml
``````yaml
# order.yml
---
getSandwich: # order name, GET https://shop.example/{tenantid}/getSandwich
runtime: node9_10 # runtime needed, used to pick sandwich
path: getSandwich.js # path function is relative to tenant's root
env: [] # any variables to include
makeSandwich:
runtime: go1_13
path: make_sandwich.go
env: []
````.key` file
```
this-is-my-api-key
```**OR**
`sandwich-shop.tenants` in your MongoDB cluster
```json
{
"_id": "tenant id",
"key": "this-is-my-api-key"
}
```## TL;DR - `sudo make me a gowich`
```bash
mkdir ~/sandwich-shop
go install github.com/suhay/sandwich-shop@latest
go install github.com/suhay/sandwich-shop/sandwiches/gowich@latestcd ~/sandwich-shop
printf "JWT_SECRET=1234567890jwtsecretcode\nTENANTS=~/sandwich-shop" > .env
printf "JWT_SECRET=1234567890jwtsecretcode\nGO1_17=/usr/local/go/bin/go" > .node1.env
echo '[{"_id": "ciabatta", "name": "Ciabatta", "host": "http://127.0.0.1", "port": 4007, "runtimes": ["go1_17"]}]' > sandwiches.json
mkdir myFunctionscd myFunctions
echo "password1234" > .key
printf -- '---\nhello:\n runtime: go1_17\n path: hello.go' > orders.yml
printf 'package main\nimport "fmt"\nfunc main() {\nfmt.Printf("%%s", "Hello!")\n}' > hello.go
```### Run
```
sandwich-shop --env ~/sandwich-shop/.env &
gowich --env ~/sandwich-shop/.node1.env --port 4007 &
```### Use
```bash
curl -X POST --header "Authorization: Bearer password1234" http://localhost:3002/shop/myFunctions/hello
```## Current Development
- [x] ~~Move tenant path into an environment variable~~
- [ ] CLI for adding `tenants`, standing up and tearing down Sandwiches, and changing `.key` values.
- [ ] A+B testing against a Serverless pattern (to see if this is even a thing or just something for fun)
- [ ] Security audit on tenants### Developing for Sandwich Shop
```
make dev
```