Skip to content
This repository has been archived by the owner on Jul 15, 2024. It is now read-only.

0.5 - Feature scan endpoint directory #12

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
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
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,9 @@ There's also a 1% chance for the server to claim to be a [Teapot](https://tools.

**Note**: JSON keys must be strings, providing your response codes as integers will not work!

### Registering endpoints automatically
The service will scan the `endpoints/` directory relative to the currenct working directory on startup. You can change the directory to be scanned by adding a flag `--endpoint-dir=ENDPOINT_DIR`.

# Tags
Apidemic uses tags to annotate what kind of fake data to generate and also control different requrements of fake data.

Expand Down
3 changes: 2 additions & 1 deletion api.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import (
)

// Version is the version of apidemic. Apidemic uses semver.
const Version = "0.4"
const Version = "0.5"

var maxItemTime = cache.DefaultExpiration

Expand Down Expand Up @@ -149,6 +149,7 @@ func DynamicEndpoint(w http.ResponseWriter, r *http.Request) {
return
}
}

responseText := fmt.Sprintf("apidemic: %s has no %s endpoint", vars["endpoint"], r.Method)
RenderJSON(w, http.StatusNotFound, NewResponse(responseText))
}
Expand Down
32 changes: 7 additions & 25 deletions api_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package apidemic
import (
"bytes"
"encoding/json"
"io"
"io/ioutil"
"net/http"
"net/http/httptest"
Expand All @@ -21,7 +20,7 @@ func TestDynamicEndpointFailsWithoutRegistration(t *testing.T) {
payload := registerPayload(t, "fixtures/sample_request.json")

w := httptest.NewRecorder()
req := jsonRequest("POST", "/api/test", payload)
req := JsonRequest("POST", "/api/test", payload)
s.ServeHTTP(w, req)

assert.Equal(t, http.StatusNotFound, w.Code)
Expand All @@ -32,12 +31,12 @@ func TestDynamicEndpointWithGetRequest(t *testing.T) {
payload := registerPayload(t, "fixtures/sample_request.json")

w := httptest.NewRecorder()
req := jsonRequest("POST", "/register", payload)
req := JsonRequest("POST", "/register", payload)
s.ServeHTTP(w, req)
require.Equal(t, http.StatusOK, w.Code)

w = httptest.NewRecorder()
req = jsonRequest("GET", "/api/test", nil)
req = JsonRequest("GET", "/api/test", nil)
s.ServeHTTP(w, req)

assert.Equal(t, http.StatusOK, w.Code)
Expand All @@ -49,12 +48,12 @@ func TestDynamicEndpointWithPostRequest(t *testing.T) {
payload["http_method"] = "POST"

w := httptest.NewRecorder()
req := jsonRequest("POST", "/register", payload)
req := JsonRequest("POST", "/register", payload)
s.ServeHTTP(w, req)
require.Equal(t, http.StatusOK, w.Code)

w = httptest.NewRecorder()
req = jsonRequest("POST", "/api/test", nil)
req = JsonRequest("POST", "/api/test", nil)

s.ServeHTTP(w, req)
assert.Equal(t, http.StatusCreated, w.Code)
Expand All @@ -66,12 +65,12 @@ func TestDynamicEndpointWithForbiddenResponse(t *testing.T) {
registerPayload["response_code_probabilities"] = map[string]int{"403": 100}

w := httptest.NewRecorder()
req := jsonRequest("POST", "/register", registerPayload)
req := JsonRequest("POST", "/register", registerPayload)
s.ServeHTTP(w, req)
require.Equal(t, http.StatusOK, w.Code)

w = httptest.NewRecorder()
req = jsonRequest("GET", "/api/test", nil)
req = JsonRequest("GET", "/api/test", nil)

s.ServeHTTP(w, req)
assert.Equal(t, http.StatusForbidden, w.Code)
Expand All @@ -97,20 +96,3 @@ func registerPayload(t *testing.T, fixtureFile string) map[string]interface{} {

return api
}

func jsonRequest(method string, path string, body interface{}) *http.Request {
var bEnd io.Reader
if body != nil {
b, err := json.Marshal(body)
if err != nil {
return nil
}
bEnd = bytes.NewReader(b)
}
req, err := http.NewRequest(method, path, bEnd)
if err != nil {
panic(err)
}
req.Header.Set("Content-Type", "application/json")
return req
}
76 changes: 76 additions & 0 deletions cmd/apidemic/main.go
Original file line number Diff line number Diff line change
@@ -1,18 +1,36 @@
package main

import (
"bytes"
"encoding/json"
"fmt"
"io/ioutil"
"log"
"net/http"
"net/http/httptest"
"os"
"path/filepath"

"github.com/codegangsta/cli"
"github.com/gernest/apidemic"
"github.com/gorilla/mux"
)

func server(ctx *cli.Context) {
port := ctx.Int("port")
endpointDir := ctx.String("endpoint-dir")
s := apidemic.NewServer()

_, err := os.Stat(endpointDir)
if err != nil && endpointDir != "endpoints/" {
fmt.Errorf("endpoint not found: %s", endpointDir)
}

err = addEndpoints(s, endpointDir)
if err != nil {
log.Fatalln(err)
}

log.Println("starting server on port :", port)
log.Fatal(http.ListenAndServe(fmt.Sprintf(":%d", port), s))
}
Expand All @@ -38,8 +56,66 @@ func main() {
Value: 3000,
EnvVar: "PORT",
},
cli.StringFlag{
Name: "endpoint-dir",
Usage: "Directory to scan for endpoint",
Value: "endpoints/",
EnvVar: "ENDPOINT_DIR",
},
},
},
}
app.RunAndExitOnError()
}

// addEndpoints iterates over a directory and tries to register each file as an endpoint
// if directory does not exist or not readable it will simply return without registration
// failing registration however causes an error response
func addEndpoints(s *mux.Router, endpointDir string) error {
var registerPayload map[string]interface{}
files, err := ioutil.ReadDir(endpointDir)
if err != nil {
return nil
}

for _, file := range files {
if file.IsDir() {
continue
}

fullPath := filepath.Join(endpointDir ,file.Name())

registerPayload, err = getRegisterPayload(fullPath)
if err != nil {
return err
}

w := httptest.NewRecorder()
req := apidemic.JsonRequest("POST", "/register", registerPayload)
s.ServeHTTP(w, req)

log.Printf("%s is registered\n", fullPath)

if w.Code != http.StatusOK {
return fmt.Errorf("registering %s failed", fullPath)
}
}

return nil
}

func getRegisterPayload(endpoint string) (map[string]interface{}, error) {
var api map[string]interface{}

content, err := ioutil.ReadFile(endpoint)
if err != nil {
return api, err
}

err = json.NewDecoder(bytes.NewReader(content)).Decode(&api)
if err != nil {
return api, err
}

return api, nil
}
26 changes: 26 additions & 0 deletions helper.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package apidemic

import (
"bytes"
"encoding/json"
"io"
"net/http"
)

// JsonRequest creates an HTTP request
func JsonRequest(method string, path string, body interface{}) *http.Request {
var bEnd io.Reader
if body != nil {
b, err := json.Marshal(body)
if err != nil {
return nil
}
bEnd = bytes.NewReader(b)
}
req, err := http.NewRequest(method, path, bEnd)
if err != nil {
panic(err)
}
req.Header.Set("Content-Type", "application/json")
return req
}