This commit is contained in:
Wade Wegner 2015-04-27 19:54:13 -06:00
Коммит 35568f0977
14 изменённых файлов: 422 добавлений и 0 удалений

2
.deployment Normal file
Просмотреть файл

@ -0,0 +1,2 @@
[config]
command = GoDeploy.cmd

70
GoDeploy.cmd Normal file
Просмотреть файл

@ -0,0 +1,70 @@
@ECHO off
IF DEFINED WEBROOT_PATH (
ECHO WEBROOT_PATH is %WEBROOT_PATH%
GOTO :SETUP
)
ECHO set WEBROOT_PATH to D:\home\site\wwwroot
SET WEBROOT_PATH=D:\home\site\wwwroot
:SETUP
SET GOROOT=D:\Program Files\go\1.4.2
SET GOPATH=%WEBROOT_PATH%\gopath
SET GOEXE="%GOROOT%\bin\go.exe"
SET FOLDERNAME=azureapp
SET GOAZUREAPP=%WEBROOT_PATH%\gopath\src\%FOLDERNAME%
IF EXIST %GOPATH% (
ECHO %GOPATH% already exist
ECHO Removing %GOAZUREAPP%
RMDIR /S /Q %GOAZUREAPP%
) else (
ECHO creating %GOPATH%\bin
MKDIR "%GOPATH%\bin"
ECHO creating %GOPATH%\pkg
MKDIR "%GOPATH%\pkg"
ECHO creating %GOPATH%\src
MKDIR "%GOPATH%\src"
)
ECHO creating %GOAZUREAPP%
MKDIR %GOAZUREAPP%
ECHO --------------------------------------------
ECHO GOROOT: %GOROOT%
ECHO GOEXE: %GOEXE%
ECHO GOPATH: %GOPATH%
ECHO GOAZUREAPP: %GOAZUREAPP%
ECHO --------------------------------------------
ECHO copying source code to %GOAZUREAPP%
CP error.go %GOAZUREAPP%
CP handlers.go %GOAZUREAPP%
CP logger.go %GOAZUREAPP%
CP main.go %GOAZUREAPP%
CP repo.go %GOAZUREAPP%
CP router.go %GOAZUREAPP%
CP routes.go %GOAZUREAPP%
CP todo.go %GOAZUREAPP%
ECHO copying resources to WEBROOT_PATH
CP %DEPLOYMENT_SOURCE%\Web.Config %WEBROOT_PATH%\Web.Config -f
CP %DEPLOYMENT_SOURCE%\apiapp.json %WEBROOT_PATH%\apiapp.json
MKDIR "%WEBROOT_PATH%\metadata"
CP %DEPLOYMENT_SOURCE%\metadata\apiDefinition.swagger.json %WEBROOT_PATH%\metadata\apiDefinition.swagger.json -f
ECHO Resolving dependencies
CD "%GOPATH%\src"
%GOEXE% get %FOLDERNAME%
ECHO Building ...
%GOEXE% build -o %WEBROOT_PATH%\%FOLDERNAME%.exe %FOLDERNAME%
ECHO cleaning up ...
CD %WEBROOT_PATH%
RMDIR /S /Q %GOPATH%
ECHO DONE!

0
README.md Normal file
Просмотреть файл

10
Web.Config Normal file
Просмотреть файл

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.webServer>
<handlers>
<add name="httpplatformhandler" path="*" verb="*" modules="httpPlatformHandler" resourceType="Unspecified" />
</handlers>
<httpPlatform processPath="D:\home\site\wwwroot\azureapp.exe" startupTimeLimit="60">
</httpPlatform>
</system.webServer>
</configuration>

10
apiapp.json Normal file
Просмотреть файл

@ -0,0 +1,10 @@
{
"$schema": "http://json-schema.org/schemas/2014-11-01/apiapp.json#",
"id": "GoTodoApiAppDemo",
"namespace": "microsoft.com",
"gateway": "2015-01-14",
"version": "1.0.0",
"title": "Go Todo Api App Demo",
"summary": "Build demo for showing a Go Api App",
"author": "Wade Wegner"
}

6
error.go Normal file
Просмотреть файл

@ -0,0 +1,6 @@
package main
type jsonErr struct {
Code int `json:"code"`
Text string `json:"text"`
}

79
handlers.go Normal file
Просмотреть файл

@ -0,0 +1,79 @@
package main
import (
"encoding/json"
"fmt"
"io"
"io/ioutil"
"net/http"
"strconv"
"github.com/gorilla/mux"
)
func Index(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, "Welcome!\n")
}
func TodoIndex(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.WriteHeader(http.StatusOK)
if err := json.NewEncoder(w).Encode(todos); err != nil {
panic(err)
}
}
func TodoShow(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
var todoId int
var err error
if todoId, err = strconv.Atoi(vars["todoId"]); err != nil {
panic(err)
}
todo := RepoFindTodo(todoId)
if todo.Id > 0 {
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.WriteHeader(http.StatusOK)
if err := json.NewEncoder(w).Encode(todo); err != nil {
panic(err)
}
return
}
// If we didn't find it, 404
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.WriteHeader(http.StatusNotFound)
if err := json.NewEncoder(w).Encode(jsonErr{Code: http.StatusNotFound, Text: "Not Found"}); err != nil {
panic(err)
}
}
/*
Test with this curl command:
curl -H "Content-Type: application/json" -d '{"name":"New Todo"}' http://localhost:8080/todos
*/
func TodoCreate(w http.ResponseWriter, r *http.Request) {
var todo Todo
body, err := ioutil.ReadAll(io.LimitReader(r.Body, 1048576))
if err != nil {
panic(err)
}
if err := r.Body.Close(); err != nil {
panic(err)
}
if err := json.Unmarshal(body, &todo); err != nil {
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.WriteHeader(422) // unprocessable entity
if err := json.NewEncoder(w).Encode(err); err != nil {
panic(err)
}
}
t := RepoCreateTodo(todo)
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.WriteHeader(http.StatusCreated)
if err := json.NewEncoder(w).Encode(t); err != nil {
panic(err)
}
}

23
logger.go Normal file
Просмотреть файл

@ -0,0 +1,23 @@
package main
import (
"log"
"net/http"
"time"
)
func Logger(inner http.Handler, name string) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
start := time.Now()
inner.ServeHTTP(w, r)
log.Printf(
"%s\t%s\t%s\t%s",
r.Method,
r.RequestURI,
name,
time.Since(start),
)
})
}

19
main.go Normal file
Просмотреть файл

@ -0,0 +1,19 @@
package main
import (
"log"
"net/http"
"os"
)
func main() {
router := NewRouter()
port := "8080"
if os.Getenv("HTTP_PLATFORM_PORT") != "" {
port = os.Getenv("HTTP_PLATFORM_PORT")
}
log.Fatal(http.ListenAndServe(":" + port, router))
}

Просмотреть файл

@ -0,0 +1,80 @@
{
"swagger": "2.0",
"info": {
"title": "Go Todo Api App Demo",
"description": "Build demo for showing a Go Api App",
"version": "1.0.0"
},
"host": "azurewebsites.net",
"schemes": [
"https"
],
"basePath": "/v1",
"produces": [
"application/json"
],
"paths": {
"/todos": {
"get": {
"summary": "Todo Index",
"description": "Get a list of todo items\n",
"tags": [
"Todos"
],
"responses": {
"200": {
"description": "An array of todos",
"schema": {
"type": "array",
"items": {
"$ref": "#/definitions/Todo"
}
}
},
"default": {
"description": "Unexpected error",
"schema": {
"$ref": "#/definitions/Error"
}
}
}
}
}
},
"definitions": {
"Todo": {
"properties": {
"Id": {
"type": "number",
"description": "Unique id for todo"
},
"Name": {
"type": "string",
"description": "Name of the todo item"
},
"Completed": {
"type": "boolean",
"description": "Is the todo item complete?."
},
"Due": {
"type": "string",
"description": "Time the todo item is due."
}
}
},
"Error": {
"properties": {
"code": {
"type": "integer",
"format": "int32"
},
"message": {
"type": "string"
},
"fields": {
"type": "string"
}
}
}
}
}

41
repo.go Normal file
Просмотреть файл

@ -0,0 +1,41 @@
package main
import "fmt"
var currentId int
var todos Todos
// Give us some seed data
func init() {
RepoCreateTodo(Todo{Name: "Write presentation"})
RepoCreateTodo(Todo{Name: "Host meetup"})
}
func RepoFindTodo(id int) Todo {
for _, t := range todos {
if t.Id == id {
return t
}
}
// return empty Todo if not found
return Todo{}
}
//this is bad, I don't think it passes race condtions
func RepoCreateTodo(t Todo) Todo {
currentId += 1
t.Id = currentId
todos = append(todos, t)
return t
}
func RepoDestroyTodo(id int) error {
for i, t := range todos {
if t.Id == id {
todos = append(todos[:i], todos[i+1:]...)
return nil
}
}
return fmt.Errorf("Could not find Todo with id of %d to delete", id)
}

31
router.go Normal file
Просмотреть файл

@ -0,0 +1,31 @@
package main
import (
"net/http"
"github.com/gorilla/mux"
)
func NewRouter() *mux.Router {
router := mux.NewRouter().StrictSlash(true)
for _, route := range routes {
var handler http.Handler
handler = route.HandlerFunc
handler = Logger(handler, route.Name)
router.
Methods(route.Method).
Path(route.Pattern).
Name(route.Name).
Handler(handler)
}
// route static content
router.PathPrefix("/").Handler(http.FileServer(http.Dir("./")))
router.PathPrefix("/metadata").Handler(http.FileServer(http.Dir("./")))
return router
}

39
routes.go Normal file
Просмотреть файл

@ -0,0 +1,39 @@
package main
import "net/http"
type Route struct {
Name string
Method string
Pattern string
HandlerFunc http.HandlerFunc
}
type Routes []Route
var routes = Routes{
Route{
"Index",
"GET",
"/",
Index,
},
Route{
"TodoIndex",
"GET",
"/todos",
TodoIndex,
},
Route{
"TodoCreate",
"POST",
"/todos",
TodoCreate,
},
Route{
"TodoShow",
"GET",
"/todos/{todoId}",
TodoShow,
},
}

12
todo.go Normal file
Просмотреть файл

@ -0,0 +1,12 @@
package main
import "time"
type Todo struct {
Id int `json:"id"`
Name string `json:"name"`
Completed bool `json:"completed"`
Due time.Time `json:"due"`
}
type Todos []Todo