Exemple #1
0
// We can override Content-Type
func TestEnableToOverrideDefaultContentType(t *testing.T) {
	request, _ := http.NewRequest("GET", "/", nil)
	response := httptest.NewRecorder()

	a, err := dou.NewAPI("jsonapi")
	a.Handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "text/plain")
	})

	if err != nil {
		panic(err)
	}

	a.LogStackTrace = false

	if err != nil {
		panic(err)
	}

	a.ServeHTTP(response, request)

	if response.Header().Get("Content-Type") != "text/plain" {
		t.Error("default content type that is set by jsonapi.DefaultBeforeDispatch should be overridable")
	}
}
Exemple #2
0
// APIStatus should set X-API-Status header
func TestAPIStatus(t *testing.T) {
	request, _ := http.NewRequest("GET", "/", nil)
	response := httptest.NewRecorder()

	a, err := dou.NewAPI("jsonapi")
	a.Handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		a.APIStatus(w, 999)
	})

	if err != nil {
		panic(err)
	}

	a.LogStackTrace = false

	if err != nil {
		panic(err)
	}

	a.ServeHTTP(response, request)

	if response.Header().Get("X-API-Status") != "999" {
		t.Errorf("APIStatus should set X-API-Status. (expect) = \"999\", but (got) = %v", response.Header().Get("X-API-Status"))
	}
}
Exemple #3
0
// OnPanic should not write if response is already written before panic occur
func TestOnPanicDontWriteIfResponseIsAlreadyWrittenBeforePanicOccur(t *testing.T) {
	request, _ := http.NewRequest("GET", "/", nil)
	response := httptest.NewRecorder()

	a, err := dou.NewAPI("jsonapi")
	a.Handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte("hello"))
		panic("<test panic>")
	})

	if err != nil {
		panic(err)
	}

	a.LogStackTrace = false

	if err != nil {
		panic(err)
	}

	a.ServeHTTP(response, request)

	if !bytes.Equal(response.Body.Bytes(), []byte("hello")) {
		t.Error("OnPanic should not write response if response is written before panic occur")
	}
}
Exemple #4
0
// OnPanic should write response if panic occur
func TestOnPanicWriteErrorMessage(t *testing.T) {
	request, _ := http.NewRequest("GET", "/", nil)
	response := httptest.NewRecorder()

	a, err := dou.NewAPI("jsonapi")
	a.Handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		panic("<test panic>")
	})

	if err != nil {
		panic(err)
	}

	a.LogStackTrace = false

	if err != nil {
		panic(err)
	}

	a.ServeHTTP(response, request)

	if err != nil {
		panic(err)
	}

	gotContentType := response.Header().Get("Content-Type")

	switch {
	case strings.HasPrefix(gotContentType, "application/json;"):
		if string(response.Body.Bytes()) == "" {
			t.Error("OnPanic should write error message.")
		} else {

			gotJSON := map[string]string{}
			err := json.Unmarshal(response.Body.Bytes(), &gotJSON)

			if err != nil {
				panic(err)
			}

			if gotJSON["message"] != http.StatusText(http.StatusInternalServerError) {
				t.Errorf("OnPanic wrote invalid error message. (got) = %s", response.Body.Bytes())
			}
		}
	case strings.HasPrefix(gotContentType, "text/plain;"):
		if string(response.Body.Bytes()) != http.StatusText(http.StatusInternalServerError) {
			t.Errorf("OnPanic wrote invalid error message. (expect) = %s, (got) = %s", http.StatusText(http.StatusInternalServerError), response.Body.Bytes())
		}
	default:
		t.Errorf("Unexpected Content-Type. (expect has prefix) = text/plain or application/json, (got) = %v", gotContentType)
	}
}
Exemple #5
0
// BeforeDispatch should set Content-Type
func TestSetDefaultContentType(t *testing.T) {
	request, _ := http.NewRequest("GET", "/", nil)
	response := httptest.NewRecorder()

	a, err := dou.NewAPI("jsonapi")
	a.Handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
	})

	if err != nil {
		panic(err)
	}

	a.LogStackTrace = false

	if err != nil {
		panic(err)
	}

	a.ServeHTTP(response, request)

	if response.Header().Get("Content-Type") != "application/json; charset=utf-8" {
		t.Errorf("jsonapi.DefaultBeforeDispatch should set default content type `application/json; charset=utf-8`, but got %v", response.Header().Get("Content-Type"))
	}
}
Exemple #6
0
func main() {
	defer teardown()

	// --- Setup Router ---
	// ! You can use router keeping interface `api.Router` instead of github.com/ToQoz/rome
	router := rome.NewRouter()
	router.NotFoundFunc(func(w http.ResponseWriter, r *http.Request) {
		j, err := json.Marshal(map[string]string{
			"message":           http.StatusText(http.StatusNotFound),
			"documentation_url": "http://toqoz.net",
		})

		if err != nil {
			http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
			return
		}

		w.WriteHeader(http.StatusNotFound)
		// skip wrote bytesyze
		_, err = fmt.Fprintln(w, string(j))

		if err != nil {
			log.Printf("dou: fail to fmt.Fpintln(http.ResponseWriter, string)\n%v", err)
		}
	})

	// --- Setup API ---
	api, err := dou.NewAPI("jsonapi")
	api.Handler = router
	//api, err := dou.NewAPI("jsonapi")
	if err != nil {
		log.Fatal(err)
	}

	api.BeforeDispatch = func(w http.ResponseWriter, r *http.Request) (http.ResponseWriter, *http.Request) {
		// Call default
		w, r = api.Plugin.BeforeDispatch(w, r)

		lw := apachelog.NewLoggingWriter(w, r, logger)
		return lw, r
	}

	api.AfterDispatch = func(w http.ResponseWriter, r *http.Request) (http.ResponseWriter, *http.Request) {
		// Call default
		w, r = api.Plugin.AfterDispatch(w, r)

		if lw, ok := w.(*apachelog.LoggingWriter); ok {
			lw.EmitLog()
		}

		return w, r
	}

	api.ReadTimeout = 10 * time.Second
	api.WriteTimeout = 10 * time.Second
	api.MaxHeaderBytes = 1 << 20

	// --- Map routes ---
	router.GetFunc("/users", func(w http.ResponseWriter, r *http.Request) {
		api.APIStatus(w, APIStatusOk)
		api.Ok(w, users, http.StatusOK)
	})

	router.GetFunc("/error", func(w http.ResponseWriter, r *http.Request) {
		api.APIStatus(w, APIStatusUnexpectedError)
		api.Error(w, map[string]string{"message": "Internal server error"}, http.StatusInternalServerError)
	})

	// Try Ok    $ curl -X POST -d 'name=ToQoz&[email protected]' -D - :8099/users
	// Try Error $ curl -X POST -D - :8099/users
	router.PostFunc("/users", func(w http.ResponseWriter, r *http.Request) {
		u := &User{
			Name:  r.FormValue("name"),
			Email: r.FormValue("email"),
		}

		errs := u.Validate()

		if len(errs) > 0 {
			api.APIStatus(w, APIStatusValidationError)
			api.Error(w, newAPIErrors(errs), 422)
			return
		}

		err := u.Save()

		if err != nil {
			api.APIStatus(w, APIStatusUnexpectedError)
			api.Error(w, newAPIErrors(errs), http.StatusInternalServerError)
			return
		}

		api.APIStatus(w, APIStatusOk)
		api.Ok(w, u, http.StatusCreated)
	})

	// --- Create listener ---
	// You can use utility, for example github.com/lestrrat/go-server-starter-listener etc.
	l, err := net.Listen("tcp", ":8099")

	if err != nil {
		log.Printf("Could not listen: %s", ":8099")
		teardown()
		os.Exit(1)
	}

	log.Printf("Listen: %s", ":8099")

	// --- Handle C-c ---
	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt)

	go func() {
		for sig := range c {
			log.Print("Stopping the server...")

			switch sig {
			case os.Interrupt:
				// --- Stop Server ---
				api.Stop()
				return
			default:
				log.Print("Receive unknown signal...")
			}
		}
	}()

	// --- Run Server ---
	api.Run(l)
}
Exemple #7
0
func main() {
	defer teardown()

	api, err := dou.NewAPI("jsonapi")
	if err != nil {
		log.Fatal(err)
	}

	api.ReadTimeout = 10 * time.Second
	api.WriteTimeout = 10 * time.Second
	api.MaxHeaderBytes = 1 << 20

	// --- Map routes ---
	api.Handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		switch r.URL.Path {
		case "/":
			api.Ok(w, map[string]string{"hello": "world"}, http.StatusOK)
		case "/error":
			err := errors.New("some error occur")
			api.Error(w, newAPIError(err), http.StatusInternalServerError)
		case "/errors":
			var errs []error
			errs = append(errs, errors.New("1 error occur"))
			errs = append(errs, errors.New("2 error occur"))
			api.Error(w, newAPIErrors(errs), http.StatusInternalServerError)
		default:
			api.Error(w, map[string]string{"message": http.StatusText(http.StatusNotFound)}, http.StatusNotFound)
		}
	})

	// --- Create listener ---
	// You can use utility, for example github.com/lestrrat/go-server-starter-listener etc.
	l, err := net.Listen("tcp", ":8099")

	if err != nil {
		log.Printf("Could not listen: %s", ":8099")
		teardown()
		os.Exit(1)
	}

	log.Printf("Listen: %s", ":8099")

	// --- Handle C-c ---
	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt)

	go func() {
		for sig := range c {
			log.Print("Stopping the server...")

			switch sig {
			case os.Interrupt:
				// --- Stop Server ---
				api.Stop()
				return
			default:
				log.Print("Receive unknown signal...")
			}
		}
	}()

	// --- Run Server ---
	api.Run(l)
}