Initial working prototype
This commit is contained in:
Коммит
35568f0977
|
@ -0,0 +1,2 @@
|
|||
[config]
|
||||
command = GoDeploy.cmd
|
|
@ -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,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>
|
|
@ -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"
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
package main
|
||||
|
||||
type jsonErr struct {
|
||||
Code int `json:"code"`
|
||||
Text string `json:"text"`
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
}
|
|
@ -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),
|
||||
)
|
||||
})
|
||||
}
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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,
|
||||
},
|
||||
}
|
|
@ -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
|
Загрузка…
Ссылка в новой задаче