55
loading...
This website collects cookies to deliver better user experience
$ git clone https://github.com/scraly/learning-go-by-examples.git
$ cd learning-go-by-examples
go-rest-api
for our first application and go into it:$ mkdir go-rest-api
$ cd go-rest-api
$ go mod init github.com/scraly/learning-go-by-examples/go-rest-api
go: creating new go.mod: module github.com/scraly/learning-go-by-examples/go-rest-api
go.mod
file like this:module github.com/scraly/learning-go-by-examples/go-rest-api
go 1.16
.
├── README.md
├── bin
├── doc
├── go.mod
├── internal
├── pkg
└── swagger
main.go
file in the internal/
folder:package main
import (
"fmt"
"html"
"log"
"net/http"
)
func main() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello, %q", html.EscapeString(r.URL.Path))
})
log.Println("Listening on localhost:8080")
log.Fatal(http.ListenAndServe(":8080", nil))
}
$ go run internal/main.go
2021/07/12 22:10:47 Listening on localhost:8080
$ curl localhost:8080
Hello, "/"%
.go
file and then run go run myfile.go
in order to test it, awesome!$ go build -o bin/go-rest-api internal/main.go
Taskfile.yml
file with this content:version: "3"
tasks:
build:
desc: Build the app
cmds:
- GOFLAGS=-mod=mod go build -o bin/go-rest-api internal/main.go
run:
desc: Run the app
cmds:
- GOFLAGS=-mod=mod go run internal/main.go
swagger.gen:
desc: Generate Go code
cmds:
- GOFLAGS=-mod=mod go generate github.com/scraly/learning-go-by-examples/go-rest-api/internal github.com/scraly/learning-go-by-examples/go-rest-api/pkg/swagger
swagger.validate:
desc: Validate swagger
cmds:
- swagger validate pkg/swagger/swagger.yml
swagger.doc:
desc: Doc for swagger
cmds:
- docker run -i yousan/swagger-yaml-to-html < pkg/swagger/swagger.yml > doc/index.html
task
in your local machine, in order to do that you can follow installation instructions or if you have a MacOS with homebrew, you can use brew install
command:$ brew install go-task/tap/go-task
$ task --list
task: Available tasks for this project:
* build: Build the app
* run: Run the app
* swagger.doc: Doc for swagger
* swagger.gen: generate Go code
* swagger.validate: Validate swagger
go-swagger
tool, don't hesitate to follow installation page.$ brew tap go-swagger/go-swagger
$ brew install go-swagger
$ swagger version
version: v0.27.0
commit: 43c2774170504d87b104e3e4d68626aac2cd447d
pkg/swagger/swagger.yml
:consumes:
- application/json
info:
description: HTTP server in Go with Swagger endpoints definition.
title: go-rest-api
version: 0.1.0
produces:
- application/json
schemes:
- http
swagger: "2.0"
paths:
/healthz:
get:
operationId: checkHealth
produces:
- text/plain
responses:
'200':
description: OK message.
schema:
type: string
enum:
- OK
/hello/{user}:
get:
description: Returns a greeting to the user!
parameters:
- name: user
in: path
type: string
required: true
description: The name of the user to greet.
responses:
200:
description: Returns the greeting.
schema:
type: string
400:
description: Invalid characters in "user" were provided.
/gopher/{name}:
get:
description: Return the Gopher Image.
produces:
- image/png
parameters:
- name: name
in: path
type: string
required: true
description: The name of the Gopher to display.
responses:
200:
description: Returns the Gopher.
schema:
type: file
$ task swagger.validate
task: [swagger.validate] swagger validate pkg/swagger/swagger.yml
2021/07/12 22:39:47
The swagger spec at "pkg/swagger/swagger.yml" is valid against swagger specification 2.0
$ task swagger.doc
task: [swagger.doc] docker run -i yousan/swagger-yaml-to-html < pkg/swagger/swagger.yml > doc/index.html
pkg/swagger/
and now create a gen.go
file with this content:package swagger
//go:generate rm -rf server
//go:generate mkdir -p server
//go:generate swagger generate server --quiet --target server --name hello-api --spec swagger.yml --exclude-main
$ task swagger.gen
task: [swagger.gen] GOFLAGS=-mod=mod go generate github.com/scraly/learning-go-by-examples/go-rest-api/internal github.com/scraly/learning-go-by-examples/go-rest-api/pkg/swagger
pkg/swagger
├── gen.go
├── server
│ └── restapi
│ ├── configure_hello_api.go
│ ├── doc.go
│ ├── embedded_spec.go
│ ├── operations
│ │ ├── check_health.go
│ │ ├── check_health_parameters.go
│ │ ├── check_health_responses.go
│ │ ├── check_health_urlbuilder.go
│ │ ├── get_gopher_name.go
│ │ ├── get_gopher_name_parameters.go
│ │ ├── get_gopher_name_responses.go
│ │ ├── get_gopher_name_urlbuilder.go
│ │ ├── get_hello_user.go
│ │ ├── get_hello_user_parameters.go
│ │ ├── get_hello_user_responses.go
│ │ ├── get_hello_user_urlbuilder.go
│ │ └── hello_api_api.go
│ └── server.go
└── swagger.yml
main.go
file with this new content:package main
import (
"fmt"
"log"
"net/http"
"github.com/go-openapi/loads"
"github.com/go-openapi/runtime/middleware"
"github.com/scraly/learning-go-by-examples/go-rest-api/pkg/swagger/server/restapi"
"github.com/scraly/learning-go-by-examples/go-rest-api/pkg/swagger/server/restapi/operations"
)
func main() {
// Initialize Swagger
swaggerSpec, err := loads.Analyzed(restapi.SwaggerJSON, "")
if err != nil {
log.Fatalln(err)
}
api := operations.NewHelloAPIAPI(swaggerSpec)
server := restapi.NewServer(api)
defer func() {
if err := server.Shutdown(); err != nil {
// error handle
log.Fatalln(err)
}
}()
server.Port = 8080
api.CheckHealthHandler = operations.CheckHealthHandlerFunc(Health)
api.GetHelloUserHandler = operations.GetHelloUserHandlerFunc(GetHelloUser)
api.GetGopherNameHandler = operations.GetGopherNameHandlerFunc(GetGopherByName)
// Start server which listening
if err := server.Serve(); err != nil {
log.Fatalln(err)
}
}
//Health route returns OK
func Health(operations.CheckHealthParams) middleware.Responder {
return operations.NewCheckHealthOK().WithPayload("OK")
}
//GetHelloUser returns Hello + your name
func GetHelloUser(user operations.GetHelloUserParams) middleware.Responder {
return operations.NewGetHelloUserOK().WithPayload("Hello " + user.User + "!")
}
//GetGopherByName returns a gopher in png
func GetGopherByName(gopher operations.GetGopherNameParams) middleware.Responder {
var URL string
if gopher.Name != "" {
URL = "https://github.com/scraly/gophers/raw/main/" + gopher.Name + ".png"
} else {
//by default we return dr who gopher
URL = "https://github.com/scraly/gophers/raw/main/dr-who.png"
}
response, err := http.Get(URL)
if err != nil {
fmt.Println("error")
}
return operations.NewGetGopherNameOK().WithPayload(response.Body)
}
go get <my-lib>
command with the dependancies you need or copy/paste the require dependencies block in your go.mod
file:module github.com/scraly/learning-go-by-examples/go-rest-api
go 1.16
require (
github.com/go-openapi/errors v0.20.0
github.com/go-openapi/loads v0.20.2
github.com/go-openapi/runtime v0.19.29
github.com/go-openapi/spec v0.20.1
github.com/go-openapi/strfmt v0.20.0
github.com/go-openapi/swag v0.19.13
github.com/jessevdk/go-flags v1.5.0
golang.org/x/net v0.0.0-20210119194325-5f4716e94777
)
main.go
file, we initialize a REST API swagger server and we define 3 handlers (and their implementation://Health route returns OK
func Health(operations.CheckHealthParams) middleware.Responder {
return operations.NewCheckHealthOK().WithPayload("OK")
}
/healthz
route, we'll send them a response with OK as string.//GetHelloUser returns Hello + user name
func GetHelloUser(user operations.GetHelloUserParams) middleware.Responder {
return operations.NewGetHelloUserOK().WithPayload("Hello " + user.User + "!")
}
/hello/{user}
route, we'll send them a response with "Hello" + {user} as string.//GetGopherByName returns a gopher in png
func GetGopherByName(gopher operations.GetGopherNameParams) middleware.Responder {
var URL string
if gopher.Name != "" {
URL = "https://github.com/scraly/gophers/raw/main/" + gopher.Name + ".png"
} else {
//by default we return dr who gopher
URL = "https://github.com/scraly/gophers/raw/main/dr-who.png"
}
response, err := http.Get(URL)
if err != nil {
fmt.Println("error")
}
return operations.NewGetGopherNameOK().WithPayload(response.Body)
}
/gopher/{name}
route, they get a cute gopher image and then send the image back to the user. If name is empty, we will return our Doctor Who gopher by default.$ go build -o bin/go-rest-api internal/main.go
bin/
folder.$ task build
task: [build] GOFLAGS=-mod=mod go build -o bin/go-rest-api internal/main.go
$ ./bin/go-rest-api
2021/07/13 20:21:34 Serving hello API at http://[::]:8080
go build
command.# Windows 32 bits
$ GOOS=windows GOARCH=386 go build -o bin/go-rest-api-win-386 internal/main.go
# Windows 64 bits
$ GOOS=windows GOARCH=amd64 go build -o bin/go-rest-api-win-64 internal/main.go
# Linux 32 bits
$ GOOS=linux GOARCH=386 go build -o bin/go-rest-api-linux-386 internal/main.go
# Linux 64 bits
$ GOOS=linux GOARCH=amd64 go build -o bin/go-rest-api-linux-64 internal/main.go
# MacOS 32 bits
$ GOOS=darwin GOARCH=386 go build -o bin/go-rest-api-darwin-386 internal/main.go
# MacOS 64 bits
$ GOOS=darwin GOARCH=amd64 go build -o bin/go-rest-api-darwin-64 internal/main.go
# MacOS 64 bits for M1 chip
$ GOOS=darwin GOARCH=arm64 go build -o bin/go-rest-api-darwin-arm64 internal/main.go
curl
command:$ curl localhost:8080
{"code":404,"message":"path / was not found"}%
$ curl localhost:8080/healthz
OK
$ curl localhost:8080/hello/aurelie
"Hello aurelie!"
$ curl -O localhost:8080/gopher/dr-who
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 992k 0 992k 0 0 955k 0 --:--:-- 0:00:01 --:--:-- 955k
$ file dr-who
dr-who: PNG image data, 1700 x 1460, 8-bit/color RGBA, non-interlaced
localhost:8080/gopher/dr-who
in your browser to display our little Gopher :-).