├── LICENSE
├── Readme.md
└── assets
└── foods.xml
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 Debasish Sahoo
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.
22 |
--------------------------------------------------------------------------------
/Readme.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | A simple list of concepts and code snippets that would help in learning Golang and apply in Web Development :tada:. I tried to jot down when I was learning. It might be helpful for beginners who want to learn Go for web development.
5 |
6 |
7 |
8 | [](https://opensource.org/)
9 | [](https://github.com/debck/Learning-Go/blob/master/LICENSE)  
10 | [](http://hits.dwyl.com/debck/Learning-Go)
11 |
12 |
13 | > ✌️ Hope you find something useful. If you like it please give it a 🌟.
14 |
15 | ## Contents
16 | * [Installation](#Installation)
17 | * [Concepts to learn before diving into Web](#Initial-Concepts-to-Study-before-diving-deep)
18 | * [Basic Hello World](#Basic-Hello-World)
19 | * [Adding static assets](#Adding-static-asset)
20 | * [Creating Routes](#Adding-Routes)
21 | * [Adding Forms](#Adding-Forms)
22 | * [Adding MiddleWare](#Adding-MiddleWare)
23 | * [Sessions Management](#Sessions-Management)
24 | * [Adding Database](#Adding-Database)
25 | * [MongoDB](#MongoDB)
26 | * [Writing Unit Test](#Writing-Unit-Test)
27 | * [Parsing XML Data](#Parsing-XML-Data)
28 | * [File Uploading](#File-Uploading)
29 |
30 | ## Installation
31 |
32 | > Follow the [official doc](https://golang.org/doc/install) and setup Go depending on your OS (ie. Windows , Linux, OS X)
33 |
34 | ## Initial Concepts to Study before diving deep
35 |
36 | * Basic Understanding of
37 | * Variables
38 | * Constants
39 | * Packages and import/export
40 | * Functions
41 | * Pointers
42 | * Mutability
43 | * Types
44 | * Type Conversion
45 | * Type assertion**
46 | * Structs
47 | * Composition
48 | * Collection Types
49 | * Arrays
50 | * Slicing
51 | * Range & Maps
52 | * Control Flow
53 | * If, For, Switch statement
54 | * Methods
55 | * Interfaces
56 | * Concurrency
57 | * Goroutines
58 | * Channels
59 |
60 |
61 |
62 |
63 |
64 | ## Basic Hello World
65 |
66 | ```go
67 | package main
68 |
69 | import (
70 | "fmt"
71 | "net/http"
72 | )
73 |
74 | func main() {
75 | http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
76 | fmt.Fprintf(w, "Hello, World !")
77 | })
78 |
79 | http.ListenAndServe(":8000", nil)
80 | }
81 | ```
82 | [Go back to top ↑](#Contents)
83 |
84 | ## Adding static asset
85 |
86 | When we want to serve static files like CSS, JavaScript or images to Web.
87 |
88 | ```go
89 | func main() {
90 | http.HandleFunc("/", func (w http.ResponseWriter, r *http.Request) {
91 | fmt.Fprintf(w, "Hello World!")
92 | })
93 |
94 | fs := http.FileServer(http.Dir("./static"))
95 | http.Handle("/static/", http.StripPrefix("/static/", fs))
96 |
97 | http.ListenAndServe(":8000", nil)
98 | }
99 | ```
100 | [Go back to top ↑](#Contents)
101 |
102 | ## Adding Routes
103 |
104 | ```go
105 | package main
106 |
107 | import (
108 | "fmt"
109 | "encoding/json"
110 | "net/http"
111 | "github.com/gorilla/mux"
112 | )
113 |
114 |
115 | type Tasks struct {
116 | ID string `json:"id,omitempty"`
117 | TASKNAME string `json:"task,omitempty"`
118 | }
119 |
120 | var task []Tasks
121 |
122 | func getAllTask(w http.ResponseWriter, r *http.Request) {
123 | json.NewEncoder(w).Encode(task)
124 | }
125 |
126 |
127 | func getTask(w http.ResponseWriter, r *http.Request) {
128 | params := mux.Vars(r)
129 | for _,item := range task {
130 | if item.ID == params["id"] {
131 | json.NewEncoder(w).Encode(item)
132 | return
133 | }
134 | }
135 | json.NewEncoder(w).Encode(&Tasks{})
136 | }
137 |
138 |
139 | func main() {
140 | router := mux.NewRouter()
141 | router.HandleFunc("/task", getAllTask).Methods("GET")
142 | router.HandleFunc("/task/{id}", getTask).Methods("GET")
143 |
144 | http.ListenAndServe(":8000", router)
145 | }
146 |
147 | ```
148 |
149 | [Go back to top ↑](#Contents)
150 |
151 | ## Adding Forms
152 |
153 | Considering the form has 2 fields `Email` and `Message`.
154 |
155 | ```go
156 |
157 | package main
158 |
159 | import (
160 | "log"
161 | "fmt"
162 | "net/http"
163 | )
164 |
165 | type Details struct {
166 | Email string
167 | Message string
168 | }
169 |
170 | func messageHandle(w http.ResponseWriter, r *http.Request) {
171 | if err := r.ParseForm(); err != nil {
172 | fmt.Fprintf(w, "ParseForm() err: %v", err)
173 | return
174 | }
175 |
176 | data := Details{
177 | Email: r.FormValue("email"),
178 | Message: r.FormValue("message"),
179 | }
180 |
181 | // do something with the data
182 | }
183 |
184 | func main() {
185 | http.HandleFunc("/", messageHandle)
186 |
187 | if err := http.ListenAndServe(":8080", nil); err != nil {
188 | log.Fatal(err)
189 | }
190 | }
191 |
192 |
193 | ```
194 |
195 | [Go back to top ↑](#Contents)
196 |
197 | ## Adding MiddleWare
198 |
199 | Here, the `Middleware` function allows adding more than one layer of middleware and handle them appropriately.
200 | `SomeMiddleware` is the middleware function which gets called before the route handler function `getAllTask`
201 |
202 | ```go
203 |
204 | package main
205 |
206 | import (
207 | "encoding/json"
208 | "log"
209 | "net/http"
210 | "github.com/gorilla/mux"
211 | )
212 |
213 | func getAllTask(w http.ResponseWriter, r *http.Request) {
214 | // ... do something inside this route
215 | }
216 |
217 |
218 | // Function allows adding more than one layer of middleware and handle them appropriately
219 |
220 | func Middleware(h http.Handler, middleware ...func(http.Handler) http.Handler) http.Handler {
221 | for _, mw := range middleware {
222 | h = mw(h)
223 | }
224 | return h
225 | }
226 |
227 | // Middlware function
228 |
229 | func SomeMiddleware(next http.Handler) http.Handler {
230 | return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
231 |
232 | // ... do middleware things
233 |
234 | next.ServeHTTP(w, r)
235 | })
236 | }
237 |
238 | func main() {
239 |
240 | router := mux.NewRouter()
241 | router.Handle("/task", Middleware(
242 | http.HandlerFunc(getAllTask),
243 | SomeMiddleware,
244 | ))
245 | log.Fatal(http.ListenAndServe(":8000", router))
246 | }
247 |
248 |
249 | ```
250 |
251 | [Go back to top ↑](#Contents)
252 |
253 | ## Sessions Management
254 |
255 | ```go
256 |
257 | import (
258 | "os"
259 | "log"
260 | "net/http"
261 | "github.com/gorilla/sessions"
262 | )
263 |
264 | var store = sessions.NewCookieStore([]byte(os.Getenv("SESSION_KEY")))
265 |
266 | func Handlerfunction(w http.ResponseWriter, r *http.Request) {
267 | session, err := store.Get(r, "session-name")
268 | if err != nil {
269 | http.Error(w, err.Error(), http.StatusInternalServerError)
270 | return
271 | }
272 |
273 | // Set some session values.
274 | session.Values["hello"] = "world"
275 | // Save it
276 | session.Save(r, w)
277 | }
278 |
279 |
280 | func main() {
281 | http.HandleFunc("/", Handlerfunction)
282 |
283 | if err := http.ListenAndServe(":8080", nil); err != nil {
284 | log.Fatal(err)
285 | }
286 | }
287 |
288 | ```
289 |
290 | [Go back to top ↑](#Contents)
291 |
292 |
293 | ## Adding Database
294 |
295 | ### MongoDB
296 |
297 | Here in this example we have connected MongoDB with our application and saved sample data into the collection
298 |
299 | ```go
300 |
301 | package main
302 |
303 | import (
304 | "context"
305 | "fmt"
306 | "os"
307 | "time"
308 | "go.mongodb.org/mongo-driver/mongo"
309 | "go.mongodb.org/mongo-driver/mongo/options"
310 | )
311 |
312 | type Data struct {
313 | ID int `json:"Field Int"`
314 | Task string `json:"Field Str"`
315 | }
316 |
317 | func main() {
318 |
319 | clientOptions := options.Client().ApplyURI("")
320 |
321 | // Connect to the MongoDB
322 | client, err := mongo.Connect(context.TODO(), clientOptions)
323 |
324 | if err != nil {
325 | fmt.Println("mongo.Connect() ERROR:", err)
326 | os.Exit(1)
327 | }
328 |
329 | // To manage multiple API requests
330 | ctx, _ := context.WithTimeout(context.Background(), 15*time.Second)
331 |
332 | // Access a MongoDB collection through a database
333 | col := client.Database("DATABASE_NAME").Collection("COLLECTION_NAME")
334 |
335 | // Declare a MongoDB struct instance for the document's fields and data
336 | newData := Data{
337 | ID: 12,
338 | Task: "Learn Go",
339 | }
340 |
341 | result, err := col.InsertOne(ctx, newData)
342 | if err != nil {
343 | fmt.Println("ERROR:", err)
344 | os.Exit(1)
345 |
346 | } else {
347 | fmt.Println("Result:", result)
348 | }
349 | }
350 |
351 | ```
352 |
353 | [Go back to top ↑](#Contents)
354 |
355 |
356 | ## Writing Unit Test
357 |
358 | Consider the [Adding Routes](#Adding-Routes) section for testing. The below test case is for the `/task` route which returns an array of tasks created by users.
359 |
360 | ```go
361 |
362 | package main
363 |
364 | import (
365 | "net/http"
366 | "testing"
367 | "net/http/httptest"
368 | "strings"
369 | )
370 |
371 | func TestGetAllTask(t *testing.T) {
372 | req, err := http.NewRequest("GET", "http://localhost:8000/task", nil)
373 | if err != nil {
374 | t.Fatal(err)
375 | }
376 | res := httptest.NewRecorder()
377 | handler := http.HandlerFunc(getAllTask)
378 | handler.ServeHTTP(res, req)
379 |
380 | if status := res.Code; status != http.StatusOK {
381 | t.Errorf("Wrong Status Code: got %v want %v",
382 | status, http.StatusOK)
383 | }
384 |
385 | // Check the response body is what we expect.
386 | expected := `[{"id":"1","task":"Hello"},{"id":"2","task":"World"},{"id":"3","task":"yeah"}]`
387 |
388 | if strings.TrimRight(res.Body.String(),"\n") != expected {
389 | t.Errorf("ERROR: got %v want %v",
390 | res.Body.String(), expected)
391 | }
392 | }
393 |
394 | ```
395 | Remember Test file should be name of original file + test like: `base.go` - `base_test.go`.(good practice)
396 |
397 | After running the above test case by `go test -v` command, the following output will appear
398 |
399 | ```bash
400 | F:\Go\src\Rest_API>go test -v
401 | === RUN TestGetAllTask
402 | --- PASS: TestGetAllTask (0.00s)
403 | PASS
404 | ok Rest_API 0.454s
405 | ```
406 |
407 | [Go back to top ↑](#Contents)
408 |
409 |
410 | ## Parsing XML Data
411 |
412 | For example we have taken [this](https://github.com/debck/Learning-Go/blob/master/assets/foods.xml) XML file for parsing.
413 |
414 | ```go
415 | package main
416 |
417 | import (
418 | "encoding/xml"
419 | "fmt"
420 | "io/ioutil"
421 | "os"
422 | )
423 |
424 | // struct which contains the array of all Foods in the file.
425 | type Foods struct {
426 | Foods []Food `xml:"food"`
427 | }
428 |
429 | // struct which contains the details of one food.
430 | type Food struct {
431 | Name string `xml:"name"`
432 | Price string `xml:"price"`
433 | Calories string `xml:"calories"`
434 | }
435 |
436 | func main() {
437 | // Open xml file
438 | xmlFile, err := os.Open("foods.xml")
439 |
440 | if err != nil {
441 | fmt.Println(err)
442 | }
443 |
444 | // defer the closing of our xmlfile so that we can parse later
445 | defer xmlFile.Close()
446 |
447 | // read the xml file as a byte array.
448 | byteValue, _ := ioutil.ReadAll(xmlFile)
449 |
450 | var f Foods
451 |
452 | xml.Unmarshal(byteValue, &f)
453 |
454 | // Do something with the info.....
455 |
456 | // Here, we print out the Foods as just an example
457 |
458 | fmt.Println("______MENU______")
459 | for i := 0; i < len(f.Foods); i++ {
460 | fmt.Println(f.Foods[i].Name + " " + f.Foods[i].Price + " " + f.Foods[i].Calories)
461 | }
462 |
463 | }
464 |
465 | ```
466 | After running the above program, the following output will appear
467 |
468 | ```bash
469 | F:\Go\src\Code>go run parsexml.go
470 | ______MENU______
471 | Belgian Waffles $5.95 650
472 | French Toast $4.50 600
473 | ```
474 |
475 | [Go back to top ↑](#Contents)
476 |
477 | ## File Uploading
478 |
479 | > Todo
480 |
481 | ## Contribute
482 |
483 | Contributions are always welcome! Please open an [issue](https://github.com/debck/Learning-Go/issues/new) if you think something should be added to the list.
484 |
485 | ## Licence
486 |
487 | MIT © [Debasish Sahoo](https://github.com/debck/Learning-Go/blob/master/LICENSE)
488 |
489 |
--------------------------------------------------------------------------------
/assets/foods.xml:
--------------------------------------------------------------------------------
1 |
2 |
14 |
--------------------------------------------------------------------------------