Skip to content

Instantly share code, notes, and snippets.

@itsbalamurali
Created October 4, 2016 01:37
Show Gist options
  • Select an option

  • Save itsbalamurali/d097ae09ece5ea375fe1c1694ab7a4ce to your computer and use it in GitHub Desktop.

Select an option

Save itsbalamurali/d097ae09ece5ea375fe1c1694ab7a4ce to your computer and use it in GitHub Desktop.
Iris
package controllers
import (
"github.com/goamz/goamz/s3"
"github.com/itsbalamurali/parse-server/models"
"github.com/kataras/iris"
"io/ioutil"
"bytes"
)
type FileAPI struct {
*iris.Context
bucket *s3.Bucket
}
/*
InvalidFileName 122 An invalid filename was used for Parse File. A valid file name contains only a-zA-Z0-9_. characters and is between 1 and 128 characters.
MissingContentType 126 Missing content type.
MissingContentLength 127 Missing content length.
InvalidContentLength 128 Invalid content length.
FileTooLarge 129 File size exceeds maximum allowed.
FileSaveError 130 Error saving a file.
FileDeleteError 131 File could not be deleted.
*/
func (f *FileAPI) Upload(ctx *iris.Context) {
if ctx.PostBody() == nil {
ctx.JSON(iris.StatusBadRequest, models.Error{Message: "InvalidContentLength", Code: 128})
}
if ctx.Request.Header.ContentLength() == 0 {
ctx.JSON(iris.StatusBadRequest, models.Error{Message: "MissingContentLength", Code: 128})
}
if ctx.Request.Header.ContentType() == nil {
ctx.JSON(iris.StatusBadRequest, models.Error{Message: "MissingContentType", Code: 128})
}
filename := ctx.Param("name")
content, err := ioutil.ReadAll(bytes.NewReader(ctx.PostBody()))
if err != nil {
ctx.JSON(iris.StatusBadRequest, models.Error{Message: "FileSaveError", Code: 130})
}
ctype := string(ctx.Request.Header.ContentType()[:])
err = f.bucket.Put(filename, content, ctype, s3.PublicRead, s3.Options{})
if err != nil {
ctx.JSON(iris.StatusBadRequest, models.Error{Message: "FileSaveError", Code: 130})
}
url := f.bucket.URL(filename)
ctx.Response.Header.Set("Location", url)
ctx.JSON(iris.StatusCreated, iris.Map{"url": url, "name": filename})
}
func (f *FileAPI) Delete(ctx *iris.Context) {
filename := ctx.Param("name")
f.bucket.Del(filename)
ctx.Response.Header.SetStatusCode(204)
}
package controllers
import (
"testing"
"net/http/httptest"
"fmt"
"net/http"
"bytes"
"github.com/goamz/goamz/aws"
"github.com/goamz/goamz/s3"
"github.com/goamz/goamz/s3/s3test"
)
func startServer() (*s3test.Server, *s3.Bucket) {
testServer, _ := s3test.NewServer(new(s3test.Config))
auth := aws.Auth{"abc", "123", ""}
server := s3.New(auth, aws.Region{Name: "faux-region-1", S3Endpoint: testServer.URL(), S3LocationConstraint: true}) // Needs true for s3test
b := server.Bucket("foobar.com")
b.PutBucket(s3.Private)
return testServer, b
}
func TestPut(t *testing.T) {
s, b := startServer()
defer s.Quit()
w := httptest.NewRecorder()
r, _ := http.NewRequest("POST", "/1/files/foo.txt", bytes.NewBufferString("foobar"))
r.Header.Set("Content-Type", "text/plain")
upload.Service(b).ServeHTTP(w, r)
expCode := 200
if w.Code != expCode {
t.Fatalf("Response status expected: %#v, got: %#v", expCode, w.Code)
}
expLoc := b.URL("/foo.txt")
if w.Header().Get("Location") != expLoc {
t.Fatalf("Response Location header expected: %#v, got: %#v", expLoc, w.Header().Get("Location"))
}
expBody := fmt.Sprintf(`{"url":"%s"}`, expLoc)
if w.Body.String() != expBody {
t.Fatalf("Response body expected: %#v, got: %#v", expBody, w.Body.String())
}
data, _ := b.Get("/foo.txt")
if string(data) != "foobar" {
t.Fatalf("Stored file content expected: %#v, got: %#v", "foobar", string(data))
}
}
func TestPutBodyNil(t *testing.T) {
s, b := startServer()
defer s.Quit()
w := httptest.NewRecorder()
r, _ := http.NewRequest("PUT", "/files/foo.txt", nil)
upload.Service(b).ServeHTTP(w, r)
expCode := 400
if w.Code != expCode {
t.Fatalf("Response status expected: %#v, got: %#v", expCode, w.Code)
}
expBody := "Body must be set\n"
if w.Body.String() != expBody {
t.Fatalf("Response body expected: %#v, got: %#v", expBody, w.Body.String())
}
}
func TestGet(t *testing.T) {
s, b := startServer()
defer s.Quit()
b.Put("/foo.txt", []byte("foobar"), "text/plain", s3.PublicRead)
w := httptest.NewRecorder()
r, _ := http.NewRequest("GET", "/files/foo.txt", nil)
upload.Service(b).ServeHTTP(w, r)
expCode := 200
if w.Code != expCode {
t.Fatalf("Response status expected: %#v, got: %#v", expCode, w.Code)
}
expBody := fmt.Sprintf(`{"url":"%s"}`, b.URL("/foo.txt"))
if w.Body.String() != expBody {
t.Fatalf("Response body expected: %#v, got: %#v", expBody, w.Body.String())
}
}
func TestDelete(t *testing.T) {
s, b := startServer()
defer s.Quit()
b.Put("/foo.txt", []byte("foobar"), "text/plain", s3.PublicRead)
w := httptest.NewRecorder()
r, _ := http.NewRequest("DELETE", "/files/foo.txt", nil)
upload.Service(b).ServeHTTP(w, r)
expCode := 204
if w.Code != expCode {
t.Fatalf("Response status expected: %#v, got: %#v", expCode, w.Code)
}
res, _ := b.Head("/foo.txt")
if res != nil {
t.Fatalf("File /foo.txt has not been deleted from S3.")
}
}
// @APIVersion 1.0.0
// @APITitle Parse Server
// @APIDescription Parse Mobile Backend API.
// @Contact [email protected]
// @License MIT
// @LicenseUrl https://github.com/itsbalamurali/parse-server/blob/master/LICENSE
// @BasePath http://0.0.0.0:8080/1/
package main
import (
"github.com/iris-contrib/middleware/cors"
"github.com/iris-contrib/middleware/logger"
"github.com/iris-contrib/middleware/recovery"
//"github.com/itsbalamurali/parse-server/config"
"github.com/itsbalamurali/parse-server/controllers"
"github.com/itsbalamurali/parse-server/database"
"github.com/itsbalamurali/parse-server/middleware"
"github.com/itsbalamurali/parse-server/models"
"github.com/kataras/iris"
"os"
"github.com/valyala/fasthttp"
)
func XparseHandler() fasthttp.RequestHandler {
//iris.Config.Websocket.Endpoint = "/ws" parselive query
iris.Config.DisableBanner = true
iris.Config.LoggerPreffix = "xParse"
//Enable Cors
crs := cors.New(cors.Options{
AllowedHeaders: []string{"X-Parse-Master-Key",
"X-Parse-REST-API-Key",
"X-Parse-Javascript-Key",
"X-Parse-Application-Id",
"X-Parse-Client-Version",
"X-Parse-Session-Token",
"X-Requested-With",
"X-Parse-Revocable-Session",
"Content-Type"},
AllowedMethods: []string{"GET", "PUT", "POST", "DELETE", "OPTIONS"},
AllowedOrigins: []string{"*"},
}) // options here
//set global middlewares
iris.Use(logger.New())
iris.Use(recovery.Handler)
iris.Use(crs)
iris.UseFunc(middleware.APIAuth)
//Main Database Connection
Db := database.MgoDb{}
Db.Init()
//Custom HTTP Errors
iris.OnError(iris.StatusNotFound, func(ctx *iris.Context) {
ctx.JSON(iris.StatusNotFound, models.Error{Code: iris.StatusNotFound, Message: "Resource Not Found"})
iris.Logger.Printf("http status: 404 happened!")
})
//API Version 1
v1 := iris.Party("/1")
//V1 Routes
//Classes
class := new(controllers.ClassAPI)
v1.Post("/classes/:className", class.Create)
v1.Get("/classes/:className/:objectId", class.Get)
v1.Put("/classes/:className/:objectId", class.Update)
v1.Get("/classes/:className", class.GetAll)
v1.Delete("/classes/:className/:objectId", class.Delete)
//Users
users := new(controllers.UserAPI)
v1.Post("/users", users.Signup)
v1.Get("/login", users.Login)
v1.Post("/logout", users.Logout)
v1.Get("/users/me", users.Me)
v1.Get("/users/:objectId", users.Get)
v1.Put("/users/:objectId", users.Update)
v1.Delete("/users/:objectId", users.Delete)
v1.Get("/users", users.GetAll)
v1.Post("/requestPasswordReset", users.ResetPassword)
//Sessions
sessions := new(controllers.SessionAPI)
v1.Post("/sessions", sessions.Create)
v1.Get("/sessions", sessions.GetAll)
v1.Get("/sessions/me", sessions.Get)
v1.Get("/sessions/:objectId", sessions.Get)
v1.Put("/sessions/me", sessions.Update)
v1.Put("/sessions/:objectId", sessions.Update)
v1.Delete("/sessions/:objectId", sessions.Delete)
//Roles
roles := new(controllers.RoleAPI)
v1.Post("/roles", roles.Create)
v1.Get("/roles/:objectId", roles.Get)
v1.Put("/roles/:objectId", roles.Update)
v1.Delete("/roles/:objectId", roles.Delete)
//Files
files := new(controllers.FileAPI)
v1.Post("/files/:name", files.Upload)
v1.Delete("/files/:name", files.Delete)
//Analytics
event := new(controllers.EventAPI)
v1.Post("/events/AppOpened", event.AppOpened)
v1.Get("/events/:eventName", event.GetAllEvents)
v1.Post("/events/:eventName", event.CustomEvent)
//Push Notifications
push := new(controllers.PushAPI)
v1.Post("/push", push.Create)
//Installations
installations := new(controllers.InstallAPI)
v1.Post("/installations/:objectId", installations.Create)
v1.Get("/installations/:objectId", installations.GetByID)
v1.Put("/installations/:objectId", installations.Update)
v1.Get("/installations", installations.GetAll)
v1.Post("/installations", installations.Create)
//Cloud Functions
functions := new(controllers.FunctionAPI)
v1.Post("/functions/:name", functions.ExecuteFunc)
v1.Post("/jobs/:name", functions.TriggerJob)
//Schemas
schema := new(controllers.SchemaAPI)
v1.Post("/schemas/:className", schema.Create)
v1.Get("/schemas/:className", schema.GetByID)
v1.Put("/schemas/:className", schema.Update)
v1.Get("/schemas", schema.GetAll)
v1.Delete("/className/:className", schema.Delete)
//Apps
apps := new(controllers.AppAPI)
v1.Post("/apps/:appId", apps.Create)
v1.Get("/apps/:appId", apps.GetByID)
v1.Put("/apps/:appId", apps.Update)
v1.Get("/apps", apps.Get)
//Config
conf := new(controllers.ConfigAPI)
v1.Get("/config", conf.Get)
v1.Put("/config", conf.Update)
//Function Hooks
hookfuncs := new(controllers.HFuncsAPI)
v1.Post("/hooks/functions", hookfuncs.Create)
v1.Get("/hooks/functions/:funcName", hookfuncs.GetByID)
v1.Put("/hooks/functions/:funcName", hookfuncs.Update)
v1.Delete("/hooks/functions/:funcName", hookfuncs.Delete)
//Trigger Hooks
hooktriggers := new(controllers.HTriggerAPI)
v1.Post("/hooks/triggers", hooktriggers.Create)
v1.Get("/hooks/triggers/:className/:triggerName", hookfuncs.GetByID)
v1.Put("/hooks/triggers/:funcName/:triggerName", hookfuncs.Update)
v1.Delete("/hooks/triggers/:funcName/:triggerName", hookfuncs.Delete)
enableSwagger := true //TODO Get from viper
if enableSwagger {
//Serve Swagger UI
iris.StaticWeb("/docs", "./public", 1)
//Serves Swagger JSON API Spec
v1.Get("/swagger.json", controllers.SwaggerJSON)
}
//iris.Listen(":" + port)
iris.Build()
return iris.Router
}
func main() {
//config.InitConfig()
port := os.Getenv("PORT")
if port == "" {
port = "8080"
}
handler := XparseHandler()
//Listen on port specified
host , err := os.Hostname()
if err != nil {
iris.Logger.Println("Cant determine Hostname")
host = "localhost"
}
fasthttp.ListenAndServe(":" + port,handler)
iris.Logger.Println("xParse is running on: http://"+host+":"+port)
enableSwagger := true //TODO Get from viper
if enableSwagger {
iris.Logger.Printf("You Access Swagger-UI at: http://"+host+":" + port + "/docs")
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment