endpoints/getting-started/app.go (86 lines of code) (raw):
// Copyright 2019 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Sample endpoints demonstrates a Cloud Endpoints API.
package main
import (
"encoding/base64"
"encoding/json"
"fmt"
"log"
"net/http"
"os"
"github.com/gorilla/mux"
)
func main() {
r := mux.NewRouter()
r.Path("/echo").Methods("POST").
HandlerFunc(echoHandler)
r.Path("/auth/info/googlejwt").Methods("GET").
HandlerFunc(authInfoHandler)
r.Path("/auth/info/googleidtoken").Methods("GET").
HandlerFunc(authInfoHandler)
r.Path("/auth/info/firebase").Methods("GET", "OPTIONS").
Handler(corsHandler(authInfoHandler))
r.Path("/auth/info/auth0").Methods("GET").
HandlerFunc(authInfoHandler)
http.Handle("/", r)
port := os.Getenv("PORT")
if port == "" {
port = "8080"
log.Printf("Defaulting to port %s", port)
}
log.Printf("Listening on port %s", port)
if err := http.ListenAndServe(":"+port, nil); err != nil {
log.Fatal(err)
}
}
// echoHandler reads a JSON object from the body, and writes it back out.
func echoHandler(w http.ResponseWriter, r *http.Request) {
var msg interface{}
if err := json.NewDecoder(r.Body).Decode(&msg); err != nil {
if _, ok := err.(*json.SyntaxError); ok {
errorf(w, http.StatusBadRequest, "Body was not valid JSON: %v", err)
return
}
errorf(w, http.StatusInternalServerError, "Could not get body: %v", err)
return
}
b, err := json.Marshal(msg)
if err != nil {
errorf(w, http.StatusInternalServerError, "Could not marshal JSON: %v", err)
return
}
w.Write(b)
}
// corsHandler wraps a HTTP handler and applies the appropriate responses for Cross-Origin Resource Sharing.
type corsHandler http.HandlerFunc
func (h corsHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Access-Control-Allow-Origin", "*")
if r.Method == "OPTIONS" {
w.Header().Set("Access-Control-Allow-Headers", "Authorization")
return
}
h(w, r)
}
// [START endpoints_auth_info_backend]
// authInfoHandler reads authentication info provided by the Endpoints proxy.
func authInfoHandler(w http.ResponseWriter, r *http.Request) {
encodedInfo := r.Header.Get("X-Endpoint-API-UserInfo")
if encodedInfo == "" {
w.Write([]byte(`{"id": "anonymous"}`))
return
}
b, err := base64.StdEncoding.DecodeString(encodedInfo)
if err != nil {
errorf(w, http.StatusInternalServerError, "Could not decode auth info: %v", err)
return
}
w.Write(b)
}
// [END endpoints_auth_info_backend]
// errorf writes a swagger-compliant error response.
func errorf(w http.ResponseWriter, code int, format string, a ...interface{}) {
var out struct {
Code int `json:"code"`
Message string `json:"message"`
}
out.Code = code
out.Message = fmt.Sprintf(format, a...)
b, err := json.Marshal(out)
if err != nil {
http.Error(w, `{"code": 500, "message": "Could not format JSON for original message."}`, 500)
return
}
http.Error(w, string(b), code)
}