Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ xcompile:
GOPATH=${GOPATH} GOOS=windows GOARCH=amd64 go build -o releases/windows/amd64/restjester ${GOPACKAGE}

# OSX 64
mkdir -p releases/OSX/amd64
mkdir -p releases/darwin/amd64
GOPATH=${GOPATH} GOOS=darwin GOARCH=amd64 go build -o releases/darwin/amd64/restjester ${GOPACKAGE}

# linux 64
Expand Down
25 changes: 17 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,17 @@

Download the server compiled for your architecture

[OSX] (https://github.com/kswope/restjester/blob/sync/releases/darwin/amd64/restjester?raw=true)
[OSX](https://github.com/kswope/restjester/blob/sync/releases/darwin/amd64/restjester?raw=true)
|
[Linux 386] (https://github.com/kswope/restjester/blob/sync/releases/linux/386/restjester?raw=true)
[Linux 386](https://github.com/kswope/restjester/blob/sync/releases/linux/386/restjester?raw=true)
|
[Linux x86-64] (https://github.com/kswope/restjester/blob/sync/releases/linux/amd64/restjester?raw=true)
[Linux x86-64](https://github.com/kswope/restjester/blob/sync/releases/linux/amd64/restjester?raw=true)
|
[Linux ARM] (https://github.com/kswope/restjester/blob/sync/releases/linux/arm/restjester?raw=true)
[Linux ARM](https://github.com/kswope/restjester/blob/sync/releases/linux/arm/restjester?raw=true)
|
[Linux ARM64] (https://github.com/kswope/restjester/blob/sync/releases/linux/arm64/restjester?raw=true)
[Linux ARM64](https://github.com/kswope/restjester/blob/sync/releases/linux/arm64/restjester?raw=true)
|
[Windows](https://github.com/kswope/restjester/blob/sync/releases/windows/amd64/restjester?raw=true)
[Windows](https://github.com/kswope/restjester/blob/sync/releases/windows/amd64/restjester.exe?raw=true)


#### If you want/need to compile your own binary
Expand All @@ -50,9 +50,19 @@ As a daemon (requires deamon)
shell> deamon --name restjester ./restjester
```

#### For proxying and cache of API
To forward requests when there is no previously registered endpoint and then cache the response

With output to terminal
```
shell> ./restjester -f https://apihost:80
Starting server at port 5351
```


As a daemon (requires deamon)
```
shell> deamon --name restjester ./restjester -f https://apihost:80
```


### Complete Functionality
Expand All @@ -72,7 +82,6 @@ shell> deamon --name restjester ./restjester




### Example in ruby using rest-client and rspec

```
Expand Down
Binary file modified releases/darwin/amd64/restjester
Binary file not shown.
Binary file modified releases/linux/386/restjester
Binary file not shown.
Binary file modified releases/linux/amd64/restjester
Binary file not shown.
Binary file modified releases/linux/arm/restjester
Binary file not shown.
Binary file modified releases/linux/arm64/restjester
Binary file not shown.
Binary file removed releases/windows/amd64/restjester
Binary file not shown.
Binary file added releases/windows/amd64/restjester.exe
Binary file not shown.
13 changes: 9 additions & 4 deletions server/src/restjester/endpoint.go
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
package main

// import "fmt"
import "reflect"
import (
"net/http"
"reflect"
)

type endpoint struct {
Path string // /a/b/c
Query map[string][]string // ?a=b&c=d
Method string // POST, GET
Status int //
Data string // endpoint data
Data []byte // endpoint data
Header http.Header // header to response
}

//-----------------------------------------------------------------------------
Expand All @@ -24,14 +27,16 @@ func createEndpoint(
query map[string][]string,
method string,
status int,
data string,
data []byte,
header http.Header,
) endpoint {
return endpoint{
Path: path,
Query: query,
Method: method,
Status: status,
Data: data,
Header: header,
}
}

Expand Down
12 changes: 6 additions & 6 deletions server/src/restjester/endpoint_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,19 +15,19 @@ func getSampleEndpoint(index int) endpoint {
var query map[string][]string

query = map[string][]string{"a": []string{"1"}}
ep = createEndpoint("/a/b/c", query, "POST", 200, "data a")
ep = createEndpoint("/a/b/c", query, "POST", 200, []byte("data a"), defaultHeader)
samples = append(samples, ep)

query = map[string][]string{"b": []string{"2"}}
ep = createEndpoint("/d/e/f", query, "GET", 200, "data b")
ep = createEndpoint("/d/e/f", query, "GET", 200, []byte("data b"), defaultHeader)
samples = append(samples, ep)

query = map[string][]string{"c": []string{"3"}}
ep = createEndpoint("/g/h/i", query, "POST", 200, "data c")
ep = createEndpoint("/g/h/i", query, "POST", 200, []byte("data c"), defaultHeader)
samples = append(samples, ep)

query = map[string][]string{"d": []string{"4"}}
ep = createEndpoint("/j/k/l", query, "POST", 200, "data d")
ep = createEndpoint("/j/k/l", query, "POST", 200, []byte("data d"), defaultHeader)
samples = append(samples, ep)

return samples[index]
Expand All @@ -39,14 +39,14 @@ func getSampleEndpoint(index int) endpoint {
func TestCreateEndpoint(t *testing.T) {

query := map[string][]string{"a": []string{"1"}}
endpoint := createEndpoint("/a/b/c", query, "POST", 200, "data a")
endpoint := createEndpoint("/a/b/c", query, "POST", 200, []byte("data a"), defaultHeader)

// equality checks
pathCheck := endpoint.Path == "/a/b/c"
queryCheck := endpoint.Query["a"][0] == "1"
methodCheck := endpoint.Method == "POST"
statusCheck := endpoint.Status == 200
dataCheck := endpoint.Data == "data a"
dataCheck := string(endpoint.Data) == "data a"

if !(pathCheck && queryCheck && methodCheck && statusCheck && dataCheck) {
t.Errorf("Failed with path:%q query:%s method:%s data:%s",
Expand Down
6 changes: 3 additions & 3 deletions server/src/restjester/extract_from_request.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,11 @@ func extractMethodFromRequest(req *http.Request) string {
}
}

func extractDataFromRequest(req *http.Request) string {
func extractDataFromRequest(req *http.Request) []byte {
if len(req.Form["data"]) > 0 {
return req.Form["data"][0]
return []byte(req.Form["data"][0])
} else {
return "" // default
return []byte("") // default
}
}

Expand Down
2 changes: 1 addition & 1 deletion server/src/restjester/extract_from_request_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ func TestExtractData(t *testing.T) {

expected := "the payload"

if data != expected {
if string(data) != expected {
t.Errorf("expected '%s', got '%s' from request %q", expected, data, request)
}

Expand Down
68 changes: 57 additions & 11 deletions server/src/restjester/handlers.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
package main

import "fmt"
import "net/http"
import "encoding/json"
import (
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
)

func handleRootPut(w http.ResponseWriter, req *http.Request) {
errMsg := "PUT / not implemented yet\n"
Expand All @@ -14,6 +17,7 @@ func handleRootPut(w http.ResponseWriter, req *http.Request) {
func handleRootGet(w http.ResponseWriter, req *http.Request) {
fmt.Println("dumping endpoints")
dumped, _ := json.Marshal(endpoints)
w.Header().Set("Content-Type", "application/json")
w.Write([]byte(dumped))
}

Expand All @@ -27,6 +31,7 @@ func handleRootPost(w http.ResponseWriter, req *http.Request) {
extractMethodFromRequest(req),
extractStatusFromRequest(req),
extractDataFromRequest(req),
defaultHeader,
)

if endpoint.Path == "" {
Expand All @@ -53,17 +58,58 @@ func handleRootDelete(w http.ResponseWriter, req *http.Request) {
func handlerEndpoint(w http.ResponseWriter, req *http.Request) {

// create a 'close enough' endpoint to search with
var endpointApprox = createEndpoint(req.URL.Path, req.URL.Query(), req.Method, 200, "")
var endpointApprox = createEndpoint(req.URL.Path, req.URL.Query(), req.Method, 200, []byte{}, defaultHeader)

if endpoint, found := endpointGet(endpoints, endpointApprox); found {
fmt.Printf("endpoint HIT %s\n", formatEndpoint(endpoint))
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(endpoint.Status)
w.Write([]byte(endpoint.Data))
doResponse(w, endpoint)
} else {
fmt.Printf("endpoint MISS, %s\n", formatEndpoint(endpointApprox))
w.WriteHeader(http.StatusNotFound)
fmt.Fprintln(w, "404 endpoint not found")

if len(proxyURL) > 0 {
urlEndPoint := fmt.Sprintf("%s%s", proxyURL, req.URL)
fmt.Printf("Proxying url, %s\n", urlEndPoint)
proxyRequest, err := http.NewRequest(endpointApprox.Method, urlEndPoint, req.Body)
if err != nil {
errorHandle(w, err)
return
}
proxyRequest.Header = req.Header

proxyResponse, err := httpClient.Do(proxyRequest)
if err != nil {
errorHandle(w, err)
return
}
proxyResponseData, err := ioutil.ReadAll(proxyResponse.Body)
if err != nil {
errorHandle(w, err)
return
}
endpointApprox.Data = proxyResponseData
endpointApprox.Header = proxyResponse.Header
fmt.Println(endpointApprox.Header)
endpoints = endpointPut(endpoints, endpointApprox)

doResponse(w, endpointApprox)
} else {
fmt.Printf("endpoint MISS, %s\n", formatEndpoint(endpointApprox))
w.WriteHeader(http.StatusNotFound)
fmt.Fprintln(w, "404 endpoint not found")
}
}

}

func errorHandle(w http.ResponseWriter, err error) {
fmt.Printf("proxy MISS, %s\n", err)
w.WriteHeader(http.StatusInternalServerError)
fmt.Fprintln(w, "500 Internal Server Error")
}

func doResponse(w http.ResponseWriter, endpoint endpoint) {
fmt.Printf("endpoint HIT %s\n", formatEndpoint(endpoint))
for k, v := range endpoint.Header {
w.Header().Set(k, v[0])
}
w.WriteHeader(endpoint.Status)
w.Write(endpoint.Data)
}
19 changes: 16 additions & 3 deletions server/src/restjester/restjester.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,17 @@
package main

import "fmt"
import "net/http"
import (
"crypto/tls"
"flag"
"fmt"
"net/http"
)

var endpoints = createEndpoints()
var gPort int
var proxyURL string
var defaultHeader = http.Header{"Content-Type": []string{"application/json"}}
var httpClient = http.Client{Transport: &http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: true}}}

func handler(w http.ResponseWriter, req *http.Request) {

Expand All @@ -30,7 +37,13 @@ func handler(w http.ResponseWriter, req *http.Request) {

func main() {

gPort = 5351
flagPort := flag.Int("p", 5351, "the server port")
flagURL := flag.String("f", "", "url to forward the request")
flag.Parse()

gPort = *flagPort
proxyURL = *flagURL

fmt.Printf("Starting server at port %d\n", gPort)
http.HandleFunc("/", handler)
http.ListenAndServe(fmt.Sprintf(":%d", gPort), nil)
Expand Down