├── .idea
├── dictionaries
│ └── florin.xml
├── gopherconuk.iml
├── inspectionProfiles
│ └── Project_Default.xml
├── modules.xml
├── runConfigurations
│ ├── DB.xml
│ └── gcuk.xml
├── sqldialects.xml
└── vcs.xml
├── Dockerfile
├── Dockerfile.db
├── LICENSE
├── README.md
├── certs
├── docker.localhost.cert
├── docker.localhost.key
├── local.localhost.cert
└── local.localhost.key
├── go.mod
├── go.sum
├── homepage
├── home.go
└── home_test.go
├── main.go
├── requests.http
└── server
└── server.go
/.idea/dictionaries/florin.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | gcuk
5 | gopherconuk
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.idea/gopherconuk.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/.idea/inspectionProfiles/Project_Default.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.idea/runConfigurations/DB.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/.idea/runConfigurations/gcuk.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/.idea/sqldialects.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM golang:1.11beta2-alpine3.8 AS build-env
2 |
3 | # Allow Go to retrive the dependencies for the build step
4 | RUN apk add --no-cache git
5 |
6 | # Secure against running as root
7 | RUN adduser -D -u 10000 florin
8 | RUN mkdir /gopherconuk/ && chown florin /gopherconuk/
9 | USER florin
10 |
11 | WORKDIR /gopherconuk/
12 | ADD . /gopherconuk/
13 |
14 | # Compile the binary, we don't want to run the cgo resolver
15 | RUN CGO_ENABLED=0 go build -o /gopherconuk/gcuk .
16 |
17 | # final stage
18 | FROM alpine:3.8
19 |
20 | # Secure against running as root
21 | RUN adduser -D -u 10000 florin
22 | USER florin
23 |
24 | WORKDIR /
25 | COPY --from=build-env /gopherconuk/certs/docker.localhost.* /
26 | COPY --from=build-env /gopherconuk/gcuk /
27 |
28 | EXPOSE 8080
29 |
30 | CMD ["/gcuk"]
31 |
--------------------------------------------------------------------------------
/Dockerfile.db:
--------------------------------------------------------------------------------
1 | FROM postgres:10.4-alpine
2 |
3 | ENV POSTGRES_USER postgres
4 | ENV POSTGRES_PASSWORD postgres
5 | ENV POSTGRES_DB gcuk
6 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 Florin Pățan
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Go micro-service in ~30 minutes
2 |
3 | This is a Go micro-service written from scratch.
4 |
5 | It shows how to use [net/http](https://godoc.org/net/http), and how to structure a Go project.
6 |
7 | It relies on Go 1.11 Beta 2 and the upcoming "Go modules" (formerly known as "vgo") support.
8 |
9 | Dependency injection is used to insert a logger instance into the handler.
10 |
11 | You can also notice how the test is constructed in order to provide testing for the handler.
12 |
13 | A Docker container is available, thanks to the Dockerfile. It shows how to construct such containers.
14 |
15 | ## How to use
16 |
17 | Because this project uses go modules, as long as you are using Go 1.11 Beta 2+ or Go 1.10 with vgo support,
18 | you should be ok.
19 |
20 | Clone this anywhere in your computer and create a project in your editor. I'm using [GoLand IDE](https://jetbrains.com/go) in order to work
21 | on the project during the presentation as well as have support for go modules.
22 |
23 | The bundled, self-signed, certificates are bound to either ` dev.localhost:8080 ` or ` docker.localhost:8080 `. I obviously
24 | do not recommend using these in production.
25 |
26 | ## Presentation link
27 |
28 | I created this as part of the presentation at [GopherCon UK 18](https://www.gophercon.co.uk/).
29 |
30 | The link for the video will be updated here when the presentation is out.
31 |
32 | ## References
33 |
34 | ### Structuring Go applications
35 |
36 | In order to learn how to approach package design in Go, you can read the following resources:
37 |
38 | - [Style guideline for Go packages - JBD](https://rakyll.org/style-packages/)
39 | - [Standard Package Layout - Ben Johnson](https://medium.com/@benbjohnson/standard-package-layout-7cdbc8391fc1#.ds38va3pp)
40 | - [Go best practices, six years in - Peter Bourgon](https://peter.bourgon.org/go-best-practices-2016/#repository-structure)
41 |
42 | Once done, this article will help you understand the [Design Philosophy On Packaging by William Kennedy](https://www.ardanlabs.com/blog/2017/02/design-philosophy-on-packaging.html).
43 |
44 | ### Exposing Go applications to the Internet
45 |
46 | [This article](https://blog.cloudflare.com/exposing-go-on-the-internet/) describes how you can start approaching
47 |
48 | ## Thank you
49 |
50 | I would like to thank you [William "Bill" Kennedy](https://twitter.com/goinggodotnet) for the inspiration he provided on
51 | getting me to do this talk.
52 |
53 |
54 | ## License
55 |
56 | This project is under the MIT license. Please see the [LICENSE](LICENSE) file for more details.
57 |
--------------------------------------------------------------------------------
/certs/docker.localhost.cert:
--------------------------------------------------------------------------------
1 | -----BEGIN CERTIFICATE-----
2 | MIIDCTCCAfGgAwIBAgIJALznbLlRwEspMA0GCSqGSIb3DQEBBQUAMBsxGTAXBgNV
3 | BAMMEGRvY2tlci5sb2NhbGhvc3QwHhcNMTgwODAyMjI0NDE2WhcNMjgwNzMwMjI0
4 | NDE2WjAbMRkwFwYDVQQDDBBkb2NrZXIubG9jYWxob3N0MIIBIjANBgkqhkiG9w0B
5 | AQEFAAOCAQ8AMIIBCgKCAQEAr6YgpwNNs37fjXw1bpKqfdkrSCTi7z3ecxKzzxHQ
6 | x/IqRUuWEhoJ6s64vFJkPM3YnkzQI8FlFLFUPUISuOrJBdFyyq/QrEHDhj8FElmk
7 | jLaNk62p8J3BE7imNtjoUHT7Ly7XPEoWFaP+FpsIX6i8JilJykyjEpmLjTe0sRxo
8 | OtUPATzg5RWZhy85GBqmQLgYxlkIV5Kc58NLWax1Onsl7r9WL/BNyDOtoAQKy9Z7
9 | oG5hwAzNzK9DdMvQnxeoHyqo4otF8t0UBqDzWCrJ66GtOFQcu5wBuypciYU7UeHf
10 | nT6XyCPWFYPLnkOfwEuSdXcu6gI9xvg6kJ9ODU9UnsCOZQIDAQABo1AwTjAdBgNV
11 | HQ4EFgQUCTKuk7Kbc89VJOMvZ4HAXHg9mqEwHwYDVR0jBBgwFoAUCTKuk7Kbc89V
12 | JOMvZ4HAXHg9mqEwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAW+pY
13 | WTax46RFSWTPOmn6G748NXWiRdsbcWc6Q6NHR1E6le48GqfOAEN5Pub7JQAUMXfC
14 | ufn0yNr/cCeKgXNVBsE6hr+dw2snzh1Q3NIseXM4imGbQvTM9W8RRclULViSUta/
15 | D/b0JtcdWyACAVwvw6nQPcW5rGA9y+ZTSiI+EwckYVhBhqDcSmMrnCcbtsLjjUB3
16 | DazSfZXfT/RjZw5vcoCDVRo/hidWNQ5/2fGysW7anSWo18HUIvdy9sMOiTAXchVa
17 | SKIZvplfjPJBHpNVuqMSranN5Khd49rx1li8ZAnpLOVc5+tWOwSKzbW/C/4mZFAo
18 | f5arbOZ7NQWbJzZn7w==
19 | -----END CERTIFICATE-----
20 |
--------------------------------------------------------------------------------
/certs/docker.localhost.key:
--------------------------------------------------------------------------------
1 | -----BEGIN RSA PRIVATE KEY-----
2 | MIIEowIBAAKCAQEAr6YgpwNNs37fjXw1bpKqfdkrSCTi7z3ecxKzzxHQx/IqRUuW
3 | EhoJ6s64vFJkPM3YnkzQI8FlFLFUPUISuOrJBdFyyq/QrEHDhj8FElmkjLaNk62p
4 | 8J3BE7imNtjoUHT7Ly7XPEoWFaP+FpsIX6i8JilJykyjEpmLjTe0sRxoOtUPATzg
5 | 5RWZhy85GBqmQLgYxlkIV5Kc58NLWax1Onsl7r9WL/BNyDOtoAQKy9Z7oG5hwAzN
6 | zK9DdMvQnxeoHyqo4otF8t0UBqDzWCrJ66GtOFQcu5wBuypciYU7UeHfnT6XyCPW
7 | FYPLnkOfwEuSdXcu6gI9xvg6kJ9ODU9UnsCOZQIDAQABAoIBAQCXnQUIREC4k+Xx
8 | IWqZk/2X/XFvp28+5J9zoowUS6N0QyKbh7/0xgcTZ/Zrj464MVIuac0rX86ZSuuU
9 | qMiyVu7Hl9/G9nVfirBz20fMbBYt45FXDIroh7LWDAdkxlvYvvDl7D+a6bQgX9p9
10 | trpGn8YwBmmMNhR4hJLBhXjxe7y4Mis6D90RDkE+6ZXFe9gbpdppaAZ/VVHVzrXq
11 | 0yBolGS0e+64bZ8bjokDhyuRyVpjQTQeO9bTxvSCn2rrQ9WbrQW1HxFrY7WLdioX
12 | sqNVF1J4PE2Ox1eTmirE3iTE34nI99rGitOOudx7R++kSbkDB2JyEttnDTRHnA+3
13 | vPIRJcAtAoGBAODZmfQYGeItplNJgyxwZBCG7ut7X23g62EgGMwPxpIBFeWgO7q0
14 | uzchEauK4qWlFulr7k2vGo7NBBP3wsgBQyx81Vnw5V1XXktC5sdBShymMWMt/S8G
15 | 3+2whNTNzf9n9bSavBIWm+b5mezDPVft+IprARjt9V0zBJXEwrJ1XKcvAoGBAMf7
16 | lv/3Yp+eF22Va0AgLOepz3Ab0KHdKDTn62BhgBl3PwOKrRGjb4k+mT4zNq0JjtZR
17 | 9MezZ+S2iJPMoaL8Gc/Kpa/KPsbpfsGrqmOzhW6feSFOyPeJgPn9zYpkwpmvkYWh
18 | S3aH+aZpxE8kfkJdK8HBbXennPowZeys5xR0uL6rAoGAJF0s19w5+2lUl+2wqDQ5
19 | Cq833p+iTFvu1VNij0YR4DUKvItQfZ6TFJRlji+0/gMYFIIfFTM3gVbIzQ3p03zY
20 | x04dFyGtho4FsvhL6He3q7B5FkguxTdAael9YgkywpamlyHbPrWnWxCNA0yEFD9p
21 | TcGGeOirIPqKSEp9Dm2KoYMCgYBp7ZAMQWOSHNFYEF9g9ioTA9WHEpSuSFD1xSre
22 | QIbz9kAAhkIqJ6H61pehZMs/WOK6D2tTJGqRsUYi06+Cf3rEoBinRr996UxlFaMJ
23 | cJvq/rnQtMSqqcERqihnd/vEIEU6vTcVr+zDAx8itLfUOznkRarQSI5Tz7MNbIBy
24 | S2lYRQKBgDeo2Gv1UEJH59mjz5jIOlRxo03+c+DPl6088BcErN9/CTU+WlqxLhLa
25 | u02RO3KCe3GO2KZS9E5LZzanLDdfynj2HFjf0MRGxcHtv0/Odr8UEg3lfah6GL2Y
26 | dEGAfQNZuqaIf3NX7/oK1wyaajZNfCN6vKbJbCnfqx6hDuiTIw6X
27 | -----END RSA PRIVATE KEY-----
28 |
--------------------------------------------------------------------------------
/certs/local.localhost.cert:
--------------------------------------------------------------------------------
1 | -----BEGIN CERTIFICATE-----
2 | MIIDBzCCAe+gAwIBAgIJAM3zCUrPG4X1MA0GCSqGSIb3DQEBBQUAMBoxGDAWBgNV
3 | BAMMD2xvY2FsLmxvY2FsaG9zdDAeFw0xODA4MDIyMjQzMjhaFw0yODA3MzAyMjQz
4 | MjhaMBoxGDAWBgNVBAMMD2xvY2FsLmxvY2FsaG9zdDCCASIwDQYJKoZIhvcNAQEB
5 | BQADggEPADCCAQoCggEBALPCrtIsm4iIK2sv5NO13LZ1qqlo32qEMLisCm3b3k4N
6 | jEulO7QqA2ke861H6OxWL3IEci7U7Vtt0rSYqniRPhTV17sq3IQUN+vrzM2EOJGG
7 | +rD8cpJqgUOEb3MUieql0OHXRRNFox9OFVRPGfn5E/CcotVoT6ym6qU3qUGYjfGu
8 | MKMDEXyV63EkwrUUH6ry/8Ykfe49WldZMikrxbm0s7Q7PvGh7Ke4MFRVI+nilZ0T
9 | OqncawcGn1mDR3880rWxZMwVyL44lX7axLOcZCreQE/RSGG+XfueIB06tP3tfFFh
10 | Wuz0hgLoACgfQQHNa0bcVG0XvqkxzQqsN0U8yHE7G3cCAwEAAaNQME4wHQYDVR0O
11 | BBYEFMfDqZEHnd3wQyPLg+S3pSxD6xkrMB8GA1UdIwQYMBaAFMfDqZEHnd3wQyPL
12 | g+S3pSxD6xkrMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAKeqdY6O
13 | +hY8Igx/LQ44XUDNqnCJuyqg8JDibadbsqsaxZtWt56n8XfTw47R4SfeqD7TwhLu
14 | PlX7uQhh+fd8btBVmsmOX79ENtvRVJArmJzc77ATdBwA13rMiCD8UEudf6T9Vef8
15 | o0H0vgWXju2ovdrMFTK7SONcZgybTDr9n/JPMrghsoGm1kHL3D2r41SGVeM2705R
16 | JKJ6VwAcLBydWe2uZTskeR0O0POEzQzTJfodmIt9l2G9mObCQygal6SsPTBARVOk
17 | BcYix2JW2q3XsV1bT9DbVk3jNGdcNhhulPaH/jfmOgkn68TF53Rriw+fsHU1o3b1
18 | InheFMfx+4NP5Sc=
19 | -----END CERTIFICATE-----
20 |
--------------------------------------------------------------------------------
/certs/local.localhost.key:
--------------------------------------------------------------------------------
1 | -----BEGIN RSA PRIVATE KEY-----
2 | MIIEowIBAAKCAQEAs8Ku0iybiIgray/k07XctnWqqWjfaoQwuKwKbdveTg2MS6U7
3 | tCoDaR7zrUfo7FYvcgRyLtTtW23StJiqeJE+FNXXuyrchBQ36+vMzYQ4kYb6sPxy
4 | kmqBQ4RvcxSJ6qXQ4ddFE0WjH04VVE8Z+fkT8Jyi1WhPrKbqpTepQZiN8a4wowMR
5 | fJXrcSTCtRQfqvL/xiR97j1aV1kyKSvFubSztDs+8aHsp7gwVFUj6eKVnRM6qdxr
6 | BwafWYNHfzzStbFkzBXIvjiVftrEs5xkKt5AT9FIYb5d+54gHTq0/e18UWFa7PSG
7 | AugAKB9BAc1rRtxUbRe+qTHNCqw3RTzIcTsbdwIDAQABAoIBADoCYGIozQRRVRmg
8 | +gosDQ7AiBNlaXu5LvPZaQAszN+JVbXvm4W3bSRWPbK0mwDxixwTPTnJstMnbLCk
9 | 95Yy4MLeg2C+Iy1oTOeQT6YevhaQZYQJ43tGbXJ5YXHUtfEIE5Fd48elWE+45f8w
10 | C6T0cS/bjFyr7dI8h0pL3Q3zChNsZYSO7yUhk3t5h9uVcl/3so64ctTBs/wpw3n+
11 | fxEaHUOOzbFI6J6KYVD0AM41kza6NY6MBySEVgdfbDsNDfFxu2/KAC2oV9vjZyJ0
12 | hWtkEVyV5mNVnC4Z61NdXdZRGG1Z9fFIZi9zeb5iWH2lValT7AQpUZEuw9ch0omP
13 | NQ6qeWECgYEA2TR0xejHdayZwWYq1BndRzQNLAekpUfXMXEuRsm2jLcclrBs/dbJ
14 | sfUKD1I5Z3A0W+94z1AUOuSKj3WzLqB8Ta1IGjDEJ58Y36ubVgoTVTCHE/xeGr74
15 | pSxkJarb9Zj1dNVyfzRDppmvlVxkEsexe79wy8nx9mxnsWIDoNaegNECgYEA094b
16 | NVcnXF8nn1URoNB5yIT7U9Kqd8O5WW+qZaflSPhl7RF4mUR+gPJMt6zNj8h1N7xw
17 | lpBHa6mlMJ4R1Gwrstbu5bFveN/TrQ+08WrFH5NbjQXiB5z5OgtsbKL1pwjEXiFO
18 | +dIev8TuFIts0OSiEoyjjPUbMo3JCTSnaHALqccCgYBwgveqPPZ1Qj8zK1UsIWm6
19 | JIBeOmdTJm+WMOajzIE/SusIM8OBie1YvXHElfceWcUFinquCPExwIj13yY+FOvO
20 | 4N/kkTZKv+MGmcIRQ47YJhcShzvH5vytstz9lg/ynJUpPBffRJd2iU2mtQExqTeK
21 | vpQTPDyWRXlBLWBrxEC+wQKBgQC4r6+WIuAb5JLckMJqJfFTO6D+o/CXsBUdgnrO
22 | XLpBjs8DBizTpmKEMzNvFYKnqP2NVYXrqd+oWVy3ccNnIdhB8JyVu8PJYYvbG4sG
23 | u6UUblbrKsqrCkozMAwW80MilUDgMTbwDRti3d8QJ632tqcVdmWHlY5c1j39+VlJ
24 | cAqqtwKBgCQtB98sm7y2n6tU8TAm+miPBWUhbjVeBhlgOu8FoAI1ve+nhPOOPsc+
25 | P/ee+Ru0x7XyyR4omG1D5kZqTIzw2aHzxMU40dQbCSe1EGbmEAxz47DuIn0iRU92
26 | kg4/DS7+n6VyGiYkg1YxpTqF4BLAlsMExNCcwTLEhHj743woVtlz
27 | -----END RSA PRIVATE KEY-----
28 |
--------------------------------------------------------------------------------
/go.mod:
--------------------------------------------------------------------------------
1 | module gopherconuk
2 |
--------------------------------------------------------------------------------
/go.sum:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dlsniper/gopherconuk/fc9bbccfa90017929aee4126d618cbc3d84b30af/go.sum
--------------------------------------------------------------------------------
/homepage/home.go:
--------------------------------------------------------------------------------
1 | package homepage
2 |
3 | import (
4 | "log"
5 | "net/http"
6 | "time"
7 | )
8 |
9 | const message = "Hello GopherCon UK 2018!"
10 |
11 | type Handlers struct {
12 | logger *log.Logger
13 | }
14 |
15 | func (h *Handlers) Home(w http.ResponseWriter, r *http.Request) {
16 | w.Header().Set("Content-Type", "text/plain; charset=utf-8")
17 | w.WriteHeader(http.StatusOK)
18 | w.Write([]byte(message))
19 | }
20 |
21 | func (h *Handlers) Logger(next http.HandlerFunc) http.HandlerFunc {
22 | return func(w http.ResponseWriter, r *http.Request) {
23 | startTime := time.Now()
24 | defer h.logger.Printf("request processed in %s\n", time.Now().Sub(startTime))
25 | next(w, r)
26 | }
27 | }
28 | func (h *Handlers) SetupRoutes(mux *http.ServeMux) {
29 | mux.HandleFunc("/", h.Logger(h.Home))
30 | }
31 |
32 | func NewHandlers(logger *log.Logger) *Handlers {
33 | return &Handlers{
34 | logger: logger,
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/homepage/home_test.go:
--------------------------------------------------------------------------------
1 | package homepage
2 |
3 | import (
4 | "net/http"
5 | "net/http/httptest"
6 | "testing"
7 | )
8 |
9 | func TestHandlers_Handler(t *testing.T) {
10 | tests := []struct {
11 | name string
12 | in *http.Request
13 | out *httptest.ResponseRecorder
14 | expectedStatus int
15 | expectedBody string
16 | }{
17 | {
18 | name: "good",
19 | in: httptest.NewRequest("GET", "/", nil),
20 | out: httptest.NewRecorder(),
21 | expectedStatus: http.StatusOK,
22 | expectedBody: message,
23 | },
24 | }
25 |
26 | for _, test := range tests {
27 | test := test
28 | t.Run(test.name, func(t *testing.T) {
29 | h := NewHandlers(nil)
30 | h.Home(test.out, test.in)
31 | if test.out.Code != test.expectedStatus {
32 | t.Logf("expected: %d\ngot: %d\n", test.expectedStatus, test.out.Code)
33 | t.Fail()
34 | }
35 |
36 | body := test.out.Body.String()
37 | if body != test.expectedBody {
38 | t.Logf("expected: %s\ngot: %s\n", test.expectedBody, body)
39 | t.Fail()
40 | }
41 | })
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "gopherconuk/homepage"
5 | "gopherconuk/server"
6 | "log"
7 | "net/http"
8 | "os"
9 | )
10 |
11 | var (
12 | GcukCertFile = os.Getenv("GCUK_CERT_FILE")
13 | GcukKeyFile = os.Getenv("GCUK_KEY_FILE")
14 | GcukServiceAddr = os.Getenv("GCUK_SERVICE_ADDR")
15 | )
16 |
17 | func main() {
18 | logger := log.New(os.Stdout, "gcuk ", log.LstdFlags|log.Lshortfile)
19 |
20 | h := homepage.NewHandlers(logger)
21 |
22 | mux := http.NewServeMux()
23 | h.SetupRoutes(mux)
24 |
25 | srv := server.New(mux, GcukServiceAddr)
26 |
27 | logger.Println("server starting")
28 | err := srv.ListenAndServeTLS(GcukCertFile, GcukKeyFile)
29 | if err != nil {
30 | logger.Fatalf("server failed to start: %v", err)
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/requests.http:
--------------------------------------------------------------------------------
1 | ### Local connection
2 | GET https://local.localhost:8080/
3 |
4 | ###
5 |
--------------------------------------------------------------------------------
/server/server.go:
--------------------------------------------------------------------------------
1 | package server
2 |
3 | import (
4 | "crypto/tls"
5 | "net/http"
6 | "time"
7 | )
8 |
9 | func New(mux *http.ServeMux, serverAddress string) *http.Server {
10 | // See https://blog.cloudflare.com/exposing-go-on-the-internet/ for details
11 | // about these settings
12 | tlsConfig := &tls.Config{
13 | // Causes servers to use Go's default cipher suite preferences,
14 | // which are tuned to avoid attacks. Does nothing on clients.
15 | PreferServerCipherSuites: true,
16 | // Only use curves which have assembly implementations
17 | CurvePreferences: []tls.CurveID{
18 | tls.CurveP256,
19 | tls.X25519, // Go 1.8 only
20 | },
21 |
22 | MinVersion: tls.VersionTLS12,
23 | CipherSuites: []uint16{
24 | tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
25 | tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
26 | tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
27 | tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
28 | tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
29 | tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
30 | },
31 | }
32 | srv := &http.Server{
33 | Addr: serverAddress,
34 | ReadTimeout: 5 * time.Second,
35 | WriteTimeout: 10 * time.Second,
36 | IdleTimeout: 120 * time.Second,
37 | TLSConfig: tlsConfig,
38 | Handler: mux,
39 | }
40 | return srv
41 | }
42 |
--------------------------------------------------------------------------------