diff --git a/en/eBook/01.0.md b/en/eBook/01.0.md index ff2f4905..a1e30140 100644 --- a/en/eBook/01.0.md +++ b/en/eBook/01.0.md @@ -5,12 +5,12 @@ Welcome to the world of Go, let's start exploring! Go is a fast-compiled, garbage-collected, concurrent systems programming language. It has the following advantages: - Compiles a large project within a few seconds. -- Provides a software development model that is easy to reason about, avoiding most of the problems that caused by C-style header files. +- Provides a software development model that is easy to reason about, avoiding most of the problems associated with C-style header files. - Is a static language that does not have levels in its type system, so users do not need to spend much time dealing with relations between types. It is more like a lightweight object-oriented language. - Performs garbage collection. It provides basic support for concurrency and communication. - Designed for multi-core computers. -Go is a compiled language. It combines the development efficiency of interpreted or dynamic languages with the security of static languages. It is going to be the language of choice for the modern multi-core computers with networking. For these purposes, there are some problems that have to be resolved in language itself, such as a richly expressive lightweight type system, concurrency, and strictly regulated garbage collection. For quite some time, no packages or tools have come out that have solved all of these problems pragmatically; thus was born the motivation for the Go language. +Go is a compiled language. It combines the development efficiency of interpreted or dynamic languages with the security of static languages. It is going to be the language of choice for modern, multi-core computers with networking. For these purposes, there are some problems that need to inherently be resolved at the level of the language of choice, such as a richly expressive lightweight type system, a native concurrency model, and strictly regulated garbage collection. For quite some time, no packages or tools have emerged that have aimed to solve all of these problems in a pragmatic fashion; thus was born the motivation for the Go language. In this chapter, I will show you how to install and configure your own Go development environment. diff --git a/en/eBook/01.1.md b/en/eBook/01.1.md index 058981b6..41ccc4bc 100644 --- a/en/eBook/01.1.md +++ b/en/eBook/01.1.md @@ -2,32 +2,33 @@ ## Three ways to install Go -There are many ways to configure the Go development environment on your computer, you can choose any one you like. The three most common ways are as follows. +There are many ways to configure the Go development environment on your computer, and you can choose whichever one you like. The three most common ways are as follows. - Official installation packages. - - The Go team provides convenient installation packages in Windows, Linux, Mac and other operating systems. The easiest way to get started. -- Install from source code. + - The Go team provides convenient installation packages in Windows, Linux, Mac and other operating systems. This is probably the easiest way to get started. +- Install it yourself from source code. - Popular with developers who are familiar with Unix-like systems. -- Use third-party tools. +- Using third-party tools. - There are many third-party tools and package managers for installing Go, like apt-get in Ubuntu and homebrew for Mac. -In case you want to install more than one version of Go in one computer, you should take a look at the tool called [GVM](https://github.com/moovweb/gvm). It is the best tool I've seen so far for achieving this job, otherwise you have to know how to deal with this problem by yourself. +In case you want to install more than one version of Go on a computer, you should take a look at a tool called [GVM](https://github.com/moovweb/gvm). It is the best tool I've seen so far for accomplishing this task, otherwise you'd have to deal with it yourself. ## Install from source code Because some parts of Go are written in Plan 9 C and AT&T assembler, you have to install a C compiler before taking the next step. -On a Mac, once you install the Xcode, you have already have the compiler. +On a Mac, if you have installed Xcode, you already have the compiler. + +On Unix-like systems, you need to install gcc or a similar compiler. For example, using the package manager apt-get (included with Ubuntu), one can install the required compilers as follows: -On Unix-like systems, you need to install gcc or a like compiler. For example, using the package manager apt-get included with Ubuntu, one can install the required compilers as follows: `sudo apt-get install gcc libc6-dev` -On Windows, you need to install MinGW in order to install gcc. Don't forget to configure environment variables after the installation is finished.( ***Everything looks like this means it's commented by translator: If you are using 64-bit Windows, you would better install 64-bit version of MinGW*** ) +On Windows, you need to install MinGW in order to install gcc. Don't forget to configure your environment variables after the installation has completed.( ***Everything that looks like this means it's commented by a translator: If you are using 64-bit Windows, you should install the 64-bit version of MinGW*** ) -The Go team uses [Mercurial](http://mercurial.selenic.com/downloads/) to manage source code, so you need to install this tool in order to download Go source code. +The Go team uses [Mercurial](http://mercurial.selenic.com/downloads/) to manage their source code, so you need to install this tool in order to download the Go source code. -At this point, execute following commands to clone Go source code, and start compiling.( ***It will clone source code to you current directory, switch your work path before you continue. This may take some time.*** ) +At this point, execute the following commands to clone the Go source code and compile it.( ***It will clone the source code to your current directory. Switch your work path before you continue. This may take some time.*** ) hg clone -u release https://code.google.com/p/go cd go/src @@ -37,7 +38,7 @@ A successful installation will end with the message "ALL TESTS PASSED." On Windows, you can achieve the same by running `all.bat`. -If you are using Windows, installation package will set environment variables automatically. In Unix-like systems, you need to set these variables manually as follows.( ***If your Go version is greater than 1.0, you don't have to set $GOBIN, and it will automatically be related to your $GOROOT/bin, which we will talk about in the next section***) +If you are using Windows, the installation package will set your environment variables automatically. In Unix-like systems, you need to set these variables manually as follows. ( ***If your Go version is greater than 1.0, you don't have to set $GOBIN, and it will automatically be related to your $GOROOT/bin, which we will talk about in the next section***) export GOROOT=$HOME/go export GOBIN=$GOROOT/bin @@ -47,59 +48,59 @@ If you see the following information on your screen, you're all set. ![](images/1.1.mac.png?raw=true) -Figure 1.1 Information after installed from source code +Figure 1.1 Information after installing from source code -Once you see the usage information of Go, it means you successfully installed Go on your computer. If it says "no such command", check if your $PATH environment variable contains the installation path of Go. +Once you see the usage information of Go, it means you have successfully installed Go on your computer. If it says "no such command", check that your $PATH environment variable contains the installation path of Go. -## Use standard installation packages +## Using the standard installation packages -Go has one-click installation packages for every operating system. These packages will install Go in `/usr/local/go` (`c:\Go` in Windows) as default. Of course you can change it, but you also need to change all the environment variables manually as I showed above. +Go has one-click installation packages for every supported operating system. These packages will install Go in `/usr/local/go` (`c:\Go` in Windows) by default. Of course this can be modified, but you also need to change all the environment variables manually as I've shown above. ### How to check if your operating system is 32-bit or 64-bit? Our next step depends on your operating system type, so we have to check it before we download the standard installation packages. -If you are using Windows, press `Win+R` and then run the command tool, type command `systeminfo` and it will show you some useful information just few seconds. Find the line with "system type", if you see "x64-based PC" that means your operating system is 64-bit, 32-bit otherwise. +If you are using Windows, press `Win+R` and then run the command tool. Type the `systeminfo` command and it will show you some useful system information. Find the line that says "system type" -if you see "x64-based PC" that means your operating system is 64-bit, 32-bit otherwise. -I strongly recommend downloading the 64-bit version of package if you are Mac users as Go is no longer supports pure 32-bit processors in Mac OS. +I strongly recommend downloading the 64-bit package if you are a Mac user, as Go no longer supports pure 32-bit processors on Mac OSX. Linux users can type `uname -a` in the terminal to see system information. -64-bit operating system shows as follows. +A 64-bit operating system will show the following: x86_64 x86_64 x86_64 GNU/Linux // some machines such as Ubuntu 10.04 will show as following x86_64 GNU/Linux -32-bit operating system shows as follows. +32-bit operating systems instead show: i686 i686 i386 GNU/Linux ### Mac -Go to the [download page](http://code.google.com/p/go/downloads/list), choose `go1.0.3.darwin-386.pkg` for 32-bit systems and `go1.0.3.darwin-amd64.pkg` for 64-bit systems. All the way to the end by clicking "next", `~/go/bin` will be added to $PATH after you finished the installation. Now open the terminal and type `go`. You should now see the what is displayed in figure 1.1. +Go to the [download page](http://code.google.com/p/go/downloads/list), choose `go1.0.3.darwin-386.pkg` for 32-bit systems and `go1.0.3.darwin-amd64.pkg` for 64-bit systems. Going all the way to the end by clicking "next", `~/go/bin` will be added to your system's $PATH after you finish the installation. Now open the terminal and type `go`. You should see the same output shown in igure 1.1. ### Linux -Go to the [download page]((http://code.google.com/p/go/downloads/list), choose `go1.0.3.linux-386.tar.gz` for 32-bit systems and `go1.0.3.linux-amd64.tar.gz` for 64-bit systems. Suppose you want to install Go in path `$GO_INSTALL_DIR`, uncompress `tar.gz` to the path by command `tar zxvf go1.0.3.linux-amd64.tar.gz -C $GO_INSTALL_DIR`. Then set your $PATH `export PATH=$PATH:$GO_INSTALL_DIR/go/bin`. Now just open the terminal and type `go`. You should now see the what is displayed in figure 1.1. +Go to the [download page]((http://code.google.com/p/go/downloads/list), choose `go1.0.3.linux-386.tar.gz` for 32-bit systems and `go1.0.3.linux-amd64.tar.gz` for 64-bit systems. Suppose you want to install Go in the `$GO_INSTALL_DIR` path. Uncompress the `tar.gz` to your chosen path using the command `tar zxvf go1.0.3.linux-amd64.tar.gz -C $GO_INSTALL_DIR`. Then set your $PATH with the following: `export PATH=$PATH:$GO_INSTALL_DIR/go/bin`. Now just open the terminal and type `go`. You should now see the same output displayed in figure 1.1. ### Windows -Go to the [download page]((http://code.google.com/p/go/downloads/list), choose `go1.0.3.windows-386.msi` for 32-bit systems and `go1.0.3.windows-amd64.msi` for 64-bit systems. All the way to the end by clicking "next", `c:/go/bin` will be added to `path`. Now just open a command line window and type `go`. You should now see the what is displayed in figure 1.1. +Go to the [download page]((http://code.google.com/p/go/downloads/list), choose `go1.0.3.windows-386.msi` for 32-bit systems and `go1.0.3.windows-amd64.msi` for 64-bit systems. Going all the way to the end by clicking "next", `c:/go/bin` will be added to `path`. Now just open a command line window and type `go`. You should now see the same output displayed in figure 1.1. ## Use third-party tools ### GVM -GVM is a Go multi-version control tool developed by third-party, like rvm in ruby. It's quite easy to use it. Install gvm by typing following commands in your terminal. +GVM is a Go multi-version control tool developed by a third-party, like rvm for ruby. It's quite easy to use. Install gvm by typing the following commands in your terminal: bash < <(curl -s https://raw.github.com/moovweb/gvm/master/binscripts/gvm-installer) -Then we install Go by following commands. +Then we install Go using the following commands: gvm install go1.0.3 gvm use go1.0.3 -After the process finished, you're all set. +After the process has finished, you're all set. ### apt-get @@ -111,7 +112,7 @@ Ubuntu is the most popular desktop release version of Linux. It uses `apt-get` t ### Homebrew -Homebrew is a software manage tool commonly used in Mac to manage software. Just type following commands to install Go. +Homebrew is a software management tool commonly used in Mac to manage packages. Just type the following commands to install Go. brew install go diff --git a/en/eBook/01.3.md b/en/eBook/01.3.md index 7fb11eb0..0de241e5 100644 --- a/en/eBook/01.3.md +++ b/en/eBook/01.3.md @@ -2,7 +2,7 @@ ## Go commands -The Go language comes with a complete set of command operation tools, you can execute the command line `go` to see them: +The Go language comes with a complete set of command operation tools. You can execute the command line `go` to see them: ![](images/1.3.go.png?raw=true) @@ -14,23 +14,23 @@ These are all useful for us. Let's see how to use some of them. This command is for compiling tests. It will compile dependence packages if it's necessary. -- If the package is not the `main` package such as `mymath` in section 1.2, nothing will be generated after you executed `go build`. If you need package file `.a` in `$GOPATH/pkg`, use `go install` instead. +- If the package is not the `main` package such as `mymath` in section 1.2, nothing will be generated after you execute `go build`. If you need package file `.a` in `$GOPATH/pkg`, use `go install` instead. - If the package is the `main` package, it will generate an executable file in the same folder. If you want the file to be generated in `$GOPATH/bin`, use `go install` or `go build -o ${PATH_HERE}/a.exe.` -- If there are many files in the folder, but you just want to compile one of them, you should append file name after `go build`. For example, `go build a.go`. `go build` will compile all the files in the folder. -- You can also assign the name of file that will be generated. For instance, we have `mathapp` in section 1.2, use `go build -o astaxie.exe` will generate `astaxie.exe` instead of `mathapp.exe`. The default name is your folder name(non-main package) or the first source file name(main package). +- If there are many files in the folder, but you just want to compile one of them, you should append the file name after `go build`. For example, `go build a.go`. `go build` will compile all the files in the folder. +- You can also assign the name of the file that will be generated. For instance, in the `mathapp` project (in section 1.2), using `go build -o astaxie.exe` will generate `astaxie.exe` instead of `mathapp.exe`. The default name is your folder name (non-main package) or the first source file name (main package). -(According to [The Go Programming Language Specification](https://golang.org/ref/spec), package name should be the name after the word `package` in the first line of your source files, it doesn't have to be the same as folder's, and the executable file name will be your folder name as default.]) +(According to [The Go Programming Language Specification](https://golang.org/ref/spec), package names should be the name after the word `package` in the first line of your source files. It doesn't have to be the same as the folder name, and the executable file name will be your folder name by default.]) -- `go build` ignores files whose name starts with `_` or `.`. -- If you want to have different source files for every operating system, you can name files with system name as suffix. Suppose there are some source files for loading arrays, they could be named as follows. +- `go build` ignores files whose names start with `_` or `.`. +- If you want to have different source files for every operating system, you can name files with the system name as a suffix. Suppose there are some source files for loading arrays. They could be named as follows: array_linux.go | array_darwin.go | array_windows.go | array_freebsd.go -`go build` chooses the one that associated with your operating system. For example, it only compiles array_linux.go in Linux systems, and ignores all the others. +`go build` chooses the one that's associated with your operating system. For example, it only compiles array_linux.go in Linux systems, and ignores all the others. ## go clean -This command is for cleaning files that are generated by compilers, including the following files. +This command is for cleaning files that are generated by compilers, including the following files: _obj/ // old directory of object, left by Makefiles _test/ // old directory of test, left by Makefiles @@ -43,24 +43,24 @@ This command is for cleaning files that are generated by compilers, including th DIR.test(.exe) // generated by go test -c MAINFILE(.exe) // generated by go build MAINFILE.go -I usually use this command to clean my files before I upload my project to the Github. These are useful for local tests, but useless for version control. +I usually use this command to clean up my files before I upload my project to Github. These are useful for local tests, but useless for version control. ## go fmt -The people who are working with C/C++ should know that people are always arguing about code style between K&R-style and ANSI-style, which one is better. However in Go, there is only one code style which is enforced. For example, you must put a left brace in the end of the line, and can't put it in a single line, otherwise you will get compile errors! Fortunately, you don't have to remember these rules. `go fmt` does this job for you. Just execute the command `go fmt .go` in terminal. I don't use this command very much because IDEs usually execute this command automatically when you save source files. I will talk about IDEs more in next section. +The people who are working with C/C++ should know that people are always arguing about which code style is better: K&R-style or ANSI-style. However in Go, there is only one code style which is enforced. For example, left braces must only be inserted at the end of lines, and they cannot be on their own lines, otherwise you will get compile errors! Fortunately, you don't have to remember these rules. `go fmt` does this job for you. Just execute the command `go fmt .go` in terminal. I don't use this command very much because IDEs usually execute this command automatically when you save source files. I will talk about IDEs more in the next section. -We usually use `gofmt -w` instead of `go fmt`, the latter will not rewrite your source files after formatted code. `gofmt -w src` formats the whole project. +We usually use `gofmt -w` instead of `go fmt`. The latter will not rewrite your source files after formatting code. `gofmt -w src` formats the whole project. ## go get -This command is for getting remote packages. It supports BitBucket, Github, Google Code and Launchpad so far. There are actually two things that happen after we execute this command. The first thing is to download the source code, then execute `go install`. Before you use this command, make sure you have installed all the related tools. +This command is for getting remote packages. So far, it supports BitBucket, Github, Google Code and Launchpad. There are actually two things that happen after we execute this command. The first thing is that Go downloads the source code, then executes `go install`. Before you use this command, make sure you have installed all of the related tools. BitBucket (Mercurial Git) Github (git) Google Code (Git, Mercurial, Subversion) Launchpad (Bazaar) -In order to use this command, you have to install these tools correctly. Don't forget to set `PATH`. By the way, it also supports customized domain names, use `go help remote` for more details. +In order to use this command, you have to install these tools correctly. Don't forget to set `$PATH`. By the way, it also supports customized domain names. Use `go help remote` for more details about this. ## go install @@ -75,27 +75,27 @@ This command loads all files whose name include `*_test.go` and generates test f ok compress/gzip 0.033s ... -It tests all your test files by default, use command `go help testflag` for more details. +It tests all your test files by default. Use command `go help testflag` for more details. ## go doc -Many people said that we don't need any third-party documentation for programming in Go (actually I've made a [CHM](https://github.com/astaxie/godoc) already), Go has a powerful tool to manage documentation by itself. +Many people say that we don't need any third-party documentation for programming in Go (actually I've made a [CHM](https://github.com/astaxie/godoc) already). Go has a powerful tool to manage documentation natively. -So how do we look up package information in documentation? If you want to get more details about the package `builtin`, use command `go doc builtin`, and use command `go doc net/http` for package `http`. If you want to see more details about specific functions, use command `godoc fmt Printf`, and `godoc -src fmt Printf` to view source code. +So how do we look up package information in documentation? For instance, if you want to get more details about the `builtin` package, use the `go doc builtin` command. Similarly, use the `go doc net/http` command to look up the `http` package documentation. If you want to see more details about specific functions, use the `godoc fmt Printf` and `godoc -src fmt Printf` commands to view the source code. -Execute command `godoc -http=:8080`, then open `127.0.0.1:8080` in your browsers, you should see a localized golang.org. It can not only show the standard packages' information, but also packages in your `$GOPATH/pkg`. It's great for people who are suffering from the Great Firewall of China. +Execute the `godoc -http=:8080` command, then open `127.0.0.1:8080` in your browser. You should see a localized golang.org. It can not only show the standard packages' information, but also packages in your `$GOPATH/pkg`. It's great for people who are suffering from the Great Firewall of China. ## Other commands -Go provides more commands then I just talked about. +Go provides more commands then those we've just talked about. - go fix // upgrade code from old version before go1 to new version after go1 - go version // get information about Go version + go fix // upgrade code from an old version before go1 to a new version after go1 + go version // get information about your version of Go go env // view environment variables about Go go list // list all installed packages go run // compile temporary files and run the application -There are also more details about commands that I talked about, you can use `go help ` to get more information. +There are also more details about the commands that I've talked about. You can use `go help ` to look them up. ## Links diff --git a/en/eBook/02.1.md b/en/eBook/02.1.md index e3c14dce..ad0168fc 100644 --- a/en/eBook/02.1.md +++ b/en/eBook/02.1.md @@ -44,7 +44,7 @@ You may notice that the example above contains many non-ASCII characters. The pu ## Conclusion -Go uses `package` (like modules in Python) to organize programs. The function `main.main()` (this function must be in the `main` package) is the entry point of any program. Go supports UTF-8 characters because one of the creators of Go is a creator of UTF-8, so Go supports multiple languages from the time it was born. +Go uses `package` (like modules in Python) to organize programs. The function `main.main()` (this function must be in the `main` package) is the entry point of any program. Go supports UTF-8 characters because one of the creators of Go is a creator of UTF-8, so Go has supported multiple languages from the time it was born. ## Links diff --git a/en/eBook/05.0.md b/en/eBook/05.0.md index 948d8a28..ba0e6af1 100644 --- a/en/eBook/05.0.md +++ b/en/eBook/05.0.md @@ -1,13 +1,13 @@ # 5 Database -For web developers, the database is the core of web development. You can save almost anything in database, query and update data, like user information, products or news list. +For web developers, the database is at the core of web development. You can save almost anything into a database and query or update data inside it, like user information, products or news articles. -Go doesn't have any driver for database, but it does have a driver interface defined in package `database/sql`, people can develop database drivers based on that interface. In section 5.1, we are going to talk about database driver interface design in Go; in sections 5.2 to 5.4, I will introduce some SQL database drivers to you; in section 5.5, I'll show the ORM that I developed which is based on `database/sql` interface standard, it compatible with most of drivers that implemented `database/sql` interface, and easy to access database in Go code style. +Go doesn't provide any database drivers, but it does have a driver interface defined in the `database/sql` package. People can develop database drivers based on that interface. In section 5.1, we are going to talk about database driver interface design in Go; in sections 5.2 to 5.4, I will introduce some SQL database drivers to you; in section 5.5, i'll present the ORM that i've developed which is based on the `database/sql` interface standard. It's compatible with most drivers that have implemented the `database/sql` interface, and it makes it easy to access databases idiomatically in Go. -NoSQL is a hot topic in recent years, more websites decide to use NoSQL database as their main database instead of just for cache usage. I will introduce two NoSQL database which are MongoDB and Redis to you in section 5.6. +NoSQL has been a hot topic in recent years. More websites are deciding to use NoSQL databases as their main database instead of just for the purpose of caching. I will introduce you to two NoSQL databases, which are MongoDB and Redis, in section 5.6. ## Links - [Directory](preface.md) - Previous Chapter: [Chapter 4 Summary](04.6.md) -- Next section: [database/sql interface](05.1.md) \ No newline at end of file +- Next section: [database/sql interface](05.1.md) diff --git a/en/eBook/05.1.md b/en/eBook/05.1.md index 1f3decc6..b38540f8 100644 --- a/en/eBook/05.1.md +++ b/en/eBook/05.1.md @@ -1,12 +1,12 @@ # 5.1 database/sql interface -Go doesn't provide any official database driver which PHP does, but it does have some database driver interface standards for developers develop database drivers. There is an advantage that if your code is developed according to these interface standards, you will not change any code when your database changes. Let's see what these database interface standards are. +Go doesn't provide any official database drivers, unlike other languages like PHP which do. However, it does have some database driver interface standards for developers to develop database drivers with. The advantage is that if your code is developed according to these interface standards, you will not need to change any code if your database changes. Let's see what these database interface standards are. ## sql.Register -This function is in package `database/sql` for registering database drivers when you use third-party database drivers. In all those drivers, they should call function `Register(name string, driver driver.Driver)` in `init()` function in order to register their drivers. +This function is in the `database/sql` package for registering database drivers when you use third-party database drivers. All of these should call the `Register(name string, driver driver.Driver)` function in `init()` in order to register themselves. -Let's take a look at corresponding code in drivers of mymysql and sqlite3: +Let's take a look at the corresponding mymysql and sqlite3 driver code: //https://github.com/mattn/go-sqlite3 driver func init() { @@ -21,45 +21,45 @@ Let's take a look at corresponding code in drivers of mymysql and sqlite3: sql.Register("mymysql", &d) } -We see that all third-party database drivers implemented this function to register themselves, and Go uses a map to save user drivers inside of `databse/sql`. +We see that all third-party database drivers have implemented this function to register themselves, and Go uses a map to save user drivers inside of `databse/sql`. var drivers = make(map[string]driver.Driver) drivers[name] = driver -Therefore, this register function can register drivers as many as you want with all different name. +Therefore, this register function can register drivers as many as you want with different names. -We always see following code when we use third-party drivers: +We always see the following code when we use third-party drivers: import ( "database/sql" _ "github.com/mattn/go-sqlite3" ) -Here the blank `_` is quite confusing for many beginners, and this is a great design in Go. We know this identifier is for discarding values from function return, and you have to use all imported packages in your code in Go. So when the blank is used with import means you need to execute init() function of that package without directly using it, which is for registering database driver. +Here the underscore (also known as a 'blank') `_` can be quite confusing for many beginners, but this is a great feature in Go. We already know that this identifier is for discarding values from function returns, and also that you must use all packages that you've imported in your code in Go. So when the blank is used with import, it means that you need to execute the init() function of that package without directly using it, which exactly fits the use-case for registering database drivers. ## driver.Driver -`Driver` is a interface that has a method `Open(name string)` that returns a interface of `Conn`. +`Driver` is an interface containing an `Open(name string)` method that returns a `Conn` interface. type Driver interface { Open(name string) (Conn, error) } -This is a one-time Conn, which means it can be used only once in one goroutine. The following code will occur errors: +This is a one-time Conn, which means it can only be used once in one goroutine. The following code will cause errors to occur: ... go goroutineA (Conn) // query go goroutineB (Conn) // insert ... -Because Go has no idea about which goroutine does what operation, so the query operation may get result of insert, vice-versa. +Because Go has no idea which goroutine does what operation, the query operation may get the result of the insert operation, and vice-versa. -All third-party drivers should have this function to parse name of Conn and return results correctly. +All third-party drivers should have this function to parse the name of Conn and return the correct results. ## driver.Conn -This is a database connection interface with some methods, and as I said above, same Conn can only be used in one goroutine. +This is a database connection interface with some methods, and as i've said above, the same Conn can only be used in one goroutine. type Conn interface { Prepare(query string) (Stmt, error) @@ -67,13 +67,13 @@ This is a database connection interface with some methods, and as I said above, Begin() (Tx, error) } -- `Prepare` returns prepare status of corresponding SQL commands for querying and deleting, etc. -- `Close` closes current connection and clean resources. Most of third-party drivers implemented some kinds of connection pool, so you don't need to cache connections unless you want to have unexpected errors. -- `Begin` returns a Tx that represents a affair handle, you can use it for querying, updating or affair roll back etc. +- `Prepare` returns the prepare status of corresponding SQL commands for querying and deleting, etc. +- `Close` closes the current connection and cleans resources. Most third-party drivers implement some kind of connection pool, so you don't need to cache connections unless you want to have unexpected errors. +- `Begin` returns a Tx that represents a transaction handle. You can use it for querying, updating, rolling back transactions, etc. ## driver.Stmt -This is a ready status and is corresponding with Conn, so it can only be used in one goroutine like Conn. +This is a ready status that corresponds with Conn, so it can only be used in one goroutine like Conn. type Stmt interface { Close() error @@ -82,14 +82,14 @@ This is a ready status and is corresponding with Conn, so it can only be used in Query(args []Value) (Rows, error) } -- `Close` closes current connection, but it still returns rows data if it is doing query operation. -- `NumInput` returns the number of obligate arguments, database drivers should check caller's arguments when the result is greater than 0, and it returns -1 when database drivers don't know any obligate argument. -- `Exec` executes SQL commands of `update/insert` that are prepared in `Prepare`, returns `Result`. -- `Query` executes SQL commands of `select` that are prepared in `Prepare`, returns rows data. +- `Close` closes the current connection but still returns row data if it is executing a query operation. +- `NumInput` returns the number of obligate arguments. Database drivers should check their caller's arguments when the result is greater than 0, and it returns -1 when database drivers don't know any obligate argument. +- `Exec` executes the `update/insert` SQL commands prepared in `Prepare`, returns `Result`. +- `Query` executes the `select` SQL command prepared in `Prepare`, returns row data. ## driver.Tx -Generally, affair handle only have submit or roll back, and database drivers only need to implement these two methods. +Generally, transaction handles only have submit or rollback methods, and database drivers only need to implement these two methods. type Tx interface { Commit() error @@ -104,23 +104,23 @@ This is an optional interface. Exec(query string, args []Value) (Result, error) } -If the driver doesn't implement this interface, then when you call DB.Exec, it automatically calls Prepare and returns Stmt, then executes Exec of Stmt, then closes Stmt. +If the driver doesn't implement this interface, when you call DB.Exec, it will automatically call Prepare, then return Stmt. After that it executes the Exec method of Stmt, then closes Stmt. ## driver.Result -This is the interface for result of `update/insert` operations. +This is the interface for results of `update/insert` operations. type Result interface { LastInsertId() (int64, error) RowsAffected() (int64, error) } -- `LastInsertId` returns auto-increment Id number after insert operation from database. -- `RowsAffected` returns rows that affected after query operation. +- `LastInsertId` returns auto-increment Id number after a database insert operation. +- `RowsAffected` returns rows that were affected by query operations. ## driver.Rows -This is the interface for result set of query operation. +This is the interface for the result of a query operation. type Rows interface { Columns() []string @@ -128,13 +128,13 @@ This is the interface for result set of query operation. Next(dest []Value) error } -- `Columns` returns fields information of database tables, the slice is one-to-one correspondence to SQL query field, not all fields in that database table. +- `Columns` returns field information of database tables. The slice has a one-to-one correspondence with SQL query fields only, and does not return all fields of that database table. - `Close` closes Rows iterator. -- `Next` returns next data and assigns to dest, all string should be converted to byte array, and gets io.EOF error if no more data available. +- `Next` returns next data and assigns to dest, converting all strings into byte arrays, and gets io.EOF error if no more data is available. -## diriver.RowsAffected +## driver.RowsAffected -This is a alias of int64, but it implemented Result interface. +This is an alias of int64, but it implements the Result interface. type RowsAffected int64 @@ -144,11 +144,11 @@ This is a alias of int64, but it implemented Result interface. ## driver.Value -This is a empty interface that can contain any kind of data. +This is an empty interface that can contains any kind of data. type Value interface{} -The Value must be somewhat that drivers can operate or nil, so it should be one of following types: +The Value must be something that drivers can operate on or nil, so it should be one of following types: int64 float64 @@ -159,33 +159,33 @@ The Value must be somewhat that drivers can operate or nil, so it should be one ## driver.ValueConverter -This defines a interface for converting normal values to driver.Value. +This defines an interface for converting normal values to driver.Value. type ValueConverter interface { ConvertValue(v interface{}) (Value, error) } -This is commonly used in database drivers and has many good features: +This interface is commonly used in database drivers and has many useful features: -- Convert driver.Value to corresponding database field type, for example convert int64 to uint16. -- Convert database query results to driver.Value. -- Convert driver.Value to user defined value in `scan` function. +- Converts driver.Value to a corresponding database field type, for example converts int64 to uint16. +- Converts database query results to driver.Value. +- Converts driver.Value to a user defined value in the `scan` function. ## driver.Valuer -This defines a interface for returning driver.Value. +This defines an interface for returning driver.Value. type Valuer interface { Value() (Value, error) } -Many types implemented this interface for conversion between driver.Value and itself. +Many types implement this interface for conversion between driver.Value and itself. -At this point, you should have concepts about how to develop a database driver. Once you implement about interfaces for operations like add, delete, update, etc. There only left problems about communicating with specific database. +At this point, you should know a bit about developping database drivers in Go. Once you can implement interfaces for operations like add, delete, update, etc., there are only a few problems left related to communicating with specific databases. ## database/sql -databse/sql defines more high-level methods above database/sql/driver for more convenient operations with databases, and it suggests you to implement a connection pool. +databse/sql defines even more high-level methods on top of database/sql/driver for more convenient database operations, and it suggests that you implement a connection pool. type DB struct { driver driver.Driver @@ -195,7 +195,7 @@ databse/sql defines more high-level methods above database/sql/driver for more c closed bool } -As you can see, Open function returns a DB that has a freeConn, and this is the simple connection pool. Its implementation is very simple or ugly, it uses `defer db.putConn(ci, err)` in function Db.prepare to put connection into connection pool. Every time you call Conn function, it checks length of freeCoon, if it's greater than 0 means there is a reusable connection and directly returns to you, otherwise it creates a new connection and returns. +As you can see, the `Open` function returns a DB that has a freeConn, and this is a simple connection pool. Its implementation is very simple and ugly. It uses `defer db.putConn(ci, err)` in the Db.prepare function to put a connection into the connection pool. Everytime you call the Conn function, it checks the length of freeCoon. If it's greater than 0, that means there is a reusable connection and it directly returns to you. Otherwise it creates a new connection and returns. ## Links diff --git a/en/eBook/05.2.md b/en/eBook/05.2.md index 1ca94d7c..31a62247 100644 --- a/en/eBook/05.2.md +++ b/en/eBook/05.2.md @@ -1,24 +1,24 @@ # 5.2 MySQL -The framework call LAMP is very popular on the internet in recent years, and the M is the MySQL. MySQL is famous by its open source, easy to use, so it becomes the database in the back-end of many websites. +The LAMP stack has been very popular on the internet in recent years, and the M in LAMP stand for MySQL. MySQL is famous because it's open source and easy to use. As such, it became the defacto database in the back-ends of many websites. ## MySQL drivers -There are couple of drivers that support MySQL in Go, some of them implemented `database/sql` interface, and some of them use their only interface standards. +There are a couple of drivers that support MySQL in Go. Some of them implement the `database/sql` interface, and others use their own interface standards. -- [https://github.com/go-sql-driver/mysql](https://github.com/go-sql-driver/mysql) supports `database/sql`, pure Go code. -- [https://github.com/ziutek/mymysql](https://github.com/ziutek/mymysql) supports `database/sql` and user defined interface, pure Go code. -- [https://github.com/Philio/GoMySQL](https://github.com/Philio/GoMySQL) only supports user defined interface, pure Go code. +- [https://github.com/go-sql-driver/mysql](https://github.com/go-sql-driver/mysql) supports `database/sql`, written in pure Go. +- [https://github.com/ziutek/mymysql](https://github.com/ziutek/mymysql) supports `database/sql` and user defined interfaces, written in pure Go. +- [https://github.com/Philio/GoMySQL](https://github.com/Philio/GoMySQL) only supports user defined interfaces, written in pure Go. -I'll use the first driver in my future examples(I use this one in my projects also), and I recommend you to use this one for following reasons: +I'll use the first driver in the following examples (I use this one in my personal projects too), and I also recommend that you use it for the following reasons: - It's a new database driver and supports more features. -- Fully support `databse/sql` interface standards. -- Support keepalive, long connection with thread-safe. +- Fully supports `databse/sql` interface standards. +- Supports keepalive, long connections with thread-safety. ## Samples -In following sections, I'll use same database table structure for different databases, the create SQL as follows: +In the following sections, I'll use the same database table structure for different databases, then create SQL as follows: CREATE TABLE `userinfo` ( `uid` INT(10) NOT NULL AUTO_INCREMENT, @@ -28,7 +28,7 @@ In following sections, I'll use same database table structure for different data PRIMARY KEY (`uid`) ); -The following example shows how to operate database based on `database/sql` interface standards. +The following example shows how to operate on a database based on the `database/sql` interface standards. package main @@ -104,20 +104,20 @@ The following example shows how to operate database based on `database/sql` inte } } -Let me explain few important functions: +Let me explain a few of the important functions here: -- `sql.Open()` opens a registered database driver, here the Go-MySQL-Driver registered mysql driver. The second argument is DSN(Data Source Name) that defines information of database connection, it supports following formats: +- `sql.Open()` opens a registered database driver. The Go-MySQL-Driver registered the mysql driver here. The second argument is the DSN (Data Source Name) that defines information pertaining to the database connection. It supports following formats: user@unix(/path/to/socket)/dbname?charset=utf8 user:password@tcp(localhost:5555)/dbname?charset=utf8 user:password@/dbname user:password@tcp([de:ad:be:ef::ca:fe]:80)/dbname -- `db.Prepare()` returns SQL operation that is going to execute, also returns execute status after executed SQL. -- `db.Query()` executes SQL and returns Rows result. -- `stmt.Exec()` executes SQL that is prepared in Stmt. +- `db.Prepare()` returns a SQL operation that is going to be executed. It also returns the execution status after executing SQL. +- `db.Query()` executes SQL and returns a Rows result. +- `stmt.Exec()` executes SQL that has been prepared and stored in Stmt. -Note that we use format `=?` to pass arguments, it is for preventing SQL injection. +Note that we use the format `=?` to pass arguments. This is necessary for preventing SQL injection attacks. ## Links diff --git a/en/eBook/05.3.md b/en/eBook/05.3.md index c47c5a5d..e57aea92 100644 --- a/en/eBook/05.3.md +++ b/en/eBook/05.3.md @@ -1,20 +1,20 @@ # 5.3 SQLite -SQLite is a open source, embedded relational database, it has a self-contained, zero-configuration and affair-supported database engine. Its characteristics are highly portable, easy to use, compact, efficient and reliable. In most of cases, you only need a binary file of SQLite to create, connect and operate database. If you are looking for a embedded database solution, SQLite is worth to consider. You can say SQLite is the open source version of Access. +SQLite is an open source, embedded relational database. It has a self-contained, zero-configuration and transaction-supported database engine. Its characteristics are highly portable, easy to use, compact, efficient and reliable. In most of cases, you only need a binary file of SQLite to create, connect and operate a database. If you are looking for an embedded database solution, SQLite is worth considering. You can say SQLite is the open source version of Access. ## SQLite drivers -There are many database drivers for SQLite in Go, but many of them are not supporting `database/sql` interface standards. +There are many database drivers for SQLite in Go, but many of them do not support the `database/sql` interface standards. - [https://github.com/mattn/go-sqlite3](https://github.com/mattn/go-sqlite3) supports `database/sql`, based on cgo. - [https://github.com/feyeleanor/gosqlite3](https://github.com/feyeleanor/gosqlite3) doesn't support `database/sql`, based on cgo. - [https://github.com/phf/go-sqlite3](https://github.com/phf/go-sqlite3) doesn't support `database/sql`, based on cgo. -The first driver is the only one that supports `database/sql` interface standards in SQLite drivers, so I use this in my projects and it will be easy to migrate code in the future. +The first driver is the only one that supports the `database/sql` interface standard in its SQLite driver, so I use this in my projects -it will make it easy to migrate my code in the future if I need to. ## Samples -The create SQL as follows: +We create the following SQL: CREATE TABLE `userinfo` ( `uid` INTEGER PRIMARY KEY AUTOINCREMENT, @@ -99,9 +99,9 @@ An example: } } -You may notice that the code is almost same as previous section, and we only changed registered driver name, and call `sql.Open` to connect to SQLite in a different way. +You may have noticed that the code is almost the same as in the previous section, and that we only changed the name of the registered driver and called `sql.Open` to connect to SQLite in a different way. -There is a SQLite management tool available: [http://sqliteadmin.orbmu2k.de/](http://sqliteadmin.orbmu2k.de/) +As a final note on this secton, there is a useful SQLite management tool available: [http://sqliteadmin.orbmu2k.de/](http://sqliteadmin.orbmu2k.de/) ## Links diff --git a/en/eBook/05.4.md b/en/eBook/05.4.md index 6a2a820d..8bf850f9 100644 --- a/en/eBook/05.4.md +++ b/en/eBook/05.4.md @@ -1,20 +1,20 @@ # 5.4 PostgreSQL -PostgreSQL is an object-relational database management system available for many platforms including Linux, FreeBSD, Solaris, Microsoft Windows and Mac OS X. It is released under the MIT-style license, and is thus free and open source software. It's larger than MySQL, because it's designed for enterprise usage like Oracle. So it's a good choice to use PostgreSQL in enterprise projects. +PostgreSQL is an object-relational database management system available for many platforms including Linux, FreeBSD, Solaris, Microsoft Windows and Mac OS X. It is released under an MIT-style license, and is thus free and open source software. It's larger than MySQL because it's designed for enterprise usage like Oracle. Postgresql is good choice for enterprise type projects. ## PostgreSQL drivers -There are many database drivers for PostgreSQL, and three of them as follows: +There are many database drivers available for PostgreSQL. Here are three examples of them: -- [https://github.com/bmizerany/pq](https://github.com/bmizerany/pq) supports `database/sql`, pure Go code. -- [https://github.com/jbarham/gopgsqldriver](https://github.com/jbarham/gopgsqldriver) supports `database/sql`, pure Go code. -- [https://github.com/lxn/go-pgsql](https://github.com/lxn/go-pgsql) supports `database/sql`, pure Go code. +- [https://github.com/bmizerany/pq](https://github.com/bmizerany/pq) supports `database/sql`, written in pure Go. +- [https://github.com/jbarham/gopgsqldriver](https://github.com/jbarham/gopgsqldriver) supports `database/sql`, written in pure Go. +- [https://github.com/lxn/go-pgsql](https://github.com/lxn/go-pgsql) supports `database/sql`, written in pure Go. I'll use the first one in my following examples. ## Samples -The create SQL as follows: +We create the following SQL: CREATE TABLE userinfo ( @@ -103,15 +103,15 @@ An example: } } -Note that PostgreSQL uses format like `$1,$2` instead of `?` in MySQL, and it has different DSN format in `sql.Open`. -Another thing is that the Postgres does not support `sql.Result.LastInsertId()`. +Note that PostgreSQL uses the `$1, $2` format instead of the `?` that MySQL uses, and it has a different DSN format in `sql.Open`. +Another thing is that the Postgres driver does not support `sql.Result.LastInsertId()`. So instead of this, stmt, err := db.Prepare("INSERT INTO userinfo(username,departname,created) VALUES($1,$2,$3);") res, err := stmt.Exec("astaxie", "研发部门", "2012-12-09") fmt.Println(res.LastInsertId()) -Use `db.QueryRow()` and `.Scan()` to get the value for the last inserted id. +use `db.QueryRow()` and `.Scan()` to get the value for the last inserted id. err = db.QueryRow("INSERT INTO TABLE_NAME values($1) returning uid;", VALUE1").Scan(&lastInsertId) fmt.Println(lastInsertId) diff --git a/en/eBook/05.5.md b/en/eBook/05.5.md index 40e3f23e..3ad7a0a7 100644 --- a/en/eBook/05.5.md +++ b/en/eBook/05.5.md @@ -1,13 +1,13 @@ # 5.5 Develop ORM based on beedb -( ***Project beedb is no longer maintained, but code still there*** ) +( ***Project beedb is no longer maintained, but the code s still there*** ) -beedb is a ORM, "Object/Relational Mapping", that developed in Go by me. -It uses Go style to operate database, implemented mapping struct to database records. It's a lightweight Go ORM framework, the purpose of developing this ORM is to help people learn how to write ORM, and finds a good balance between functions and performance. +beedb is an ORM ( object-relational mapper ) developed in Go, by me. +It uses idiomatic Go to operate on databases, implementing struct to database mapping and acts as a lightweight Go ORM framework. The purpose of developing this ORM is not only to help people learn how to write an ORM, but also to find a good balance between functionality and performance when it comes to data persistence. -beedb is an open source project, and supports basic functions of ORM, but doesn't support associated query. +beedb is an open source project that supports basic ORM functionality, but doesn't support association queries. -Because beedb support `database/sql` interface standards, so any driver that supports this interface can be used in beedb, I've tested following drivers: +Because beedb supports `database/sql` interface standards, any driver that implements this interface can be used with beedb. I've tested the following drivers: Mysql: [github.com/ziutek/mymysql/godrv](github.com/ziutek/mymysql/godrv) @@ -23,13 +23,13 @@ ODBC: [bitbucket.org/miquella/mgodbc](bitbucket.org/miquella/mgodbc) ## Installation -You can use `go get` to install beedb in your computer. +You can use `go get` to install beedb locally. go get github.com/astaxie/beedb ## Initialization -First, you have to import all corresponding packages as follows: +First, you have to import all the necessary packages: import ( "database/sql" @@ -37,7 +37,7 @@ First, you have to import all corresponding packages as follows: _ "github.com/ziutek/mymysql/godrv" ) -Then you need to open a database connection and create a beedb object(MySQL in this example): +Then you need to open a database connection and create a beedb object (MySQL in this example): db, err := sql.Open("mymysql", "test/xiemengjun/123456") if err != nil { @@ -45,9 +45,9 @@ Then you need to open a database connection and create a beedb object(MySQL in t } orm := beedb.New(db) -`beedb.New()` actually has two arguments, the first one is for standard requirement, and the second one is for indicating database engine, but if you are using MySQL/SQLite, you can just skip the second one. +`beedb.New()` actually has two arguments. The first is the the database opject, and the second is for indicating which database engine you're using. If you're using MySQL/SQLite, you can just skip the second argument. -Otherwise, you have to initialize, like SQLServer: +Otherwise, this argument must be supplied. For instance, in the case of SQLServer: orm = beedb.New(db, "mssql") @@ -55,11 +55,11 @@ PostgreSQL: orm = beedb.New(db, "pg") -beedb supports debug, and use following code to enable: +beedb supports debugging. Use the following code to enable it: beedb.OnDebug=true -Now we have a struct for the database table `Userinfo` that we used in previous sections. +Next, we have a struct for the `Userinfo` database table that we used in previous sections. type Userinfo struct { Uid int `PK` // if the primary key is not id, you need to add tag `PK` for your customized primary key. @@ -68,12 +68,12 @@ Now we have a struct for the database table `Userinfo` that we used in previous Created time.Time } -Be aware that beedb auto-convert your camel style name to underline and lower case letter. For example, we have `UserInfo` as the struct name, and it will be `user_info` in database, same rule for field name. +Be aware that beedb auto-converts camelcase names to lower snake case. For example, if we have `UserInfo` as the struct name, beedb will convert it to `user_info` in the database. The same rule applies to struct field names. Camel ## Insert data -The following example shows you how to use beedb to save a struct instead of SQL command, and use Save method to apply change. +The following example shows you how to use beedb to save a struct, instead of using raw SQL commands. We use the beedb Save method to apply the change. var saveone Userinfo saveone.Username = "Test Add User" @@ -81,9 +81,9 @@ The following example shows you how to use beedb to save a struct instead of SQL saveone.Created = time.Now() orm.Save(&saveone) -And you can check `saveone.Uid` after inserted, its value is self-increase ID, Save method did this job for you. +You can check `saveone.Uid` after the record is inserted; its value is a self-incremented ID, which the Save method takes care of for you. -beedb provides another way to insert data, which is using map. +beedb provides another way of inserting data; this is via Go's map type. add := make(map[string]interface{}) add["username"] = "astaxie" @@ -102,37 +102,37 @@ Insert multiple data: add2["username"] = "astaxie2" add2["departname"] = "cloud develop2" add2["created"] = "2012-12-02" - addslice =append(addslice, add, add2) + addslice = append(addslice, add, add2) orm.SetTable("userinfo").InsertBatch(addslice) -The way I showed you above is like chain query, you should be familiar if you know jquery. It returns original ORM object after calls, and continue to do other jobs. +The method shown above is similar to a chained query, which you should be familiar with if you've ever used jquery. It returns the original ORM object after calls, then continues doing other jobs. -The method `SetTable` tells ORM we want to insert our data to table `userinfo`. +The method `SetTable` tells the ORM we want to insert our data into the `userinfo` table. ## Update data -Continue above example to show how to update data. Now we have primary key value of saveone(Uid), so beedb executes update operation instead of inserting new record. +Let's continue working with the above example to see how to update data. Now that we have the primary key of saveone(Uid), beedb executes an update operation instead of inserting a new record. saveone.Username = "Update Username" saveone.Departname = "Update Departname" saveone.Created = time.Now() orm.Save(&saveone) // update -You can use map for updating data also: +Like before, you can use map for updating data also: t := make(map[string]interface{}) t["username"] = "astaxie" orm.SetTable("userinfo").SetPK("uid").Where(2).Update(t) -Let me explain some methods we used above: +Let me explain some of the methods used above: -- `.SetPK()` tells ORM `uid` is the primary key of table `userinfo`. -- `.Where()` sets conditions, supports multiple arguments, if the first argument is a integer, it's a short form of `Where("=?", )`. -- `.Update()` method accepts map and update to database. +- `.SetPK()` tells the ORM that `uid` is the primary key records in the `userinfo` table. +- `.Where()` sets conditions and supports multiple arguments. If the first argument is an integer, it's a short form for `Where("=?", )`. +- `.Update()` method accepts a map and updates the database. ## Query data -beedb query interface is very flexible, let's see some examples: +The beedb query interface is very flexible. Let's see some examples: Example 1, query by primary key: @@ -159,7 +159,7 @@ Example 4, more complex conditions: Examples to get multiple records: -Example 1, gets 10 records that `id>3` and starts with position 20: +Example 1, gets 10 records with `id>3` that starts with position 20: var allusers []Userinfo err := orm.Where("id > ?", "3").Limit(10,20).FindAll(&allusers) @@ -174,17 +174,17 @@ Example 3, gets all records: var everyone []Userinfo err := orm.OrderBy("uid desc,username asc").FindAll(&everyone) -As you can see, the Limit method is for limiting number of results. +As you can see, the Limit method is for limiting the number of results. -- `.Limit()` supports two arguments, which are number of results and start position. 0 is the default value of start position. -- `.OrderBy()` is for ordering results, the arguments is the order condition. +- `.Limit()` supports two arguments: the number of results and the starting position. 0 is the default value of the starting position. +- `.OrderBy()` is for ordering results. The argument is the order condition. -All examples that you see is mapping records to structs, and you can also just put data into map as follows: +All the examples here are simply mapping records to structs. You can also just put the data into a map as follows: a, _ := orm.SetTable("userinfo").SetPK("uid").Where(2).Select("uid,username").FindMap() -- `.Select()` tells beedb how many fields you want to get from database table, returns all fields as default. -- `.FindMap()` returns type `[]map[string][]byte`, so you need to convert to other types by yourself. +- `.Select()` tells beedb how many fields you want to get from the database table. If unspecified, all fields are returned by default. +- `.FindMap()` returns the `[]map[string][]byte` type, so you need to convert to other types yourself. ## Delete data @@ -204,15 +204,15 @@ Example 3, delete records by SQL: orm.SetTable("userinfo").Where("uid>?", 3).DeleteRow() -## Associated query +## Association queries beedb doesn't support joining between structs. -However since some applications need this feature, here is a implementation: +However, since some applications need this feature, here is an implementation: a, _ := orm.SetTable("userinfo").Join("LEFT", "userdetail", "userinfo.uid=userdetail.uid") .Where("userinfo.uid=?", 1).Select("userinfo.uid,userinfo.username,userdetail.profile").FindMap() -We see a new method called `.Join()`, it has three arguments: +We see a new method called `.Join()` that has three arguments: - The first argument: Type of Join; INNER, LEFT, OUTER, CROSS, etc. - The second argument: the table you want to join with. @@ -220,19 +220,19 @@ We see a new method called `.Join()`, it has three arguments: ## Group By and Having -beedb also has a implementation of `group by` and `having`. +beedb also has an implementation of `group by` and `having`. a, _ := orm.SetTable("userinfo").GroupBy("username").Having("username='astaxie'").FindMap() -- `.GroupBy()` indicates field that is for group by. +- `.GroupBy()` indicates the field that is for group by. - `.Having()` indicates conditions of having. ## Future -I have received many feedback from many people from all around world, and I'm thinking about reconfiguration in following aspects: +I have received a lot of feedback on beedb from many people all around world, and I'm thinking about reconfiguring the following aspects: -- Implement interface design like `database/sql/driver` in order to implement corresponding CRUD operations. -- Implement relational database design, one to one, one to many, many to many, here are some samples: +- Implement an interface design similar to `database/sql/driver` in order to facilitate CRUD operations. +- Implement relational database associations like one to one, one to many and many to many. Here's a sample: type Profile struct { Nickname string @@ -246,8 +246,8 @@ I have received many feedback from many people from all around world, and I'm th Profile HasOne } -- Auto-create table and index. -- Implement connection pool through goroutine. +- Auto-create tables and indexes. +- Implement a connection pool using goroutines. ## Links diff --git a/en/eBook/05.6.md b/en/eBook/05.6.md index 8361bcbe..bf3bdc0a 100644 --- a/en/eBook/05.6.md +++ b/en/eBook/05.6.md @@ -1,12 +1,12 @@ # 5.6 NoSQL database -A NoSQL database provides a mechanism for storage and retrieval of data that use looser consistency models than relational database in order to achieve horizontal scaling and higher availability. Some authors refer to them as "Not only SQL" to emphasize that some NoSQL systems do allow SQL-like query language to be used. +A NoSQL database provides a mechanism for the storage and retrieval of data that uses looser consistency models than typical relational databases in order to achieve horizontal scaling and higher availability. Some authors refer to them as "Not only SQL" to emphasize that some NoSQL systems do allow SQL-like query languages to be used. -As the C language of 21st century, Go has good support for NoSQL databases, and the popular NoSQL database including redis, mongoDB, Cassandra and Membase. +As the C language of the 21st century, Go has good support for NoSQL databases, including the popular redis, mongoDB, Cassandra and Membase NoSQL databases. ## redis -redis is a key-value storage system like Memcached, it supports string, list, set and zset(ordered set) as it's value types. +redis is a key-value storage system like Memcached, that supports the string, list, set and zset(ordered set) value types. There are some Go database drivers for redis: @@ -15,11 +15,11 @@ There are some Go database drivers for redis: - [https://github.com/simonz05/godis](https://github.com/simonz05/godis) - [https://github.com/hoisie/redis.go](https://github.com/hoisie/redis.go) -I forked the last one and fixed some bugs, and use it in my short URL service(2 million PV every day). +I forked the last of these packages, fixed some bugs, and used it in my short URL service (2 million PV every day). - [https://github.com/astaxie/goredis](https://github.com/astaxie/goredis) -Let's see how to use the driver that I forked to operate database: +Let's see how to use the driver that I forked to operate on a database: package main @@ -52,7 +52,7 @@ Let's see how to use the driver that I forked to operate database: client.Del("l") } -We can see that it's quite easy to operate redis in Go, and it has high performance. Its client commands are almost the same as redis built-in commands. +We can see that it's quite easy to operate redis in Go, and it has high performance. Its client commands are almost the same as redis' built-in commands. ## mongoDB @@ -60,9 +60,9 @@ mongoDB (from "humongous") is an open source document-oriented database system d ![](images/5.6.mongodb.png?raw=true) -Figure 5.1 MongoDB compares to Mysql +Figure 5.1 MongoDB compared to Mysql -The best driver for mongoDB is called `mgo`, and it is possible to be in the standard library in the future. +The best driver for mongoDB is called `mgo`, and it is possible that it will be included in the standard library in the future. Here is the example: @@ -104,7 +104,7 @@ Here is the example: fmt.Println("Phone:", result.Phone) } -We can see that there is no big different to operate database between mgo and beedb, they are both based on struct, this is what Go style is. +We can see that there are no big differences when it comes to operating on mgo or beedb databases; they are both based on structs. This is the Go way of doing things. ## Links diff --git a/en/eBook/05.7.md b/en/eBook/05.7.md index b25432f6..96c8bf8e 100644 --- a/en/eBook/05.7.md +++ b/en/eBook/05.7.md @@ -1,11 +1,11 @@ # 5.7 Summary -In this chapter, you first learned the design of `database/sql` interface, and many third-party database drivers for different kinds of database. Then I introduced beedb to you, an ORM for relational databases, also showed some samples for operating database. In the end, I talked about some NoSQL databases, I have to see Go gives very good support for those NoSQL databases. +In this chapter, you first learned about the design of the `database/sql` interface and many third-party database drivers for various database types. Then I introduced beedb, an ORM for relational databases, to you. I also showed you some sample database operations. In the end, I talked about a few NoSQL databases. We saw that Go provides very good support for those NoSQL databases. -After read this chapter, I hope you know how to operate databases in Go. This is the most important part in web development, so I want to you completely understand design ideas of `database/sql` interface. +After reading this chapter, I hope that you have a better understanding of how to operate databases in Go. This is the most important part of web development, so I want you to completely understand the design concepts of the `database/sql` interface. ## Links - [Directory](preface.md) - Previous section: [NoSQL database](05.6.md) -- Next section: [Data storage and session](06.0.md) \ No newline at end of file +- Next section: [Data storage and session](06.0.md) diff --git a/en/eBook/06.0.md b/en/eBook/06.0.md index f4f118d3..2c517a6d 100644 --- a/en/eBook/06.0.md +++ b/en/eBook/06.0.md @@ -1,8 +1,8 @@ -# 6 Data storage and session +# 6 Data storage and sessions -An important topic in web development is providing good user experience, but HTTP is stateless protocol, how can we control the whole process of viewing web sites of users? The classic solutions are using cookie and session, where cookies is client side mechanism and session is saved in server side with unique identifier for every single user. Noted that session can be passed in URL or in cookie, or even in your database which is much safer but it may drag down your application performance. +An important topic in web development is providing a good user experience, but the fact that HTTP is a stateless protocol seems contrary to this spirit. How can we control the whole process of viewing websites for users? The classic solutions are using cookies and sessions, where cookies serve as the client side mechanism and sessions are saved on the server side with a unique identifier for every single user. Note that sessions can be passed in URLs or cookies, or even in your database (which is much more secure, but may hamper your application performance). -In section 6.1, we are going to talk about differences between cookie and session. In section 6.2, you'll learn how to use session in Go with a implementation of session manager. In section 6.3, we will talk about session hijack and how to prevent it when you know that session can be saved in anywhere. The session manager we will implement in section 6.3 is saving session in memory, but if we need to expand our application that have requirement of sharing session, we'd better save session in database, and we'll talk more about this in section 6.4. +In section 6.1, we are going to talk about differences between cookies and sessions. In section 6.2, you'll learn how to use sessions in Go with an implementation of a session manager. In section 6.3, we will talk about session hijacking and how to prevent it when you know that sessions can be saved anywhere. The session manager we will implement in section 6.3 will save sessions in memory, but if we need to expand our application to allow for session sharing, it's always better to save these sessions directly into our database. We'll talk more about this in section 6.4. ## Links diff --git a/en/eBook/06.1.md b/en/eBook/06.1.md index 509ca550..48da2d80 100644 --- a/en/eBook/06.1.md +++ b/en/eBook/06.1.md @@ -1,44 +1,44 @@ ## 6.1 Session and cookies -Session and cookies are two common concepts in web browse, also they are very easy to misunderstand, but they are extremely important in authorization and statistic pages. Let's comprehend both of them. +Sessions and cookies are two very common web concepts, and are also very easy to misunderstand. However, they are extremely important for the authorization of pages, as well as for gathering page statistics. Let's take a look at these two use cases. -Suppose you want to crawl a limited access page, like user home page in twitter. Of course you can open your browser and type your user name and password to log in and access those information, but so-called "crawl" means we use program to simulate this process without human intervene. Therefore, we have to find out what is really going on behind our actions when we use browsers to log in. +Suppose you want to crawl a page that restricts public access, like a twitter user's homepage for instance. Of course you can open your browser and type in your username and password to login and access that information, but so-called "web crawling" means that we use a program to automate this process without any human intervention. Therefore, we have to find out what is really going on behind the scenes when we use a browser to login. -When we get log in page, and type user name and password, and press "log in" button, browser send POST request to remote server. Browser redirects to home page after server returns right respond. The question is how does server know that we have right to open limited access page? Because HTTP is stateless, server has no way to know we passed the verification in last step. The easiest solution is append user name and password in the URL, it works but gives too much pressure to server (verify every request in database), and has terrible user experience. So there is only one way to achieve this goal, which is save identify information either in server or client side, this is why we have cookie and session. +When we first receive a login page and type in a username and password, after we press the "login" button, the browser sends a POST request to the remote server. The Browser redirects to the user homepage after the server verifies the login information and returns an HTTP response. The question here is, how does the server know that we have access priviledges for the desired webpage? Because HTTP is stateless, the server has no way of knowing whether or not we passed the verification in last step. The easiest and perhaps the most naive solution is to append the username and password to the URL. This works, but puts too much pressure on the server (the server must validate every request against the database), and can be detrimental to the user experience. An alternative way of achieving this goal is to save the user's identity either on the server side or client side using cookies and sessions. -cookie, in short it is history information (including log in information) that is saved in client computer, and browser sends cookies when next time user visits same web site, automatically finishes log in step for user. +Cookies, in short, store historical information (including user login information) on the client's computer. The client's browser sends these cookies everytime the user visits the same website, automatically completing the login step for the user. ![](images/6.1.cookie2.png?raw=true) Figure 6.1 cookie principle. -session, in short it is history information that is saved in server, server uses session id to identify different session, and the session id is produced by server, it should keep random and unique, you can use cookie to get client identity, or by URL as arguments. +Sessions, on the other hand, store historical information on the server side. The server uses a session id to identify different sessions, and the session id that is generated by the server should always be random and unique. You can use cookies or URL arguments to get the client's identity. ![](images/6.1.session.png?raw=true) Figure 6.2 session principle. -## Cookie +## Cookies -Cookie is maintained by browsers and along with requests between web servers and browsers. Web application can access cookies information when users visit site. In browser setting there is one about cookies privacy, and you should see something similar as follows when you open it: +Cookies are maintained by browsers. They can be modified during communication between webservers and browsers. Web applications can access cookie information when users visit the corresponding websites. Within most browser settings, there is one setting pertaining to cookie privacy. You should be able to see something similar to the following when you open it. ![](images/6.1.cookie.png?raw=true) Figure 6.3 cookie in browsers. -Cookie has expired time, and there are two kinds of cookies based on life period: session cookie and persistent cookie. +Cookies have an expiry time, and there are two types of cookies distinguished by their life cyles: session cookies and persistent cookies. -If you don't set expired time, browser will not save it into local file after you close the browser, it's called session cookies; this kind of cookies are usually saved in memory instead of local file system. +If your application doesn't set a cookie expiry time, the browser will not save it into the local file system after the browser is closed. These cookies are called session cookies, and this type of cookie is usually saved in memory instead of to the local file system. -If you set expired time (setMaxAge(60*60*24)), browser will save this cookies in local file system, and it will not be deleted until reached expired time. Cookies that is saved in local file system can be shared in different processes of browsers, for example, two IE windows; different kinds of browsers use different process for handling cookie that is saved in memory.    +If your application does set an expiry time (for example, setMaxAge(60*60*24)), the browser *will* save this cookie to the local file system, and it will not be deleted until reaching the allotted expiry time. Cookies that are saved to the local file system can be shared by different browser processes -for example, by two IE windows; different browsers use different processes for dealing with cookies that are saved in memory.    ## Set cookies in Go -Go uses function `SetCookie` in package `net/http` to set cookie: +Go uses the `SetCookie` function in the `net/http` package to set cookies: http.SetCookie(w ResponseWriter, cookie *Cookie) -`w` is the response of the request, cookie is a struct, let's see how it looks like: +`w` is the response of the request and cookie is a struct. Let's see what it looks like: type Cookie struct { Name string @@ -58,7 +58,7 @@ Go uses function `SetCookie` in package `net/http` to set cookie: Unparsed []string // Raw text of unparsed attribute-value pairs } -Here is an example of setting cookie: +Here is an example of setting a cookie: expiration := *time.LocalTime() expiration.Year += 1 @@ -66,46 +66,46 @@ Here is an example of setting cookie: http.SetCookie(w, &cookie)    -## Get cookie in Go +## Fetch cookies in Go -The above example shows how to set cookies, let's see how to get cookie: +The above example shows how to set a cookie. Now let's see how to get a cookie that has been set: cookie, _ := r.Cookie("username") fmt.Fprint(w, cookie) -Here is another way to get cookie: +Here is another way to get a cookie: for _, cookie := range r.Cookies() { fmt.Fprint(w, cookie.Name) } -As you can see, it's very convenient to get cookie in request. +As you can see, it's very convenient to get cookies from requests. -## Session +## Sessions -Session means a series of actions or messages, for example, your actions from pick up your telephone to hang up can be called a session. However, session implied connection-oriented or keep connection when it's related to network protocol. +A session is a series of actions or messages. For example, you can think of the actions you between picking up your telephone to hanging up to be a type of session. When it comes to network protocols, sessions have more to do with connections between browsers and servers. -Session has more meaning when it hits web development, which means a solution that keep connection status between server and client, sometimes it also means the data storage struct of this solution. +Sessions help to store the connection status between server and client, and this can sometimes be in the form of a data storage struct. -Session is the server side mechanism, server uses something like (or actually) use hash table to save information. +Sessions are a server side mechanism, and usually employ hash tables (or something similar) to save incoming information. -When an application need to assign a new session for the client, server should check if there is any session for same client with unique session id. If the session id has already existed, server just return the same session to client, create a new session if there is no one for that client (it usually happens when server has deleted corresponding session id but user append ole session manually). +When an application needs to assign a new session to a client, the server should check if there are any existing sessions for same client with a unique session id. If the session id already exists, the server will just return the same session to the client. On the other hand, if a session id doesn't exist for the client, the server creates a brand new session (this usually happens when the server has deleted the corresponding session id, but the user has appended the old session manually). -The session itself is not complex, but its implementation and deployment are very complicated, so you cannot use "one way to rule them all". +The session itself is not complex but its implementation and deployment are, so you cannot use "one way to rule them all". ## Summary -In conclusion, the goal of session and cookie is the same, they are both for overcoming defect of HTTP stateless, but they use different ways. Session uses cookie to save session id in client side, and save other information in server side, and cookie saves all information in client side. So you may notice that cookie has some security problems, for example, user name and password can be cracked and collected by other sites. +In conclusion, the purpose of sessions and cookies are the same. They are both for overcoming the statelessness of HTTP, but they use different ways. Sessions use cookies to save session ids on the client side, and save all other information on the server side. Cookies save all client information on the client side. You may have noticed that cookies have some security problems. For example, usernames and passwords can potentially be cracked and collected by malicious third party websites. -There are two examples: +Here are two common exploits: -1. appA setting unexpected cookie for appB. -2. XSS, appA uses JavaScript `document.cookie` to access cookies of appB. +1. appA setting an unexpected cookie for appB. +2. XSS attack: appA uses the JavaScript `document.cookie` to access the cookies of appB. -Through introduction of this section, you should know basic concepts of cookie and session, understand the differences between them, so you will not kill yourself when bugs come out. We will get more detail about session in following sections. +After finishing this section, you should know some of the basic concepts of cookies and sessions. You should be able to understand the differences between them so that you won't kill yourself when bugs inevitably emerge. We'll discuss sessions in more detail in the following sections. ## Links - [Directory](preface.md) - Previous section: [Data storage and session](06.0.md) -- Next section: [How to use session in Go](06.2.md) \ No newline at end of file +- Next section: [How to use session in Go](06.2.md) diff --git a/en/eBook/06.2.md b/en/eBook/06.2.md index bfb13ace..0bbb6bdf 100644 --- a/en/eBook/06.2.md +++ b/en/eBook/06.2.md @@ -1,35 +1,35 @@ -# 6.2 How to use session in Go +# 6.2 How to use sessions in Go -You learned that session is a solution of user verification between client and server in section 6.1, and for now there is no support for session from Go standard library, so we're going to implement our version of session manager in Go. +In section 6.1, we learned that sessions are one solution for verifying users, and that for now, the Go standard library does not have baked-in support for sessions or session handling. So, we're going to implement our own version of a session manager in Go. -## Create session +## Creating sessions -The basic principle of session is that server maintains a kind of information for every single client, and client rely on an unique session id to access the information. When users visit the web application, server will crated a new session as following three steps as needed: +The basic principle behind sessions is that a server maintains information for every single client, and clients rely on unique session ids to access this information. When users visit the web application, the server will create a new session with the following three steps, as needed: -- Create unique session id -- Open up data storage space: normally we save session in memory, but you will lose all session data once the system interrupt accidentally, it causes serious problems if your web application is for electronic commerce. In order to solve this problem, you can save your session data in database or file system, it makes data be persistence and easy to share with other applications, though it needs more IO pay expenses. -- Send unique session id to clients. +- Create a unique session id +- Open up a data storage space: normally we save sessions in memory, but you will lose all session data if the system is accidentally interrupted. This can be a very serious issue if web application deals with sensitive data, like in electronic commerce for instance. In order to solve this problem, you can instead save your session data in a database or file system. This makes data persistence more reliable and easy to share with other applications, although the tradeoff is that more server-side IO is needed to read and write these sessions. +- Send the unique session id to the client. -The key step of above steps is to send unique session id to clients. In consideration of HTTP, you can either use respond line, header or body; therefore, we have cookie and URL rewrite two ways to send session id to clients. +The key step here is to send the unique session id to the client. In the context of a standard HTTP response, you can either use the response line, header or body to accomplish this; therefore, we have two ways to send session ids to clients: by cookies or URL rewrites. -- Cookie: Server can easily use Set-cookie in header to save session id to clients, and clients will carry this cookies in future requests; we often set 0 as expired time of cookie that contains session information, which means the cookie will be saved in memory and deleted after users close browsers. -- URL rewrite: append session id as arguments in URL in all pages, this way seems like messy, but it's the best choice if client disabled the cookie feature. +- Cookies: the server can easily use `Set-cookie` inside of a response header to save a session id to a client, and a client can then this cookie for future requests; we often set the expiry time for for cookies containing session information to 0, which means the cookie will be saved in memory and only deleted after users have close their browsers. +- URL rewrite: append the session id as arguments in the URL for all pages. This way seems messy, but it's the best choice if clients have disabled cookies in their browsers. -## Use Go to manage session +## Use Go to manage sessions -After we talked about the constructive process of session, you should have a overview of it, but how can we use it in dynamic pages? Let's combine life cycle of session to implement a Go session manager. +We've talked about constructing sessions, and you should now have a general overview of it, but how can we use sessions on dynamic pages? Let's take a closer look at the life cycle of a session so we can continue implementing our Go session manager. ### Session management design -Here is the list of factors of session management: +Here is a list of some of the key considerations in session management design. - Global session manager. - Keep session id unique. -- Have one session for every single user. -- Session storage, in memory, file or database. -- Deal with expired session. +- Have one session for every user. +- Session storage in memory, file or database. +- Deal with expired sessions. -I'll show you a complete example of Go session manager and mentality of designing. +Next, we'll examine a complete example of a Go session manager and the rationale behind some of its design decisions. ### Session manager @@ -50,15 +50,15 @@ Define a global session manager: return &Manager{provider: provider, cookieName: cookieName, maxlifetime: maxlifetime}, nil } -Create a global session manager in main() function: +Create a global session manager in the `main()` function: var globalSessions *session.Manager - //然后在init函数中初始化 + // Then, initialize the session manager func init() { globalSessions = NewManager("memory","gosessionid",3600) } -We know that we can save session in many ways, including memory, file system or database, so we need to define a interface `Provider` in order to represent underlying structure of our session manager: +We know that we can save sessions in many ways including in memory, the file system or directly into the database. We need to define a `Provider` interface in order to represent the underlying structure of our session manager: type Provider interface { SessionInit(sid string) (Session, error) @@ -67,12 +67,12 @@ We know that we can save session in many ways, including memory, file system or SessionGC(maxLifeTime int64) } -- `SessionInit` implements initialization of session, it returns new session variable if it succeed. -- `SessionRead` returns session variable that is represented by corresponding sid, it creates a new session variable and return if it does not exist. -- `SessionDestory` deletes session variable by corresponding sid. +- `SessionInit` implements the initialization of a session, and returns new a session if it succeeds. +- `SessionRead` returns a session represented by the corresponding sid. Creates a new session and returns it if it does not already exist. +- `SessionDestroy` given an sid, deletes the corresponding session. - `SessionGC` deletes expired session variables according to `maxLifeTime`. -So what methods should our session interface have? If you have web development experience, you should know that there are only four operations for session, which are set value, get value, delete value and get current session id, so our session interface should have four method for these operations. +So what methods should our session interface have? If you have any experience in web development, you should know that there are only four operations for sessions: set value, get value, delete value and get current session id. So, our session interface should have four methods to perform these operations. type Session interface { Set(key, value interface{}) error //set session value @@ -81,12 +81,12 @@ So what methods should our session interface have? If you have web development e SessionID() string //back current sessionID } -The mentality of designing is from `database/sql/driver` that define the interface first and register specific structure when we want to use. The following code is the internal implementation of session register function. +This design takes its roots from the `database/sql/driver`, which defines the interface first, then registers specific structures when we want to use it. The following code is the internal implementation of a session register function. var provides = make(map[string]Provider) - // Register makes a session provide available by the provided name. - // If Register is called twice with the same name or if driver is nil, + // Register makes a session provider available by the provided name. + // If a Register is called twice with the same name or if the driver is nil, // it panics. func Register(name string, provider Provider) { if provider == nil { @@ -98,9 +98,9 @@ The mentality of designing is from `database/sql/driver` that define the interfa provides[name] = provider } -### Unique session id +### Unique session ids -Session id is for identifying users of web applications, so it has to be unique, the following code shows how to achieve this goal: +Session ids are for identifying users of web applications, so they must be unique. The following code shows how to achieve this goal: func (manager *Manager) sessionId() string { b := make([]byte, 32) @@ -110,9 +110,9 @@ Session id is for identifying users of web applications, so it has to be unique, return base64.URLEncoding.EncodeToString(b) } -### Create session +### Creating a session -We need to allocate or get corresponding session in order to verify user operations. Function `SessionStart` is for checking if any session related to current user, create a new one if no related session. +We need to allocate or get an existing session in order to validate user operations. The `SessionStart` function is for checking if any there are any sessions related to the current user, creating a new session non are found. func (manager *Manager) SessionStart(w http.ResponseWriter, r *http.Request) (session Session) { manager.lock.Lock() @@ -130,7 +130,7 @@ We need to allocate or get corresponding session in order to verify user operati return } -Here is an example that uses session for log in operation. +Here is an example that uses sessions for a login operation. func login(w http.ResponseWriter, r *http.Request) { sess := globalSessions.SessionStart(w, r) @@ -147,9 +147,9 @@ Here is an example that uses session for log in operation. ### Operation value: set, get and delete -Function `SessionStart` returns a variable that implemented session interface, so how can we use it? +The `SessionStart` function returns a variable that implements a session interface. How do we use it? -You saw `session.Get("uid")` in above example for basic operation, now let's see a detailed example. +You saw `session.Get("uid")` in the above example for a basic operation. Now let's examine a more detailed example. func count(w http.ResponseWriter, r *http.Request) { sess := globalSessions.SessionStart(w, r) @@ -171,13 +171,13 @@ You saw `session.Get("uid")` in above example for basic operation, now let's see t.Execute(w, sess.Get("countnum")) } -As you can see, operate session is very like key/value pattern database in operation Set, Get and Delete, etc. +As you can see, operating on sessions simply involves using the key/value pattern in the Set, Get and Delete operations. -Because session has concept of expired, so we defined GC to update session latest modify time, then GC will not delete session that is expired but still using. +Because sessions have the concept of an expiry time, we define the GC to update the session's latest modify time. This way, the GC will not delete sessions that have expired but are still being used. -### Reset session +### Reset sessions -We know that web application has log out operation, and we need to delete corresponding session, we've already used reset operation in above example, let's see the code of function body. +We know that web application have a logout operation. When users logout, we need to delete the corresponding session. We've already used the reset operation in above example -now let's take a look at the function body. //Destroy sessionid func (manager *Manager) SessionDestroy(w http.ResponseWriter, r *http.Request){ @@ -194,9 +194,9 @@ We know that web application has log out operation, and we need to delete corres } } -### Delete session +### Delete sessions -Let's see how to let session manager delete session, we need to start GC in main() function: +Let's see how to let the session manager delete a session. We need to start the GC in the `main()` function: func init() { go globalSessions.GC() @@ -209,14 +209,14 @@ Let's see how to let session manager delete session, we need to start GC in main time.AfterFunc(time.Duration(manager.maxlifetime), func() { manager.GC() }) } -We see that GC makes full use of the timer function in package `time`, it automatically calls GC when timeout, ensure that all session are usable during `maxLifeTime`, similar solution can be used to count online users. +We see that the GC makes full use of the timer function in the `time` package. It automatically calls GC when the session times out, ensuring that all sessions are usable during `maxLifeTime`. A similar solution can be used to count online users. ## Summary -So far we implemented a session manager to manage global session in the web application, defined the `Provider` interface for storage implementation of `Session`. In next section, we are going to talk about how to implement `Provider` for more session storage structures, and you can reference in the future development. +So far, we implemented a session manager to manage global sessions in the web application and defined the `Provider` interface as the storage implementation of `Session`. In the next section, we are going to talk about how to implement `Provider` for additional session storage structures, which you will be able to reference in the future. ## Links - [Directory](preface.md) - Previous section: [Session and cookies](06.1.md) -- Next section: [Session storage](06.3.md) \ No newline at end of file +- Next section: [Session storage](06.3.md) diff --git a/en/eBook/06.3.md b/en/eBook/06.3.md index f2ac65f9..64ae232a 100644 --- a/en/eBook/06.3.md +++ b/en/eBook/06.3.md @@ -1,6 +1,6 @@ # 6.3 Session storage -We introduced session manager work principle in previous section, we defined a session storage interface. In this section, I'm going to show you an example of memory-based session storage engine that implements the interface. You can change this to others forms of session storage as well. +We introduced a simple session manager's working principles in the previous section, and among other things, we defined a session storage interface. In this section, I'm going to show you an example of a memory based session storage engine that implements this interface. You can tailor this to other forms of session storage as well. package memory @@ -115,14 +115,14 @@ We introduced session manager work principle in previous section, we defined a s } -The above example implemented a memory-based session storage mechanism, then use init() function to register this storage engine to session manager. So how to register this engine? +The above example implemented a memory based session storage mechanism. It uses its `init()` function to register this storage engine to the session manager. So how do we register this engine from our main program? import ( "github.com/astaxie/session" _ "github.com/astaxie/session/providers/memory" ) -Use import mechanism to register this engine in init() function automatically to session manager, then we use following code to initialize a session manager: +We use the blank import mechanism (which will invoke the package's `init()` function automatically) to register this engine to a session manager. We then use the following code to initialize the session manager: var globalSessions *session.Manager @@ -135,5 +135,5 @@ Use import mechanism to register this engine in init() function automatically to ## Links - [Directory](preface.md) -- Previous section: [How to use session in Go](06.2.md) -- Next section: [Prevent hijack of session](06.4.md) +- Previous section: [How to use sessions in Go](06.2.md) +- Next section: [Prevent session hijacking](06.4.md) diff --git a/en/eBook/06.4.md b/en/eBook/06.4.md index 78d01ef1..beeed381 100644 --- a/en/eBook/06.4.md +++ b/en/eBook/06.4.md @@ -1,12 +1,12 @@ -# 6.4 Prevent hijack of session +# 6.4 Preventing session hijacking -Session hijack is a broader exist serious security threaten. Clients use session id to communicate with server, and we can easily to find out which is the session id when we track the communications, and used by attackers. +Session hijacking is a common yet serious security threat. Clients use session ids for validation and other purposes when communicating with servers. Unfortunately, malicious third parties can sometimes track these communications and figure out the client session id. -In the section, we are going to show you how to hijack session in order to help you understand more about session. +In this section, we are going to show you how to hijack a session for educational purposes. -## Session hijack process +## The session hijacking process -The following code is a counter for `count` variable: +The following code is a counter for the `count` variable: func count(w http.ResponseWriter, r *http.Request) { sess := globalSessions.SessionStart(w, r) @@ -21,45 +21,45 @@ The following code is a counter for `count` variable: t.Execute(w, sess.Get("countnum")) } -The content of `count.gtpl` as follows: +The content of `count.gtpl` is as follows: Hi. Now count:{{.}} -Then we can see following content in the browser: +We can see the following content in the browser: ![](images/6.4.hijack.png?raw=true) Figure 6.4 count in browser. -Keep refreshing until the number becomes 6, and we open the cookies manager (I use chrome here), you should see following information: +Keep refreshing until the number becomes 6, then open the browser's cookie manager (I use chrome here). You should be able to see the following information: ![](images/6.4.cookie.png?raw=true) -Figure 6.5 cookies that saved in browser. +Figure 6.5 cookies saved in a browser. -This step is very important: open another browser (I use firefox here), copy URL to new browser, and open cookie simulator to crate a new cookie, input exactly the same value of cookie we saw. +This step is very important: open another browser (I use firefox here), copy the URL to the new browser, open a cookie simulator to create a new cookie and input exactly the same value as the cookie we saw in our first browser. ![](images/6.4.setcookie.png?raw=true) -Figure 6.6 Simulate cookie. +Figure 6.6 Simulate a cookie. -Refresh page, and you'll see: +Refresh the page and you'll see the following: ![](images/6.4.hijacksuccess.png?raw=true) -Figure 6.7 hijack session succeed. +Figure 6.7 hijacking the session has succeeded. -Here we see that we can hijack session between different browsers, and same thing will happen in different computers. If you click firefox and chrome in turn, you'll see they actually modify the same counter. Because HTTP is stateless, so there is no way to know the session id from firefox is simulated, and chrome is not able to know its session id has been hijacked. +Here we see that we can hijack sessions between different browsers, and actions performed in one one browser can affect the state of a page in another browser. Because HTTP is stateless, there is no way of knowing that the session id from firefox is simulated, and chrome is also not able to know that its session id has been hijacked. -## prevent session hijack +## prevent session hijacking ### cookie only and token -Through the simple example of session hijack, you should know that it's very dangerous because attackers can do whatever they want. So how can we prevent session hijack? +Through this simple example of hijacking a session, you can see that it's very dangerous because it allows attackers to do whatever they want. So how can we prevent session hijacking? -The first step is to set session id only in cookie, instead of in URL rewrite, and set httponly property of cookie to true to restrict client script to access the session id. So the cookie cannot be accessed by XSS and it's not as easy as we showed to get session id in cookie manager. +The first step is to only set session ids in cookies, instead of in URL rewrites. Also, we should set the httponly cookie property to true. This restricts client side scripts that want access to the session id. Using these techniques, cookies cannot be accessed by XSS and it won't be as easy as we showed to get a session id from a cookie manager. -The second step is to add token in every request, like we deal with repeat form in previous sections, we add a hidden field that contains token, and verify this token to prove that the request is unique. +The second step is to add a token to every request. Similar to the way we dealt with repeat forms in previous sections, we add a hidden field that contains a token. When a request is sent to the server, we can verify this token to prove that the request is unique. h := md5.New() salt:="astaxie%^7&8888" @@ -72,7 +72,7 @@ The second step is to add token in every request, like we deal with repeat form ### Session id timeout -Another solution is to add a create time for every session, and we delete the session id when it's expired and create a new one. This can prevent session hijack at some point. +Another solution is to add a create time for every session, and to replace expired session ids with new ones. This can prevent session hijacking under certain circumstances. createtime := sess.Get("createtime") if createtime == nil { @@ -82,12 +82,12 @@ Another solution is to add a create time for every session, and we delete the se sess = globalSessions.SessionStart(w, r) } -We set a value to save the create time and check if it's expired(I set 60 seconds here), this step can avoid many of session hijack. +We set a value to save the create time and check if it's expired (I set 60 seconds here). This step can often thwart session hijacking attempts. -Combine those two solutions, you can avoid most of session hijack in your web applications. In the one hand, session id changes frequently and attacker always get expired and useless session id; in the other hand, we set session id can only be passed through cookie and the cookies is httponly, so all attacks based on URL are not working. Finally, we set MaxAge=0 which means session id will not be saved in history in browsers. +Combine the two solutions above and you will be able to prevent most session hijacking attempts from succeeding. On the one hand, session ids that are frequently reset will result in an attacker always getting expired and useless session ids; on the other hand, by setting the httponly property on cookies and ensuring that session ids can only be passed via cookies, all URL based attacks are mitigated. Finally, we set `MaxAge=0` on our cookies, which means that the session ids will not be saved in the browser history. ## Links - [Directory](preface.md) - Previous section: [Session storage](06.3.md) -- Next section: [Summary](06.5.md) \ No newline at end of file +- Next section: [Summary](06.5.md) diff --git a/en/eBook/06.5.md b/en/eBook/06.5.md index 71a4ba88..45281518 100644 --- a/en/eBook/06.5.md +++ b/en/eBook/06.5.md @@ -1,9 +1,9 @@ # 6.5 Summary -In this chapter, we learned what is session and what is cookie, and the relationship between them. And because Go doesn't support session in standard library, so we designed a session manager, go through the whole processes from create session to delete session. Then we defined a interface called `Procider` which supports for all session storage structures. In section 6.3, we implemented a session manager that use memory to save data. In section 6.4, I showed you how to hijack session and the way to prevent session hijack. I hope you know all the working principles of session in order to use session by safer way. +In this chapter, we learned about the definition and purpose of sessions and cookies, and the relationship between the two. Since Go doesn't support sessions in its standard library, we also designed our own session manager. We went through the everything from creating client sessions to deleting them. We then defined an interface called `Provider` which supports all session storage structures. In section 6.3, we implemented a memory based session manager to persist client data across sessions. In section 6.4, I show you one way of hijacking a session. Then we looked at how to prevent your own sessions from being hijacked. I hope that you now understand most of the working principles behind sessions so that you're able to safely use them in your applications. ## Links - [Directory](preface.md) -- Previous section: [Prevent hijack of session](06.4.md) -- Next chapter: [Text files](07.0.md) \ No newline at end of file +- Previous section: [Prevent session hijacking](06.4.md) +- Next chapter: [Text files](07.0.md) diff --git a/en/eBook/07.0.md b/en/eBook/07.0.md index fa9c0552..d6aba41b 100644 --- a/en/eBook/07.0.md +++ b/en/eBook/07.0.md @@ -1,11 +1,11 @@ # 7 Text files -Handling text file is a big part of web development, we often need to produce or handle received text content, including strings, numbers, JSON, XML, etc. As a high performance language, Go has good support from standard library, and you'll find out that it's design just awesome, you can easily use them to deal with your text content. This chapter contains 4 sections, which gives full introduction of text processing in Go. +Handling text files is a big part of web development. We often need to produce or handle received text content, including strings, numbers, JSON, XML, etc. As a high performance language, Go has good support for this in its standard library. You'll find that these supporting libraries are just awesome, and will allow you to easily deal with any text content you may encounter. This chapter contains 4 sections, and will give you a full introduction to text processing in Go. -XML is an interactive language that is commonly used in many API, many web servers that are written by Java are using XML as standard interaction language, we will talk about XML in section 7.1. In section 7.2, we will take a look at JSON which is very popular in recent years and much more convenient than XML. In section 7.3, we are going to talk about regular expression which looks like a language that is used by aliens. In section 7.4, you will see how to use MVC model to develop applications in Go and use `template` package to use templates. In section 7.5, we'll give a introduction of operating files and folders. Finally, we will explain some string operations in Go in section 7.6. +XML is an interactive language that is commonly used in many APIs, many web servers written in Java use XML as their standard interaction language. We'll more talk about XML in section 7.1. In section 7.2, we'll take a look at JSON which has been very popular in recent years and is much more convenient than XML. In section 7.3, we are going to talk about regular expressions which (for the majority of people) looks like a language used by aliens. In section 7.4, you will see how the MVC pattern is used to develop applications in Go, and also how to use Go's `template` package for templating your views. In section 7.5, we'll introduce you to file and folder operations. Finally, we will explain some Go string operations in section 7.6. ## Links - [Directory](preface.md) - Previous Chapter: [Chapter 6 Summary](06.5.md) -- Next section: [XML](07.1.md) \ No newline at end of file +- Next section: [XML](07.1.md) diff --git a/en/eBook/07.1.md b/en/eBook/07.1.md index a46ff79d..cec4225c 100644 --- a/en/eBook/07.1.md +++ b/en/eBook/07.1.md @@ -1,10 +1,10 @@ # 7.1 XML -XML is a commonly used data communication format in web services today, it becomes more and more important role in daily development. In this section, we're going to introduce how to work with XML through standard library. +XML is a commonly used data communication format in web services. Today, it's assuming a more and more important role in web development. In this section, we're going to introduce how to work with XML through Go's standard library. -I'll not teach what is XML or something like that, please read more documentation about XML if you haven't known that. We only focus on how to encode and decode XML files. +I will not make any attempts to teach XML's syntax or conventions. For that, please read more documentation about XML itself. We will only focus on how to encode and decode XML files in Go. -Suppose you are a operation staff, and you have following XML configuration file: +Suppose you work in IT, and you have to deal with the following XML configuration file: @@ -18,15 +18,15 @@ Suppose you are a operation staff, and you have following XML configuration file -Above XML document contains two kinds of information about your server, which are server name and IP; we will use this document in our following examples. +The above XML document contains two kinds of information about your server: the server name and IP. We will use this document in our following examples. ## Parse XML -How to parse this XML document? We can use function `Unmarshal` in package `xml` to do this. +How do we parse this XML document? We can use the `Unmarshal` function in Go's `xml` package to do this. func Unmarshal(data []byte, v interface{}) error -data receives data stream from XML, v is the structure you want to output, it is a interface, which means you can convert XML to any kind of structures. Here we only talk about how to convert to `struct` because they have similar tree structures. +the `data` parameter receives a data stream from an XML source, and `v` is the structure you want to output the parsed XML to. It is an interface, which means you can convert XML to any structure you desire. Here, we'll only talk about how to convert from XML to the `struct` type since they share similar tree structures. Sample code: @@ -74,7 +74,7 @@ Sample code: fmt.Println(v) } -XML actually is a tree data structure, and we can define a almost same struct in Go, then use `xml.Unmarshal` to convert from XML to our struct object. The sample code will print following content: +XML is actually a tree data structure, and we can define a very similar structure using structs in Go, then use `xml.Unmarshal` to convert from XML to our struct object. The sample code will print the following content: {{ servers} 1 [{{ server} Shanghai_VPN 127.0.0.1} {{ server} Beijing_VPN 127.0.0.2}] @@ -87,42 +87,42 @@ XML actually is a tree data structure, and we can define a almost same struct in } -We used `xml.Unmarshal` to parse XML document to corresponding struct object, and you should see that we have something like `xml:"serverName"` in our struct. This is a feature of struct which is called `struct tag` for helping reflection. Let's see the definition of `Unmarshal` again: +We use `xml.Unmarshal` to parse the XML document to the corresponding struct object. You should see that we have something like `xml:"serverName"` in our struct. This is a feature of structs called `struct tags` for helping with reflection. Let's see the definition of `Unmarshal` again: func Unmarshal(data []byte, v interface{}) error -The first argument is XML data stream, the second argument is the type of storage, for now it supports struct, slice and string. XML package uses reflection to achieve data mapping, so all fields in v should be exported. But we still have a problem, how can it knows which field is corresponding to another one? Here is a priority level when parse data. It tries to find struct tag first, if it cannot find then get field name. Be aware that all tags, field name and XML element are case sensitive, so you have to make sure that one-one correspondence. +The first argument is an XML data stream. The second argument is storage type and supports the struct, slice and string types. Go's XML package uses reflection for data mapping, so all fields in v should be exported. However, this causes a problem: how can it know which XML field corresponds to the mapped struct field? The answer is that the XML parser parses data in a certain order. The library will try to find the matching struct tag first. If a match cannot be found then it searches through the struct field names. Be aware that all tags, field names and XML elements are case sensitive, so you have to make sure that there is a one to one correspondence for the mapping to succeed. -Go reflection mechanism allows you to use these tag information to reflect XML data to struct object. If you want to know more about reflection in Go, please read more about package documentation of struct tag and reflect. +Go's reflection mechanism allows you to use this tag information to reflect XML data to a struct object. If you want to know more about reflection in Go, please read the package documentation on struct tags and reflection. -Here are the rules when package `xml` parse XML document to struct: +Here are some rules when using the `xml` package to parse XML documents to structs: -- If the a field type is string or []byte with tag `",innerxml"`, `Unmarshal` assign raw XML data to it, like `Description` in above example: +- If the field type is a string or []byte with the tag `",innerxml"`, `Unmarshal` will assign raw XML data to it, like `Description` in the above example: Shanghai_VPN127.0.0.1Beijing_VPN127.0.0.2 -- If a field called `XMLName` and its type is `xml.Name`, then it gets element name, like `servers` in above example. -- If a field's tag contains corresponding element name, then it gets element name as well, like `servername` and `serverip` in above example. -- If a field's tag contains `",attr"`, then it gets corresponding element's attribute, like `version` in above example. -- If a field's tag contains something like `"a>b>c"`, it gets value of element c of node b of node a. +- If a field is called `XMLName` and its type is `xml.Name`, then it gets the element name, like `servers` in above example. +- If a field's tag contains the corresponding element name, then it gets the element name as well, like `servername` and `serverip` in the above example. +- If a field's tag contains `",attr"`, then it gets the corresponding element's attribute, like `version` in above example. +- If a field's tag contains something like `"a>b>c"`, it gets the value of the element c of node b of node a. - If a field's tag contains `"="`, then it gets nothing. -- If a field's tag contains `",any"`, then it gets all child elements which do not fit other rules. -- If XML elements have one or more comments, all of these comments will be added to the first field that has the tag that contains `",comments"`, this field type can be string or []byte, if this kind field does not exist, all comments are discard. +- If a field's tag contains `",any"`, then it gets all child elements which do not fit the other rules. +- If the XML elements have one or more comments, all of these comments will be added to the first field that has the tag that contains `",comments"`. This field type can be a string or []byte. If this kind of field does not exist, all comments are discard. -These rules tell you how to define tags in struct, once you understand these rules, everything as easy as the sample code. Because tags and XML elements are one-one correspondence, we can also use slice to represent multiple elements in same level. +These rules tell you how to define tags in structs. Once you understand these rules, mapping XML to structs will be as easy as the sample code above. Because tags and XML elements have a one to one correspondence, we can also use slices to represent multiple elements on the same level. -Note that all fields in struct should be exported(capitalize) in order to parse data correctly. +Note that all fields in structs should be exported (capitalized) in order to parse data correctly. ## Produce XML -What if we want to produce XML document instead of parsing it, how can we do it in Go? `xml` package provides two functions which are `Marshal` and `MarshalIndent` where the second function has indents for your XML document. Their definition as follows: +What if we want to produce an XML document instead of parsing one. How do we do this in Go? Unsurprisingly, the `xml` package provides two functions which are `Marshal` and `MarshalIndent`, where the second function automatically indents the marshalled XML document. Their definition as follows: func Marshal(v interface{}) ([]byte, error) func MarshalIndent(v interface{}, prefix, indent string) ([]byte, error) -The first argument is for storing XML data stream for both functions. +The first argument in both of these functions is for storing a marshalled XML data stream. -Let's has an example to see how it works: +Let's look at an example to see how this works: package main @@ -156,7 +156,7 @@ Let's has an example to see how it works: os.Stdout.Write(output) } -The above example prints following information: +The above example prints the following information: @@ -170,34 +170,34 @@ The above example prints following information: -As we defined before, the reason we have `os.Stdout.Write([]byte(xml.Header))` is both of function `xml.MarshalIndent` and `xml.Marshal` do not output XML header by itself, so we have to print it in order to produce XML document correctly. +As we've previously defined, the reason we have `os.Stdout.Write([]byte(xml.Header))` is because both `xml.MarshalIndent` and `xml.Marshal` do not output XML headers on their own, so we have to explicitly print them in order to produce XML documents correctly. -Here we see `Marshal` also receives v in type `interface{}`, so what are the rules when it produces XML document? +Here we can see that `Marshal` also receives a v parameter of type `interface{}`. So what are the rules when marshalling to an XML document? -- If v is a array or slice, it prints all elements like value. -- If v is a pointer, it prints content that v point to, it prints nothing when v is nil. -- If v is a interface, it deal with interface as well. -- If v is one of other types, it prints value of that type. +- If v is an array or slice, it prints all elements like a value. +- If v is a pointer, it prints the content that v is pointing to, printing nothing when v is nil. +- If v is a interface, it deal with the interface as well. +- If v is one of the other types, it prints the value of that type. -So how can it decide elements' name? It follows following rules: +So how does `xml.Marshal` decide the elements' name? It follows the proceeding rules: -- If v is a struct, it defines name in tag of XMLName. -- Field name is XMLName and type is xml.Name. +- If v is a struct, it defines the name in the tag of XMLName. +- The field name is XMLName and the type is xml.Name. - Field tag in struct. - Field name in struct. - Type name of marshal. -Then we need to figure out how to set tags in order to produce final XML document. +Then we need to figure out how to set tags in order to produce the final XML document. - XMLName will not be printed. -- Fields that have tag contains `"-"` will not be printed. -- If tag contains `"name,attr"`, it uses name as attribute name and field value as value, like `version` in above example. -- If tag contains `",attr"`, it uses field's name as attribute name and field value as value. -- If tag contains `",chardata"`, it prints character data instead of element. -- If tag contains `",innerxml"`, it prints raw value. -- If tag contains `",comment"`, it prints it as comments without escaping, so you cannot have "--" in its value. -- If tag contains `"omitempty"`, it omits this field if its value is zero-value, including false, 0, nil pointer or nil interface, zero length of array, slice, map and string. -- If tag contains `"a>b>c"`, it prints three elements where a contains b, b contains c, like following code: +- Fields that have tags containing `"-"` will not be printed. +- If a tag contains `"name,attr"`, it uses name as the attribute name and the field value as the value, like `version` in the above example. +- If a tag contains `",attr"`, it uses the field's name as the attribute name and the field value as its value. +- If a tag contains `",chardata"`, it prints character data instead of element. +- If a tag contains `",innerxml"`, it prints the raw value. +- If a tag contains `",comment"`, it prints it as a comment without escaping, so you cannot have "--" in its value. +- If a tag contains `"omitempty"`, it omits this field if its value is zero-value, including false, 0, nil pointer or nil interface, zero length of array, slice, map and string. +- If a tag contains `"a>b>c"`, it prints three elements where a contains b and b contains c, like in the following code: FirstName string `xml:"name>first"` LastName string `xml:"name>last"` @@ -207,10 +207,10 @@ Then we need to figure out how to set tags in order to produce final XML documen Xie -You may notice that struct tag is very useful when you deal with XML, as well as other data format in following sections, if you still have problems with working with struct tag, you probably should read more documentation about it before get into next section. +You may have noticed that struct tags are very useful for dealing with XML, and the same goes for the other data formats we'll be discussing in the following sections. If you still find that you have problems with working with struct tags, you should probably read more documentation about them before diving into the next section. ## Links - [Directory](preface.md) - Previous section: [Text files](07.0.md) -- Next section: [JSON](07.2.md) \ No newline at end of file +- Next section: [JSON](07.2.md) diff --git a/en/eBook/07.2.md b/en/eBook/07.2.md index dc241f95..6066b18c 100644 --- a/en/eBook/07.2.md +++ b/en/eBook/07.2.md @@ -1,26 +1,26 @@ # 7.2 JSON -JSON(JavaScript Object Notation) is a lightweight data exchange language which is based on text description, its advantages including self-descriptive, easy to understand, etc. Even though it is a sub-set of JavaScript, JSON uses different text format to become an independent language, and has some similarities with C-family languages. +JSON (JavaScript Object Notation) is a lightweight data exchange language which is based on text description. Its advantages include being self-descriptive, easy to understand, etc. Even though it is a subset of JavaScript, JSON uses a different text format, the result being that it can be considered as an independent language. JSON bears similarity to C-family languages. -The biggest difference between JSON and XML is that XML is a complete mark language, but JSON is not. JSON is smaller and faster than XML, therefore it's much easier and quicker to parse in browsers, which is an important reason that many open platforms choose to use JSON as their data exchange interface language. +The biggest difference between JSON and XML is that XML is a complete markup language, whereas JSON is not. JSON is smaller and faster than XML, therefore it's much easier and quicker to parse in browsers, which is one of the reasons why many open platforms choose to use JSON as their data exchange interface language. -Since JSON is becoming more important in web development, let's take a look at the level of support JSON in Go. Actually, the standard library has very good support for encoding and decoding JSON. +Since JSON is becoming more and more important in web development, let's take a look at the level of support Go has for JSON. You'll find that Go's standard library has very good support for encoding and decoding JSON. -Here we use JSON to represent the example in previous section: +Here we use JSON to represent the example in the previous section: {"servers":[{"serverName":"Shanghai_VPN","serverIP":"127.0.0.1"},{"serverName":"Beijing_VPN","serverIP":"127.0.0.2"}]} -The rest of this section will use this JSON data to introduce you how to operate JSON in Go. +The rest of this section will use this JSON data to introduce JSON concepts in Go. ## Parse JSON ### Parse to struct -Suppose we have JSON in above example, how can we parse this data and map to struct in Go? Go has following function to do this: +Suppose we have the JSON in the above example. How can we parse this data and map it to a struct in Go? Go provides the following function for just this purpose: func Unmarshal(data []byte, v interface{}) error -We can use this function to achieve our goal, here is a complete example: +We can use this function like so: package main @@ -45,35 +45,35 @@ We can use this function to achieve our goal, here is a complete example: fmt.Println(s) } -In above example, we defined a corresponding struct in Go for our JSON, slice for array, field name for key in JSON, but how does Go know which JSON data is for specific struct filed? Suppose we have a key called `Foo` in JSON, how to find corresponding field? +In the above example, we defined a corresponding structs in Go for our JSON, using slice for an array of JSON objects and field name as our JSON keys. But how does Go know which JSON object corresponds to which specific struct filed? Suppose we have a key called `Foo` in JSON. How do we find its corresponding field? -- First, try to find the exported field(capitalized) whose tag contains `Foo`. -- Then, try to find the field whose name is `Foo`. -- Finally, try to find something like `FOO` or `FoO` without case sensitive. +- First, Go tries to find the (capitalised) exported field whose tag contains `Foo`. +- If no match can be found, look for the field whose name is `Foo`. +- If there are still not matches look for something like `FOO` or `FoO`, ignoring case sensitivity. -You may notice that all fields that are going to be assigned should be exported, and Go only assigns fields that can be found at the same time, and ignores all the others. This is good because when you receive a very large JSON data but you only need some of them, you can easily discard. +You may have noticed that all fields that are going to be assigned should be exported, and Go only assigns fields that can be found, ignoring all others. This can be useful if you need to deal with large chunks of JSON data but you only a specific subset of it; the data you don't need can easily be discarded. ### Parse to interface -When we know what kind of JSON we're going to have, we parse JSON to specific struct, but what if we don't know? +When we know what kind of JSON to expect in advance, we can parse it to a specific struct. But what if we don't know? -We know that interface{} can be everything in Go, so it is the best container to save our unknown format JSON. JSON package uses `map[string]interface{}` and `[]interface{}` to save all kinds of JSON objects and array. Here is a list of mapping relation: +We know that an interface{} can be anything in Go, so it is the best container to save our JSON of unknown format. The JSON package uses `map[string]interface{}` and `[]interface{}` to save all kinds of JSON objects and arrays. Here is a list of JSON mapping relations: - `bool` represents `JSON booleans`, - `float64` represents `JSON numbers`, - `string` represents `JSON strings`, - `nil` represents `JSON null`. -Suppose we have following JSON data: +Suppose we have the following JSON data: b := []byte(`{"Name":"Wednesday","Age":6,"Parents":["Gomez","Morticia"]}`) -Now we parse this JSON to interface{}: +Now we parse this JSON to an interface{}: var f interface{} err := json.Unmarshal(b, &f) -The `f` stores a map, where keys are strings and values interface{}. +The `f` stores a map, where keys are strings and values are interface{}'s'. f = map[string]interface{}{ "Name": "Wednesday", @@ -84,11 +84,11 @@ The `f` stores a map, where keys are strings and values interface{}. }, } -So, how to access these data? Type assertion. +So, how do we access this data? Type assertion. m := f.(map[string]interface{}) -After asserted, you can use following code to access data: +After asserted, you can use the following code to access data: for k, v := range m { switch vv := v.(type) { @@ -108,9 +108,9 @@ After asserted, you can use following code to access data: } } -As you can see, we can parse unknown format JSON through interface{} and type assert now. +As you can see, we can parse JSON of an unknown format through interface{} and type assert now. -The above example is the official solution, but type assert is not always convenient, so I recommend one open source project called `simplejson` and launched by bitly. Here is an example of how to use this project to deal with unknown format JSON: +The above example is the official solution, but type asserting is not always convenient. So, I recommend an open source project called `simplejson`, created and maintained by by bitly. Here is an example of how to use this project to deal with JSON of an unknown format: js, err := NewJson([]byte(`{ "test": { @@ -127,15 +127,15 @@ The above example is the official solution, but type assert is not always conven i, _ := js.Get("test").Get("int").Int() ms := js.Get("test").Get("string").MustString() -It's not hard to see how convenient it is, see more information: [https://github.com/bitly/go-simplejson](https://github.com/bitly/go-simplejson). +It's not hard to see how convenient this is. Check out the repository to see more information: [https://github.com/bitly/go-simplejson](https://github.com/bitly/go-simplejson). -## Produce JSON +## Producing JSON -In many situations, we need to produce JSON data and response to clients. In Go, JSON package has a function called `Marshal` to do this job: +In many situations, we need to produce JSON data and respond to clients. In Go, the JSON package has a function called `Marshal` to do just that: func Marshal(v interface{}) ([]byte, error) -Suppose we need to produce server information list, we have following sample: +Suppose we need to produce a server information list. We have following sample: package main @@ -168,7 +168,7 @@ Output: {"Servers":[{"ServerName":"Shanghai_VPN","ServerIP":"127.0.0.1"},{"ServerName":"Beijing_VPN","ServerIP":"127.0.0.2"}]} -As you know, all fields name are capitalized, but if you want your JSON key name start with lower case, you should use `struct tag` to do this, otherwise Go will not produce data for internal fields. +As you know, all field names are capitalized, but if you want your JSON key names to start with a lower case letter, you should use `struct tag`s. Otherwise, Go will not produce data for internal fields. type Server struct { ServerName string `json:"serverName"` @@ -179,14 +179,14 @@ As you know, all fields name are capitalized, but if you want your JSON key name Servers []Server `json:"servers"` } -After this modification, we can get same JSON data as beginning. +After this modification, we can produce the same JSON data as before. -Here are some points you need to keep in mind when you try to produce JSON: +Here are some points you need to keep in mind when trying to produce JSON: -- Field tag contains `"-"` will not be outputted. -- If tag contains customized name, Go uses this instead of field name, like `serverName` in above example. -- If tag contains `omitempty`, this field will not be outputted if it is its zero-value. -- If the field type is `bool`, string, int, `int64`, etc, and its tag contains `",string"`, Go converts this field to corresponding type in JSON. +- Field tags containing `"-"` will not be outputted. +- If a tag contains a customized name, Go uses this instead of the field name, like `serverName` in the above example. +- If a tag contains `omitempty`, this field will not be outputted if it is its zero-value. +- If the field type is `bool`, string, int, `int64`, etc, and its tag contains `",string"`, Go converts this field to its corresponding JSON type. Example: @@ -215,17 +215,17 @@ Output: {"serverName":"Go \"1.0\" ","serverName2":"\"Go \\\"1.0\\\" \""} -Function `Marshal` only returns data when it was succeed, so here are some points we need to keep in mind: +The `Marshal` function only returns data when it has succeeded, so here are some points we need to keep in mind: -- JSON object only supports string as key, so if you want to encode a map, its type has to be `map[string]T`, where `T` is the type in Go. -- Type like channel, complex and function are not able to be encoded to JSON. -- Do not try to encode nested data, it led dead loop when produce JSON data. -- If the field is a pointer, Go outputs data that it points to, or outputs null if it points to nil. +- JSON only supports strings as keys, so if you want to encode a map, its type has to be `map[string]T`, where `T` is the type in Go. +- Types like channel, complex types and functions are not able to be encoded to JSON. +- Do not try to encode cyclic data, it leads to an infinite recursion. +- If the field is a pointer, Go outputs the data that it points to, or else outputs null if it points to nil. -In this section, we introduced you how to decode and encode JSON data in Go, also one third-party project called `simplejson` which is for parsing unknown format JSON. These are all important in web development. +In this section, we introduced how to decode and encode JSON data in Go. We also looked at one third-party project called `simplejson` which is for parsing JSON or unknown format. These are all useful concepts for developping web applications in Go. ## Links - [Directory](preface.md) - Previous section: [XML](07.1.md) -- Next section: [Regexp](07.3.md) \ No newline at end of file +- Next section: [Regexp](07.3.md) diff --git a/en/eBook/07.3.md b/en/eBook/07.3.md index 4ab0aa00..2d524455 100644 --- a/en/eBook/07.3.md +++ b/en/eBook/07.3.md @@ -1,24 +1,24 @@ # 7.3 Regexp -Regexp is a complicated but powerful tool for pattern match and text manipulation. Although its performance is lower than pure text match, it's more flexible. Base on its syntax, you can almost filter any kind of text from your source content. If you need to collect data in web development, it's not hard to use Regexp to have meaningful data. +Regexp is a complicated but powerful tool for pattern matching and text manipulation. Although does not perform as well as pure text matching, it's more flexible. Based on its syntax, you can filter almost any kind of text from your source content. If you need to collect data in web development, it's not hard to use Regexp to retrieve meaningful data. -Go has package `regexp` as official support for regexp, if you've already used regexp in other programming languages, you should be familiar with it. Note that Go implemented RE2 standard except `\C`, more details: [http://code.google.com/p/re2/wiki/Syntax](http://code.google.com/p/re2/wiki/Syntax). +Go has the `regexp` package, which provides official support for regexp. If you've already used regexp in other programming languages, you should be familiar with it. Note that Go implemented RE2 standard except for `\C`. For more details, follow this link: [http://code.google.com/p/re2/wiki/Syntax](http://code.google.com/p/re2/wiki/Syntax). -Actually, package `strings` does many jobs like search(Contains, Index), replace(Replace), parse(Split, Join), etc. and it's faster than Regexp, but these are simple operations. If you want to search a string without case sensitive, Regexp should be your best choice. So if package `strings` can achieve your goal, just use it, it's easy to use and read; if you need to more advanced operation, use Regexp obviously. +Go's `strings` package can actually do many jobs like searching (Contains, Index), replacing (Replace), parsing (Split, Join), etc., and it's faster than Regexp. However, these are all trivial operations. If you want to search a case insensitive string, Regexp should be your best choice. So, if the `strings` package is sufficient for your needs, just use it since it's easy to use and read; if you need to perform more advanced operations, use Regexp. -If you remember form verification we talked before, we used Regexp to verify if input information is valid there already. Be aware that all characters are UTF-8, and let's learn more about Go `regexp`! +If you recall form verification from previous sections, we used Regexp to verify the validity of user input information. Be aware that all characters are UTF-8. Let's learn more about the Go `regexp` package! ## Match -Package `regexp` has 3 functions to match, if it matches returns true, returns false otherwise. +The `regexp` package has 3 functions to match: if it matches a pattern, then it returns true, returning false otherwise. func Match(pattern string, b []byte) (matched bool, error error) func MatchReader(pattern string, r io.RuneReader) (matched bool, error error) func MatchString(pattern string, s string) (matched bool, error error) -All of 3 functions check if `pattern` matches input source, returns true if it matches, but if your Regex has syntax error, it will return error. The 3 input sources of these functions are `slice of byte`, `RuneReader` and `string`. +All of 3 functions check if `pattern` matches the input source, returning true if it matches. However if your Regex has syntax errors, it will return an error. The 3 input sources of these functions are `slice of byte`, `RuneReader` and `string`. -Here is an example to verify IP address: +Here is an example of how to verify an IP address: func IsIP(ip string) (b bool) { if m, _ := regexp.MatchString("^[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}$", ip); !m { @@ -27,7 +27,7 @@ Here is an example to verify IP address: return true } -As you can see, using pattern in package `regexp` is not that different. One more example, to verify if user input is valid: +As you can see, using pattern in the `regexp` package is not that different. Here's one more example on verifying if user input is valid: func main() { if len(os.Args) == 1 { @@ -40,13 +40,13 @@ As you can see, using pattern in package `regexp` is not that different. One mor } } -In above examples, we use `Match(Reader|Sting)` to check if content is valid, they are all easy to use. +In the above examples, we use `Match(Reader|Sting)` to check if content is valid, but they are all easy to use. ## Filter -Match mode can verify content, but it cannot cut, filter or collect data from content. If you want to do that, you have to use complex mode of Regexp. +Match mode can verify content but it cannot cut, filter or collect data from it. If you want to do that, you have to use complex mode of Regexp. -Sometimes we need to write a crawl, here is an example that shows you have to use Regexp to filter and cut data. +Let's say we need to write a crawler. Here is an example that shows when you must use Regexp to filter and cut data. package main @@ -95,7 +95,7 @@ Sometimes we need to write a crawl, here is an example that shows you have to us fmt.Println(strings.TrimSpace(src)) } -In this example, we use Compile as the first step for complex mode. It verifies if your Regex syntax is correct, then returns `Regexp` for parsing content in other operations. +In this example, we use Compile as the first step for complex mode. It verifies that your Regex syntax is correct, then returns a `Regexp` for parsing content in other operations. Here are some functions to parse your Regexp syntax: @@ -104,9 +104,9 @@ Here are some functions to parse your Regexp syntax: func MustCompile(str string) *Regexp func MustCompilePOSIX(str string) *Regexp -The difference between `ComplePOSIX` and `Compile` is that the former has to use POSIX syntax which is leftmost longest search, and the latter is only leftmost search. For instance, for Regexp `[a-z]{2,4}` and content `"aa09aaa88aaaa"`, `CompilePOSIX` returns `aaaa` but `Compile` returns `aa`. `Must` prefix means panic when the Regexp syntax is not correct, returns error only otherwise. +The difference between `ComplePOSIX` and `Compile` is that the former has to use POSIX syntax which is leftmost longest search, and the latter is only leftmost search. For instance, for Regexp `[a-z]{2,4}` and content `"aa09aaa88aaaa"`, `CompilePOSIX` returns `aaaa` but `Compile` returns `aa`. `Must` prefix means panic when the Regexp syntax is not correct, returning error otherwise. -After you knew how to create a new Regexp, let's see this struct provides what methods that help us to operate content: +Now that we know how to create a new Regexp, let's see what how the methods provided by this struct can help us to operate on content: func (re *Regexp) Find(b []byte) []byte func (re *Regexp) FindAll(b []byte, n int) [][]byte @@ -127,7 +127,7 @@ After you knew how to create a new Regexp, let's see this struct provides what m func (re *Regexp) FindSubmatch(b []byte) [][]byte func (re *Regexp) FindSubmatchIndex(b []byte) []int -These 18 methods including same function for different input sources(byte slice, string and io.RuneReader), we can simplify it by ignoring input sources as follows: +These 18 methods include identical functions for different input sources (byte slice, string and io.RuneReader), so we can really simplify this list by ignoring input sources as follows: func (re *Regexp) Find(b []byte) []byte func (re *Regexp) FindAll(b []byte, n int) [][]byte @@ -194,13 +194,13 @@ Code sample: fmt.Println(submatchallindex) } -As we introduced before, Regexp also has 3 methods for matching, they do exactly same thing as exported functions, those exported functions call these methods underlying: +As we've previously introduced, Regexp also has 3 methods for matching. They do the exact same things as the exported functions. In fact, those exported functions actually call these methods under the hood: func (re *Regexp) Match(b []byte) bool func (re *Regexp) MatchReader(r io.RuneReader) bool func (re *Regexp) MatchString(s string) bool -Next, let's see how to do displacement through Regexp: +Next, let's see how to replace strings using Regexp: func (re *Regexp) ReplaceAll(src, repl []byte) []byte func (re *Regexp) ReplaceAllFunc(src []byte, repl func([]byte) []byte) []byte @@ -209,14 +209,14 @@ Next, let's see how to do displacement through Regexp: func (re *Regexp) ReplaceAllString(src, repl string) string func (re *Regexp) ReplaceAllStringFunc(src string, repl func(string) string) string -These are used in crawl example, so we don't explain more here. +These are used in the crawling example, so we don't explain more here. -Let's take a look at explanation of `Expand`: +Let's take a look at the definition of `Expand`: func (re *Regexp) Expand(dst []byte, template []byte, src []byte, match []int) []byte func (re *Regexp) ExpandString(dst []byte, template string, src string, match []int) []byte -So how to use `Expand`? +So how do we use `Expand`? func main() { src := []byte(` @@ -232,10 +232,10 @@ So how to use `Expand`? fmt.Println(string(res)) } -At this point, you learned whole package `regexp` in Go, I hope you can understand more by studying examples of key methods, and do something interesting by yourself. +At this point, you've learned the whole `regexp` package in Go. I hope that you can understand more by studying examples of key methods, so that you can do something interesting on your own. ## Links - [Directory](preface.md) - Previous section: [JSON](07.2.md) -- Next section: [Templates](07.4.md) \ No newline at end of file +- Next section: [Templates](07.4.md) diff --git a/en/eBook/07.4.md b/en/eBook/07.4.md index bf5958bb..36236ddb 100644 --- a/en/eBook/07.4.md +++ b/en/eBook/07.4.md @@ -1,19 +1,19 @@ # 7.4 Templates -## What is template? +## What is a template? -I believe you've heard MVC design model, where Model processes data, View shows results, Controller handles user requests. As for View level. Many dynamic languages generate data by writing code in static HTML files, like JSP implements by inserting `<%=....=%>`, PHP implements by inserting ``. +Hopefully you're aware of the MVC (Model, View, Controller) design model, where models process data, views show the results and finally, controllers handle user requests. For views, many dynamic languages generate data by writing code in static HTML files. For instance, JSP is implemented by inserting `<%=....=%>`, PHP by inserting ``, etc. -The following shows template mechanism: +The following demonstrates the template mechanism: ![](images/7.4.template.png?raw=true) Figure 7.1 Template mechanism -Most of content that web applications response to clients is static, and dynamic part is usually small. For example, you need to show a list of visited users, only user name is dynamic, and style of list is always the same, so template is for reusing static content. +Most of the content that web applications respond to clients with is static, and the dynamic parts are usually very small. For example, if you need to show a list users who have visited a page, only the user name would be dynamic. The style of the list remains the same. As you can see, templates are useful for reusing static content. -## Template in Go +## Templating in Go -In Go, we have package `template` to handle templates, and use functions like `Parse`, `ParseFile`, `Execute` to load templates from text or files, then execute merge like figure 7.1. +In Go, we have the `template` package to help handle templates. We can use functions like `Parse`, `ParseFile` and `Execute` to load templates from plain text or files, then evaluate the dynamic parts, like in figure 7.1. Example: @@ -24,21 +24,21 @@ Example: t.Execute(w, user) // merge. } -As you can see, it's very easy to use template in Go, load and render data, just like in other programming languages. +As you can see, it's very easy to use, load and render data in templates in Go, just like in other programming languages. -For convenient purpose, we use following rules in examples: +For the sake of convenience, we will use the following rules in our examples: -- Use `Parse` to replace `ParseFiles` because `Parse` can test content from string, so we don't need extra files. +- Use `Parse` to replace `ParseFiles` because `Parse` can test content directly from strings, so we don't need any extra files. - Use `main` for every example and do not use `handler`. -- Use `os.Stdout` to replace `http.ResponseWriter` because `os.Stdout` also implemented interface `io.Writer`. +- Use `os.Stdout` to replace `http.ResponseWriter` since `os.Stdout` also implements the `io.Writer` interface. -## Insert data to template +## Inserting data into a template -We showed you how to parse and render templates above, let's take one step more to render data to templates. Every template is an object in Go, so how to insert fields to templates? +We've just showed you how to parse and render templates. Let's take it one step further and render data to our templates. Every template is an object in Go, so how do we insert fields to templates? ### Fields -Every field that is going to be rendered in templates in Go should be put inside of `{{}}`, `{{.}}` is shorthand for current object, it's similar to Java or C++. If you want to access fields of current object, you should use `{{.FieldName}}`. Notice that only exported fields can be accessed in templates. Here is an example: +In Go, Every field that you intend to be rendered within a template should be put inside of `{{}}`. `{{.}}` is shorthand for the current object, which is similar to its Java or C++ counterpart. If you want to access the fields of the current object, you should use `{{.FieldName}}`. Notice that only exported fields can be accessed in templates. Here is an example: package main @@ -58,7 +58,7 @@ Every field that is going to be rendered in templates in Go should be put inside t.Execute(os.Stdout, p) } -The above example outputs `hello Astaxie` correctly, but if we modify a little bit, the error comes out: +The above example outputs `hello Astaxie` correctly, but if we modify our struct a little bit, the following error emerges: type Person struct { UserName string @@ -67,16 +67,16 @@ The above example outputs `hello Astaxie` correctly, but if we modify a little b t, _ = t.Parse("hello {{.UserName}}! {{.email}}") -This part of code will not be compiled because we try to access a field that is not exported; however, if we try to use a field that does not exist, Go simply outputs empty string instead of error. +This part of the code will not be compiled because we try to access a field that has not been exported. However, if we try to use a field that does not exist, Go simply outputs an empty string instead of an error. -If you print `{{.}}` in templates, Go outputs formatted string of this object, it calls `fmt` underlying. +If you print `{{.}}` in a template, Go outputs formatted string of this object, calling `fmt` under the covers. ### Nested fields -We know how to output a field now, what if the field is an object, and it also has its fields, how to print them all in loop? We can use `{{with …}}…{{end}}` and `{{range …}}{{end}}` to do this job. +We know how to output a field now. What if the field is an object, and it also has its own fields? How do we print them all in one loop? We can use `{{with …}}…{{end}}` and `{{range …}}{{end}}` for exactly that. - `{{range}}` just like range in Go. -- `{{with}}` lets you write same object name once, and use `.` as shorthand( ***Similar to `with` in VB*** ). +- `{{with}}` lets you write the same object name once and use `.` as shorthand for it ( ***Similar to `with` in VB*** ). More examples: @@ -117,9 +117,9 @@ More examples: t.Execute(os.Stdout, p) } -### Condition +### Conditions -If you need to check conditions in templates, you can use syntax `if-else` just like you use it in Go programs. If pipeline is empty, default value of `if` is `false`. Following example shows how to use `if-else` in templates: +If you need to check for conditions in templates, you can use the `if-else` syntax just like you do in regular Go programs. If the pipeline is empty, the default value of `if` is `false`. The following example shows how to use `if-else` in templates: package main @@ -142,21 +142,21 @@ If you need to check conditions in templates, you can use syntax `if-else` just tIfElse.Execute(os.Stdout, nil) } -As you can see, it's easy to use `if-else` in you tempaltes. +As you can see, it's easy to use `if-else` in templates. -** Attention ** You CANNOT use conditional expression in if, like `.Mail=="astaxie@gmail.com"`, only boolean value is acceptable. +** Attention ** You CANNOT use conditional expressions in if, for instance `.Mail=="astaxie@gmail.com"`. Only boolean values are acceptable. ### pipelines -Unix users should be familiar with `pipe` like `ls | grep "beego"`, this command filter files and only show them that contains `beego`. One thing I like Go template is that it support pipe, anything in `{{}}` can be data of pipelines. The e-mail we used above can cause XSS attack, so how can we fix this through pipe? +Unix users should be familiar with the `pipe` operator, like `ls | grep "beego"`. This command filters files and only shows those that contain the word `beego`. One thing that I like about Go templates is that they support pipes. Anything in `{{}}` can be the data of pipelines. The e-mail we used above can render our application vulnerable to XSS attacks. How can we address this issue using pipes? {{. | html}} -We can use this way to escape e-mail body to HTML, it's quite same as we write Unix commands and convenient for using template functions. +We can use this method to escape the e-mail body to HTML. It's quite the same as writing a Unix command, and its convenient for use in template functions. -### Template variable +### Template variables -Sometimes we need to use local variables in templates, and we can use them with `with``range``if`, and its scope is between these keywords and `{{end}}`. Declare local variable example: +Sometimes we need to use local variables in templates. We can use them with the `with`, `range` and `if` keywords, and their scope is between these keywords and `{{end}}`. Here's an example of declaring a global variable: $variable := pipeline @@ -166,15 +166,15 @@ More examples: {{with $x := "output"}}{{printf "%q" $x}}{{end}} {{with $x := "output"}}{{$x | printf "%q"}}{{end}} -### Template function +### Template functions -Go uses package `fmt` to format output in templates, but sometimes we need to do something else. For example, we want to replace `@` with `at` in our e-mail address like `astaxie at beego.me`. At this point, we have to write customized function. +Go uses the `fmt` package to format output in templates, but sometimes we need to do something else. As an example scenario, let's say we want to replace `@` with `at` in our e-mail address, like `astaxie at beego.me`. At this point, we have to write a customized function. -Every template function has unique name and associates with one function in your Go programs as follows: +Every template function has a unique name and is associated with one function in your Go program as follows: type FuncMap map[string]interface{} -Suppose we have template function `emailDeal` and it associates with `EmailDealWith` in Go programs, then we use following code to register this function: +Suppose we have an `emailDeal` template function associated with its `EmailDealWith` counterpart function in our Go program. We can use the following code to register this function: t = t.Funcs(template.FuncMap{"emailDeal": EmailDealWith}) @@ -262,7 +262,7 @@ Here is a list of built-in template functions: ## Must -In package template has a function `Must` which is for checking template validation, like matching of braces, comments, variables. Let's give an example of `Must`: +The template package has a function called `Must` which is for validating templates, like the matching of braces, comments, and variables. Let's take a look at an example of `Must`: package main @@ -293,15 +293,15 @@ Output: ## Nested templates -Like we write code, some part of template is the same in several templates, like header and footer of a blog, so we can define `header`, `content` and `footer` these 3 parts. Go uses following syntax to declare sub-template: +Just like in most web applications, certain parts of templates can be reused across other templates, like the headers and footers of a blog. We can declare `header`, `content` and `footer` as sub-templates, and declare them in Go using the following syntax: {{define "sub-template"}}content{{end}} -Call by following syntax: +The sub-template is called using the following syntax: {{template "sub-template"}} -A complete example, suppose we have `header.tmpl`, `content.tmpl, `footer.tmpl` these 3 files. +Here's a complete example, supposing that we have the following three files: `header.tmpl`, `content.tmpl` and `footer.tmpl`. Main template: @@ -352,16 +352,16 @@ Code: s1.Execute(os.Stdout, nil) } -We can see that `template.ParseFiles` parses all nested templates into cache, and every template that is defined by `{{define}}` is independent, they are paralleled in something like map, where key is template name and value is body of template. Then we use `ExecuteTemplate` to execute corresponding sub-template, so that header and footer are independent and content has both of them. But if we try to execute `s1.Execute`, nothing will be outputted because there is no default sub-template available. +Here we can see that `template.ParseFiles` parses all nested templates into cache, and that every template defined by `{{define}}` is independent of one another. They are persisted in something like a map, where the template names are keys and the values are the template bodies. We can then use `ExecuteTemplate` to execute the corresponding sub-templates, so that the header and footer are independent and content contains them both. Note that if we try to execute `s1.Execute`, nothing will be outputted because there is no default sub-template available. -Templates in one set knows each other, but you have to parse them for every single set. +Templates in one set know each other, but you must parse them for every single set. ## Summary -In this section, you learned that how to combine dynamic data with templates, including print data in loop, template functions, nested templates, etc. By using templates, we can finish V part of MVC model. In following chapters, we will cover M and C parts. +In this section, you learned how to combine dynamic data with templates using techniques including printing data in loops, template functions and nested templates. By learning about templates, we can conclude discussing the V part of the MVC architecture. In the following chapters, we will cover the M and C aspects of MVC. ## Links - [Directory](preface.md) - Previous section: [Regexp](07.3.md) -- Next section: [Files](07.5.md) \ No newline at end of file +- Next section: [Files](07.5.md) diff --git a/en/eBook/07.5.md b/en/eBook/07.5.md index 8ad27a70..146bcda2 100644 --- a/en/eBook/07.5.md +++ b/en/eBook/07.5.md @@ -1,14 +1,14 @@ # 7.5 Files -File is must-have object in every single computer device, and web applications also have many usage with files. In this section, we're going to learn how to operate files in Go. +Files are must-have objects on every single computer device. It won't come as any surprise to you that web applications also make heavy use of them. In this section, we're going to learn how to operate on files in Go. ## Directories -Most of functions of file operations is in package `os`, here are some functions about directories: +In Go, most of the file operation functions are located in the `os` package. Here are some directory functions: - func Mkdir(name string, perm FileMode) error - Create directory with `name`, `perm` is permission, like 0777. + Create a directory with `name`. `perm` is the directory permissions, i.e 0777. - func MkdirAll(path string, perm FileMode) error @@ -16,11 +16,11 @@ Most of functions of file operations is in package `os`, here are some functions - func Remove(name string) error - Remove directory with `name`, it returns error if it's not directory or not empty. + Removes directory with `name`. Returns error if it's not a directory or not empty. - func RemoveAll(path string) error - Remove multiple directories according to `path`, it will not be deleted if `path` is a single path. + Removes multiple directories according to `path`. Directories will not be deleted if `path` is a single path. Code sample: @@ -45,26 +45,26 @@ Code sample: ### Create and open files -Two functions to create files: +There are two functions for creating files: - func Create(name string) (file *File, err Error) - Create file with `name` and return a file object with permission 0666 and read-writable. + Create a file with `name` and return a read-writable file object with permission 0666. - func NewFile(fd uintptr, name string) *File - Create file and return a file object. + Create a file and return a file object. -Two functions to open files: +There are also two functions to open files: - func Open(name string) (file *File, err Error) - Open file with `name` with read-only permission, it calls `OpenFile` underlying. + Opens a file called `name` with read-only access, calling `OpenFile` under the covers. - func OpenFile(name string, flag int, perm uint32) (file *File, err Error) - Open file with `name`, `flag` is open mode like read-only, read-write, `perm` is permission. + Opens a file called `name`. `flag` is open mode like read-only, read-write, etc. `perm` are the file permissions. ### Write files @@ -72,15 +72,15 @@ Functions for writing files: - func (file *File) Write(b []byte) (n int, err Error) - Write byte type content to file. + Write byte type content to a file. - func (file *File) WriteAt(b []byte, off int64) (n int, err Error) - Write byte type content to certain position of file. + Write byte type content to a specific position of a file. - func (file *File) WriteString(s string) (ret int, err Error) - Write string to file. + Write a string to a file. Code sample: @@ -146,14 +146,14 @@ Code sample: ### Delete files -Go uses same function for removing files and directories: +Go uses the same function for removing files and directories: - func Remove(name string) Error - Remove file or directory with `name`.( ***`name` ends with `/` means directory*** ) + Remove a file or directory called `name`.( *** a `name` ending with `/` signifies that it's a directory*** ) ## Links - [Directory](preface.md) - Previous section: [Templates](07.4.md) -- Next section: [Strings](07.6.md) \ No newline at end of file +- Next section: [Strings](07.6.md) diff --git a/en/eBook/07.6.md b/en/eBook/07.6.md index 88ddeff4..65068992 100644 --- a/en/eBook/07.6.md +++ b/en/eBook/07.6.md @@ -1,19 +1,20 @@ # 7.6 Strings -Almost everything we see is represented by string, so it's a very important part of web development, including user inputs, database access; also we need to split, join and convert strings in many cases. In this section, we are going to introduce packages `strings` and `strconv` in Go standard library. +On the web, almost everything we see (including user inputs, database access, etc.), is represented by strings. They are a very important part of web development. In many cases, we also need to split, join, convert and otherwise manipulate strings. In this section, we are going to introduce the `strings` and `strconv` packages from the Go standard library. ## strings -Following functions are from package `strings`, more details please see official documentation: +The following functions are from the `strings` package. See the official documentation for more details: - func Contains(s, substr string) bool - Check if string `s` contains string `substr`, returns boolean value. + Check if string `s` contains string `substr`, returns a boolean value. fmt.Println(strings.Contains("seafood", "foo")) fmt.Println(strings.Contains("seafood", "bar")) fmt.Println(strings.Contains("seafood", "")) fmt.Println(strings.Contains("", "")) + //Output: //true //false @@ -39,14 +40,14 @@ Following functions are from package `strings`, more details please see official - func Repeat(s string, count int) string - Repeat string `s` with `count` times. + Repeat string `s` `count` times. fmt.Println("ba" + strings.Repeat("na", 2)) //Output:banana - func Replace(s, old, new string, n int) string - Replace string `old` with string `new` in string `s`, `n` means replication times, if n less than 0 means replace all. + Replace string `old` with string `new` in string `s`. `n` is the number of replacements. If n is less than 0, replace all instances. fmt.Println(strings.Replace("oink oink oink", "k", "ky", 2)) fmt.Println(strings.Replace("oink oink oink", "oink", "moo", -1)) @@ -75,7 +76,7 @@ Following functions are from package `strings`, more details please see official - func Fields(s string) []string - Remove space items and split string with space in to a slice. + Remove space items and split string with space into a slice. fmt.Printf("Fields are: %q", strings.Fields(" foo bar baz ")) //Output:Fields are: ["foo" "bar" "baz"] @@ -83,9 +84,9 @@ Following functions are from package `strings`, more details please see official ## strconv -Following functions are from package `strconv`, more details please see official documentation: +The following functions are from the `strconv` package. As usual, please see official documentation for more details: -- Append series convert data to string and append to current byte slice. +- Append series, convert data to string, and append to current byte slice. package main @@ -103,7 +104,7 @@ Following functions are from package `strconv`, more details please see official fmt.Println(string(str)) } -- Format series convert other type data to string. +- Format series, convert other data types into string. package main @@ -121,7 +122,7 @@ Following functions are from package `strconv`, more details please see official fmt.Println(a, b, c, d, e) } -- Parse series convert string to other types. +- Parse series, convert strings to other types. package main @@ -158,4 +159,4 @@ Following functions are from package `strconv`, more details please see official - [Directory](preface.md) - Previous section: [Files](07.5.md) -- Next section: [Summary](07.7.md) \ No newline at end of file +- Next section: [Summary](07.7.md) diff --git a/en/eBook/07.7.md b/en/eBook/07.7.md index ddbcfc8f..7c56b019 100644 --- a/en/eBook/07.7.md +++ b/en/eBook/07.7.md @@ -1,9 +1,9 @@ # 7.7 Summary -In this chapter, we introduced some text process tools like XML, JSON, Regexp and template. XML and JSON are data exchange tools, if you can represent almost all kinds of information though these two formats. Regexp is a powerful tool for searching, replacing, cutting text content. With template, you can easily combine dynamic data with static files. These tools are all useful when you develop web application, I hope you understand more about processing and showing content. +In this chapter, we introduced some text processing tools like XML, JSON, Regexp and we also talked about templates. XML and JSON are data exchange tools. You can represent almost any kind of information using these two formats. Regexp is a powerful tool for searching, replacing and cutting text content. With templates, you can easily combine dynamic data with static files. These tools are all useful when developping web applications. I hope that you now have a better understanding of processing and showing content using Go. ## Links - [Directory](preface.md) - Previous section: [Strings](07.6.md) -- Next chapter: [Web services](08.0.md) \ No newline at end of file +- Next chapter: [Web services](08.0.md) diff --git a/en/eBook/08.0.md b/en/eBook/08.0.md index 486844be..dc040939 100644 --- a/en/eBook/08.0.md +++ b/en/eBook/08.0.md @@ -1,18 +1,18 @@ # 8 Web services -Web services allows you use formats like XML or JSON to exchange information through HTTP. For example you want to know weather of Shanghai tomorrow, share price of Apple, or commodity information in Amazon, you can write a piece of code to get information from open platforms, just like you call a local function and get its return value. +Web services allow you use formats like XML or JSON to exchange information through HTTP. For example, if you want to know the weather in Shanghai tomorrow, the current share price of Apple, or product information on Amazon, you can write a piece of code to fetch that information from open platforms. In Go, this process can be comparable to calling a local function and getting its return value. -The key point is that web services are platform independence, it allows you deploy your applications in Linux and interactive with ASP.NET applications in Windows; same thing, there is no problem of interacting with JSP in FreeBSD as well. +The key point is that web services are platform independent. This allows you to deploy your applications on Linux and interact with ASP.NET applications in Windows, for example, just like you wouldn't have a problem interacting with JSP on FreeBSD either. -REST and SOAP are most popular web services in these days: +The REST architecture and SOAP protocol are the most popular styles in which web services can be implemented these days: -- Requests of REST is pretty straight forward because it's based on HTTP. Every request of REST is actually a HTTP request, and server handle request by different logic methods. Because many developers know HTTP much already, REST is like in their back pockets. We are going to tell you how to implement REST in Go in section 8.3. -- SOAP a standard of across network information transmission and remote computer function calls, which is launched by W3C. The problem of SOAP is that its specification is very long and complicated, and it's still getting larger. Go believes that things should be simple, so we're not going to talk about SOAP. Fortunately, Go provides RPC which has good performance and easy to develop, so we will introduce how to implement RPC in Go in section 8.4. +- REST requests are pretty straight forward because it's based on HTTP. Every REST request is actually an HTTP request, and servers handle requests using different methods. Because many developers are familiar with HTTP already, REST should feel like it's already in their back pockets. We are going to show you how to implement REST in Go in section 8.3. +- SOAP is a standard for cross-network information transmission and remote computer function calls, launched by W3C. The problem with SOAP is that its specification is very long and complicated, and it's still getting longer. Go believes that things should be simple, so we're not going to talk about SOAP. Fortunately, Go provides support for RPC (Remote Procedure Calls) which has good performance and is easy to develop with, so we will introduce how to implement RPC in Go in section 8.4. -Go is the C language of 21st century, we aspire simple and performance, then we will introduce socket programming in Go in section 8.1 because many game servers are using Socket due to low performance of HTTP. Along with rapid development of HTML5, websockets are used by many page game companies, and we will talk about this more in section 8.2. +Go is the C language of the 21st century, aspiring to be simple yet performant. With these qualities in mind, we'll introduce you to socket programming in Go in section 8.1. Nowadays, many real-time servers use sockets to overcome the low performance of HTTP. Along with the rapid development of HTML5, websockets are now used by many web based game companies, and we will talk about this more in section 8.2. ## Links - [Directory](preface.md) - Previous Chapter: [Chapter 7 Summary](07.7.md) -- Next section: [Sockets](08.1.md) \ No newline at end of file +- Next section: [Sockets](08.1.md) diff --git a/en/eBook/08.1.md b/en/eBook/08.1.md index 00b7e4d7..42bb6639 100644 --- a/en/eBook/08.1.md +++ b/en/eBook/08.1.md @@ -1,48 +1,48 @@ # 8.1 Sockets -Some network application developers says that lower layer is all about programming of sockets, it's may not true in all points, but many applications are using sockets indeed. How you ever think about these questions, how browsers communicate with web servers when you are surfing on the internet? How MSN connects you and your friends? Many services like these are using sockets to transfer data, so sockets occupy an important position in network programming today, and we're going to use sockets in Go in this section. +Some network application developers say that the lower application layers are all about socket programming. This may not be true for all cases, but many modern web applications do indeed use sockets to their advantage. Have you ever wondered how browsers communicate with web servers when you are surfing the internet? Or How MSN connects you and your friends together in a chatroom, relaying each message in real-time? Many services like these use sockets to transfer data. As you can see, sockets occupy an important position in network programming today, and we're going to learn about using sockets in Go in this section. -## What is socket? +## What is a socket? -Socket is from Unix, and "everything is a file" is the basic philosophy of Unix, so everything can be operated with "open -> write/read -> close". Socket is one implementation of this philosophy, network socket is a special I/O, and socket is a kind of file descriptor. Socket has a function call for opening a socket like a file, it returns a int descriptor of socket, and it will be used in following operations like create connection, transfer data, etc. +Sockets originate from Unix, and given the basic "everything is a file" philosophy of Unix, everything can be operated on with "open -> write/read -> close". Sockets are one implementation of this philosophy. Sockets have a function call for opening a socket just like you would open a file. This returns an int descriptor of the socket which can then be used for operations like creating connections, transferring data, etc. -Here are two types of sockets that are commonly used: stream socket(SOCK_STREAM) and datagram socket(SOCK_DGRAM). Stream socket is connection-oriented, like TCP; datagram socket does not have connection, like UDP. +Two types of sockets that are commonly used are stream sockets (SOCK_STREAM) and datagram sockets (SOCK_DGRAM). Stream sockets are connection-oriented like TCP, while datagram sockets do not establish connections, like UDP. ## Socket communication -Before we understand how sockets communicate each other, we need to figure out how to make sure that every socket is unique, otherwise communication is out of question. We can give every process a PID in local, but it's not able to work in network. Fortunately, TCP/IP helps us this solve this problem. IP address of network layer is unique in network of hosts, and "protocol + port" is unique of applications in hosts, then we can use this principle to make sockets be unique. +Before we understand how sockets communicate with one another, we need to figure out how to make sure that every socket is unique, otherwise establishing a reliable communication channel is already out of the question. We can give every process a unique PID which serves our purpose locally, however that's not able to work over a network. Fortunately, TCP/IP helps us solve this problem. The IP addresses of the network layer are unique in a network of hosts, and "protocol + port" is also unique among host applications. So, we can use these principles to make sockets which are unique. ![](images/8.1.socket.png?raw=true) Figure 8.1 network protocol layers -Applications that are based on TCP/IP are using APIs of sockets for programming, and network becomes big part of our lives, that's why some people say that "everything is about socket". +Applications that are based on TCP/IP all use socket APIs in their code in one way or another. Given that networked applications are becoming more and more prevalent in the modern day, it's no wonder some developers are saying that "everything is about sockets". ## Socket basic knowledge -We know that socket has two types which are TCP socket and UDP socket, TCP and UDP are protocols, and we also need IP address and port to have unique sockets. +We know that sockets have two types, which are TCP sockets and UDP sockets. TCP and UDP are protocols and, as mentioned, we also need an IP address and port number to have a unique socket. ### IPv4 -Global internet uses TCP/IP as its protocol, where IP is the network layer and core part of TCP/IP. IPv4 means its version is 4, development to date has spent over 30 years. +The global internet uses TCP/IP as its protocol, where IP is the network layer and a core part of TCP/IP. IPv4 signifies that its version is 4; infrastructure development to date has spanned over 30 years. -The bit number of IPv4 address is 32, which means 2^32 devices are able to connect internet. Due to rapid develop of internet, IP addresses are almost out of stock in recent years. +The number of bits in an IPv4 address is 32, which means that 2^32 devices are able to uniquely connect to the internet. Due to the rapid develop of the internet, IP addresses are already running out of stock in recent years. Address format:`127.0.0.1`, `172.122.121.111`. ### IPv6 -IPv6 is the next version or next generation of internet, it's being made for solving problems of implementing IPv4. Its address has 128 bit long, so we don't need to worry about shortage of addresses, for example, you can have more than 1000 IP addresses for every square meter on the earth with IPv6. Other problems like peer to peer connection, service quality(QoS), security, multiple broadcast, etc are also be improved. +IPv6 is the next version or next generation of the internet. It's being developed for solving many of the problems inherent with IPv4. Devices using IPv6 have an address that's 128 bits long, so we'll never need to worry about a shortage of unique addresses. To put this into perspective, you could have more than 1000 IP addresses for every square meter on earth with IPv6. Other problems like peer to peer connection, service quality (QoS), security, multiple broadcast, etc., are also be improved. Address format: `2002:c0e8:82e7:0:0:0:c0e8:82e7`. ### IP types in Go -Package `net` in Go provides many types, functions and methods for network programming, the definition of IP as follows: +The `net` package in Go provides many types, functions and methods for network programming. The definition of IP as follows: type IP []byte -Functions `ParseIP(s string) IP` is for converting IP format from IPv4 to IPv6: +Functions `ParseIP(s string) IP` is for converting an IP from the IPv4 format into IPv6: package main import ( @@ -65,18 +65,18 @@ Functions `ParseIP(s string) IP` is for converting IP format from IPv4 to IPv6: os.Exit(0) } -It returns corresponding IP format for given IP address. +It returns the corresponding IP format for a given IP address. ## TCP socket -What we can do when we know how to visit a web service through a network port? As a client, we can send a request to appointed network port, and gets its feedback; as a server, we need to bind a service to appointed network port, wait for clients' requests and gives them feedback. +What can we do when we know how to visit a web service through a network port? As a client, we can send a request to an appointed network port and gets its response; as a server, we need to bind a service to an appointed network port, wait for clients' requests and supply a response. -In package `net`, it has a type called `TCPConn` for this kind of clients and servers, this type has two key functions: +In Go's `net` package, there's a type called `TCPConn` that facilitates this kind of clients/servers interaction. This type has two key functions: func (c *TCPConn) Write(b []byte) (n int, err os.Error) func (c *TCPConn) Read(b []byte) (n int, err os.Error) -`TCPConn` can be used as either client or server for reading and writing data. +`TCPConn` can be used by either client or server for reading and writing data. We also need a `TCPAddr` to represent TCP address information: @@ -85,28 +85,28 @@ We also need a `TCPAddr` to represent TCP address information: Port int } -We use function `ResolveTCPAddr` to get a `TCPAddr` in Go: +We use the `ResolveTCPAddr` function to get a `TCPAddr` in Go: func ResolveTCPAddr(net, addr string) (*TCPAddr, os.Error) -- Arguments of `net` can be one of "tcp4", "tcp6" or "tcp", where are TCP(IPv4-only), TCP(IPv6-only) or TCP(IPv4 or IPv6). -- `addr` can be domain name or IP address, like "www.google.com:80" or "127.0.0.1:22". +- Arguments of `net` can be one of "tcp4", "tcp6" or "tcp", which each signify IPv4-only, IPv6-only, and either IPv4 or IPv6, respectively. +- `addr` can be a domain name or IP address, like "www.google.com:80" or "127.0.0.1:22". ### TCP client -Go uses function `DialTCP` in package `net` to create a TCP connection, and returns a `TCPConn` object; after connection created, server has a same type connection object for this connection, and exchange data with each other. In general, clients send requests to server through `TCPConn` and get servers respond information; servers read and parse clients requests, then return feedback. This connection will not be invalid until one side close it. The function of creating connection as follows: +Go clients use the `DialTCP` function in the `net` package to create a TCP connection, which returns a `TCPConn` object; after a connection is established, the server has the same type of connection object for the current connection, and client and server can begin exchanging data with one another. In general, clients send requests to servers through a `TCPConn` and receive information from the server response; servers read and parse client requests, then return feedback. This connection will remain valid until either the client or server closes it. The function for creating a connection is as follows: func DialTCP(net string, laddr, raddr *TCPAddr) (c *TCPConn, err os.Error) -- Arguments of `net` can be one of "tcp4", "tcp6" or "tcp", where are TCP(IPv4-only), TCP(IPv6-only) or TCP(IPv4 or IPv6). -- `laddr` represents local address, set it to `nil` in most of cases. -- `raddr` represents remote address. +- Arguments of `net` can be one of "tcp4", "tcp6" or "tcp", which each signify IPv4-only, IPv6-only, and either IPv4 or IPv6, respectively. +- `laddr` represents the local address, set it to `nil` in most cases. +- `raddr` represents the remote address. -Let's write a simple example to simulate a client request to connect a web server based on HTTP. We need a simple HTTP request header: +Let's write a simple example to simulate a client requesting a connection to a server based on an HTTP request. We need a simple HTTP request header: "HEAD / HTTP/1.0\r\n\r\n" -Server respond information format may like follows: +Server response information format may look like the following: HTTP/1.0 200 OK ETag: "-9985996" @@ -151,16 +151,16 @@ Client code: } } -In above example, we use user input as argument `service` and pass to `net.ResolveTCPAddr` to get a `tcpAddr`, then we pass `tcpAddr` to function `DialTCP` to create a TCP connection `conn`, then use `conn` to send request information. Finally, use `ioutil.ReadAll` to read all content from `conn`, which is server feedback. +In the above example, we use user input as the `service` argument of `net.ResolveTCPAddr` to get a `tcpAddr`. Passing `tcpAddr` to the `DialTCP` function, we create a TCP connection, `conn`. We can then use `conn` to send request information to the server. Finally, we use `ioutil.ReadAll` to read all the content from `conn`, which contains the server response. ### TCP server -We have a TCP client now, and we also can use package `net` to write a TCP server. In server side, we need to bind service to specific inactive port, and listen to this port, so it's able to receive client requests. +We have a TCP client now. We can also use the `net` package to write a TCP server. On the server side, we need to bind our service to a specific inactive port and listen for any incoming client requests. func ListenTCP(net string, laddr *TCPAddr) (l *TCPListener, err os.Error) func (l *TCPListener) Accept() (c Conn, err os.Error) -Arguments are the same as `DialTCP`, let's implement a time sync service, port is 7777: +The arguments required here are identical to those required by the `DialTCP` function we used earlier. Let's implement a time syncing service using port 7777: package main @@ -194,9 +194,9 @@ Arguments are the same as `DialTCP`, let's implement a time sync service, port i } } -After the service started, it is waiting for clients requests. When it gets client requests, `Accept` and gives feedback of current time information. It's worth noting that when error occurs in `for` loop, it continue running instead of exiting because record error log in server is better than crash, which makes service be stable. +After the service is started, it waits for client requests. When it receives a client request, it `Accept`s it and returns a response to the client containing information about the current time. It's worth noting that when errors occur in the `for` loop, the service continues running instead of exiting. Instead of crashing, the server will record the error to a server error log. -The above code is not good enough because we didn't use goroutine to accept multiple request as same time. Let's make it better: +The above code is still not good enough, however. We didn't make use of goroutines, which would have allowed us to accept simultaneous requests. Let's do this now: package main @@ -235,9 +235,9 @@ The above code is not good enough because we didn't use goroutine to accept mult } } -Through the separation of business process to the function `handleClient`, we implemented concurrency for our service. Simply add `go` keyword to implement concurrency, it's one of reasons that goroutine is simple and powerful. +By separating out our business process from the `handleClient` function, and by using the `go` keyword, we've already implemented concurrency in our service. This is a good demonstration of the power and simplicity of goroutines. -Some people may ask: this server does not do anything meaningful, what if we need to send multiple requests for different time format in one connection, how can we do that? +Some of you may be thinking the following: this server does not do anything meaningful. What if we needed to send multiple requests for different time formats over a single connection? How would we do that? package main @@ -266,7 +266,7 @@ Some people may ask: this server does not do anything meaningful, what if we nee func handleClient(conn net.Conn) { conn.SetReadDeadline(time.Now().Add(2 * time.Minute)) // set 2 minutes timeout - request := make([]byte, 128) // set maxium request length to 128KB to prevent flood attack + request := make([]byte, 128) // set maxium request length to 128KB to prevent flood based attacks defer conn.Close() // close connection before exit for { read_len, err := conn.Read(request) @@ -297,30 +297,30 @@ Some people may ask: this server does not do anything meaningful, what if we nee } } -In this example, we use `conn.Read()` to constantly read client requests, and we cannot close connection because client may have more requests. Due to timeout of `conn.SetReadDeadline()`, it closes automatically when client has not request sent in a period of time, so it jumps of code block of `for` loop. Notice that `request` need to create max size limitation in order to prevent flood attack; clean resource after processed every request because `conn.Read()` append new content instead of rewriting. +In this example, we use `conn.Read()` to constantly read client requests. We cannot close the connection because clients may issue more than one request. Due to the timeout we set using `conn.SetReadDeadline()`, the connection closes automatically when a client has not sent a request within our allotted time period. When then expiry time has elapsed, our program breaks from the `for` loop. Notice that `request` needs to be created with a max size limitation in order to prevent flood attacks. FInally, we clean the `request` array after processing every request, since `conn.Read()` appends new content to the array instead of rewriting it. -### Control TCP connections +### Controlling TCP connections -Control functions of TCP: +Controlling TCP functions: func DialTimeout(net, addr string, timeout time.Duration) (Conn, error) -Setting timeout of connections, it's suitable for clients and servers: +Setting the timeout of connections. These are suitable for use on both clients and servers: func (c *TCPConn) SetReadDeadline(t time.Time) error func (c *TCPConn) SetWriteDeadline(t time.Time) error -Setting timeout of write/read of one connection: +Setting the write/read timeout of one connection: func (c *TCPConn) SetKeepAlive(keepalive bool) os.Error -It's worth to consider whether keep long connection between client and server, long connection can reduce overhead of creating connections, it's good for applications that need to exchange data frequently. +It's worth taking some time to think about how long you want your connection timeouts to be. Long connections can reduce the amount of overhead involved in creating connections and are good for applications that need to exchange data frequently. -More information please loop up official documentation of package `net`. +For more detailed information, just look up the official documentation for Go's `net` package . -## UDP socket +## UDP sockets -The only different between UDP socket and TCP socket is processing method for multiple requests in server side, it's because UDP does not have function like `Accept`. Other functions just replace `TCP` with `UDP`. +The only difference between a UDP socket and a TCP socket is the processing method for dealing with multiple requests on server side. This arises from the fact that UDP does not have a function like `Accept`. All of the other functions have `UDP` counterparts; just replace `TCP` with `UDP` in the functions mentioned above. func ResolveUDPAddr(net, addr string) (*UDPAddr, os.Error) func DialUDP(net string, laddr, raddr *UDPAddr) (c *UDPConn, err os.Error) @@ -402,7 +402,7 @@ UDP server code sample: ## Summary -Through description and programming of TCP and UDP sockets, we can see that Go has very good support for socket programming, and they are easy to use. Go also provides many functions for building high performance socket applications. +Through describing and coding some simple programs using TCP and UDP sockets, we can see that Go provides excellent support for socket programming, and that they are fun and easy to use. Go also provides many functions for building high performance socket applications. ## Links diff --git a/en/eBook/08.2.md b/en/eBook/08.2.md index 6399db10..57abaed3 100644 --- a/en/eBook/08.2.md +++ b/en/eBook/08.2.md @@ -1,34 +1,34 @@ -# 8.2 WebSocket +# 8.2 WebSockets -WebSocket is an important feature of HTML5, it implemented remote socket based on browsers, which allows browsers have full-duplex communication with servers. Main stream browsers like Firefox, Google Chrome and Safari have supported this feature. +WebSockets are an important feature of HTML5. It implements browser based remote sockets, which allows browsers to have full-duplex communications with servers. Main stream browsers like Firefox, Google Chrome and Safari provide support for this WebSockets. -People often use "roll poling" for instant message services before WebSocket was born, which let clients send HTTP requests in every certain period, then server returns latest data to clients. This requires clients to keep sending a lot of requests and take up a large number of bandwidth. +People often used "roll polling" for instant messaging services before WebSockets were born, which allow clients to send HTTP requests periodically. The server then returns the latest data to clients. The downside to this method is that it requires clients to keep sending many requests to the server, which can consume a large amount of bandwidth. -WebSocket uses a kind of special header to reduce handshake action between browsers and servers to only once, and create a connection. This connection will remain active, you can use JavaScript to write or read data from this the connection, as in the use of a conventional TCP socket. It solves the problem of web real-time development, and has following advantages over traditional HTTP: +WebSockets use a special kind of header that reduces the number of handshakes required between browser and server to only one, for establishing a connection. This connection will remain active throughout its lifetime, and you can use JavaScript to write or read data from this connection, as in the case of a conventional TCP sockets. It solves many of the headache involved with real-time web development, and has the following advantages over traditional HTTP: -- Only one TCP connection for a singe web client. +- Only one TCP connection for a single web client. - WebSocket servers can push data to web clients. -- More lightweight header to reduce data transmission. +- Lightweight header to reduce data transmission overhead. -WebSocket URL starts with ws:// or wss://(SSL). The following picture shows the communication process of WebSocket, where a particular HTTP header was sent to server for handshake, then servers or clients are able to send or receive data through JavaScript according to some kind of socket, this socket can be used by the event handler to receive data asynchronously. +WebSocket URLs begin with ws:// or wss://(SSL). The following figure shows the communication process of WebSockets. A particular HTTP header is sent to the server as part of the handshaking protocol and the connection is established. Then, servers or clients are able to send or receive data through JavaScript via WebSocket. This socket can then be used by an event handler to receive data asynchronously. ![](images/8.2.websocket.png?raw=true) -Figure 8.2 WebSocket principle. +Figure 8.2 WebSocket principl -## WebSocket principle +## WebSocket principles -WebSocket protocol is quite simple, after the adoption of the first handshake, the connection is established successfully. Subsequent communication data are all begin with "\x00" and ends with "\xFF". Clients will not see these two parts because WebSocket will break off both ends and gives raw data automatically. +The WebSocket protocol is actually quite simple. After successfully completing the initial handshake, a connection is established. Subsequent data communications will all begin with "\x00" and end with "\xFF". This prefix and suffix will be visible to clients because the WebSocket will break off both end, yielding the raw data automatically. -WebSocket connection are requested by browsers and responded by servers, then the connection is established, this process is often called "handshake". +WebSocket connections are requested by browsers and responded to by servers, after which the connection is established. This process is often called "handshaking". -Consider the following requests and feedback: +Consider the following requests and responses: ![](images/8.2.websocket2.png?raw=true) Figure 8.3 WebSocket request and response. -"Sec-WebSocket-key" is generated randomly, as you may guess, this is encoded by base64. Servers need to append this key to a fixed string after accepted: +"Sec-WebSocket-key" is generated randomly, as you may have already guessed, and it's base64 encoded. Servers need to append this key to a fixed string after accepting a request: 258EAFA5-E914-47DA-95CA-C5AB0DC85B11 @@ -36,21 +36,21 @@ Suppose we have `f7cb4ezEAl6C3wRaU6JORA==`, then we have: f7cb4ezEAl6C3wRaU6JORA==258EAFA5-E914-47DA-95CA-C5AB0DC85B11 -Use sha1 to compute binary value and use base64 to encode it, then we have: +Use sha1 to compute the binary value and use base64 to encode it. We will then we have: rE91AJhfC+6JdVcVXOGJEADEJdQ= -Use this as value of `Sec-WebSocket-Accept` for respond header. +Use this as the value of the `Sec-WebSocket-Accept` response header. ## WebSocket in Go -Go standard library does not support WebSocket, but package `websocket`, which is the sub-package of `go.net` and maintained by official support it. +The Go standard library does not support WebSockets. However the `websocket` package, which is a sub-package of `go.net` does, and is officially maintained and supported. Use `go get` to install this package: go get code.google.com/p/go.net/websocket -WebSocket has client and server sides, let's see a simple example: user input information, client sends content to server through WebSocket; server pushes information back up client. +WebSockets have both client and server sides. Let's see a simple example where a user inputs some information on the client side and sends it to the server through a WebSocket, followed by the server pushing information back to the client. Client code: @@ -95,12 +95,12 @@ Client code: -As you can see, JavaScript is very easy to write in client side, and use corresponding function establish a connection. Event `onopen` triggered after handshake to tell client that connection was created successfully. Client bindings four events: +As you can see, it's very easy to use the client side JavaScript functions to establish a connection. The `onopen` event gets triggered after successfully completing the aforementioned handshaking process. It tells the client that the connection has been created successfully. Clients attempting to open a connection typically bind to four events: -- 1)onopen: triggered after connection was established. -- 2)onmessage: triggered after received message. -- 3)onerror: triggered after error occurred. -- 4)onclose: triggered after connection closed. +- 1)onopen: triggered after connection has been established. +- 2)onmessage: triggered after receiving a message. +- 3)onerror: triggered after an error has occurred.. +- 4)onclose: triggered after the connection has closed. Server code: @@ -144,13 +144,13 @@ Server code: } } -When client `Send` user input information, server `Receive` it, and use `Send` to return feedback. +When a client `Send`s user input information, the server `Receive`s it, and uses `Send` once again to return a response. ![](images/8.2.websocket3.png?raw=true) Figure 8.4 WebSocket server received information. -Through the example above we see that the client and server side implementation of WebSocket are very convenient. We can use package `net` directly in Go. Now with rapid develop of HTML5, I think WebSocket will be much more important in web development, we need to reserve this knowledge. +Through the example above, we can see that the client and server side implementation of WebSockets is very convenient. We can use the `net` package directly in Go. With the rapid development of HTML5, I think that WebSockets will take on a much more important role in modern day web development; we should all be at least a little bit familiar with them. ## Links diff --git a/en/eBook/08.3.md b/en/eBook/08.3.md index 801d119e..3323135f 100644 --- a/en/eBook/08.3.md +++ b/en/eBook/08.3.md @@ -1,46 +1,51 @@ # 8.3 REST -RESTful is the most popular software architecture on the internet today, due to its clear, strict standard, easy to understand and expand, more and more websites are based on it. In this section, we are going to know what it really is and how to use this architecture in Go. +REST is the most popular software architecture on the internet today because it is founded on well defined, strict standards and it's easy to understand and expand. mOre and more websites are basing their designs on to top of it. In this section, we are going to have a close look at implementing the REST architecture in Go and (hopefully) learn how to leverage it to our benefit. ## What is REST? -The first declaration of the concept of REST(REpresentational State Transfer) was in 2000 in Roy Thomas Fielding's doctoral dissertation, who is the co-founder of HTTP. It's a architecture constraints and principles, anything implemented this architecture we call them RESTful. +The first declaration of the concept of REST (REpresentational State Transfer) was in the year 2000 in Roy Thomas Fielding's doctoral dissertation, who is also just happens to be the co-founder of the HTTP protocol. It specifies the architecture's constraints and principles and anything implemented with architecture can be called a RESTful system. -Before we understand what is REST, we need to cover following concepts: +Before we understand what REST is, we need to cover the following concepts: - Resources - REST is the Presentation Layer State Transfer, where presentation layer is actually resource presentation layer. + REST is the Presentation Layer State Transfer, where the presentation layer is actually the resource presentation layer. - So what are resources? A picture, a document or a video, etc. These can all be resources and located by URI. + So what are resources? Pictures, documents or videos, etc., are all examples of resources and can be located by URI. - Representation - Resources are specific entity information, it can be showed with variety of ways in presentation layer. For instances, a TXT document can be represented as HTML, JSON, XML, etc; a image can be represented as jpg, png, etc. + Resources are specific information entities that can be shown in a variety of ways within the presentation layer. For instance, a TXT document can be represented as HTML, JSON, XML, etc; an image can be represented as jpg, png, etc. - Use URI to identify a resource, but how to determine its specific manifestations of it? You should use Accept and Content-Type in HTTP request header, these two fields are the description of presentation layer. + URIs are used to identify resources, but how do we determine its specific manifestations? You should the Accept and Content-Type in an HTTP request header; these two fields describe the presentation layer. - State Transfer - An interactive process happens between client and server when you visit a website. In this process, certain data related to the state change should be saved; however, HTTP is stateless, so we need to save these data on the server side. Therefore, if the client wants to change the data and inform the server-side state changes, it has to use some way to tell server. + An interactive process is initiated between client and server each time you visit any page of a website. During this process, certain data related to the current page state need to be saved. However, you'll recall that HTTP is a stateless protocol! It's obvious that we need to save this client state on our server side. It follows that if a client modifies some data and wants to persist the changes, there must be a way to inform the server side about the new state. - Most of time, the client informs server through HTTP. Specifically, it has four operations: GET, POST, PUT, DELETE, where GET to obtain resources, POST to create or update resources, PUT to update resources and DELETE to delete resources. + Most of the time, clients inform servers of state changes using HTTP. They have four operations with which to do this: -In conclusion of above explanations: + -GET is used to obtain resources + -POSTs is used to create or update resources + -PUT updates resources + -DELETE deletes resources -- (1)Every URI reresented a kind of resource. -- (2)A representation layer for transferring resources between clients and servers. -- (3)Clients use four operation of HTTP to operation resources to implement "Presentation Layer State Transfer". +To summarize the above: -The most important principle of web applications that implement REST is that interactive between clients and servers are stateless, and every request should include all needed information. If the server restart at anytime, clients should not get notification. In addition, requests can be responded by any server of same service, which is good for cloud computing. What's more, because it's stateless, clients can cache data for performance improvement. +- (1)Every URI reresents a resource. +- (2)There is a representation layer for transferring resources between clients and servers. +- (3)Clients use four HTTP methods to implement "Presentation Layer State Transfer", allowing them to operate on remote resources. -Another important principle of REST is system delamination, which means components have no way to have direct interaction with components in other layers. This can limit system complexity and improve the independence of the underlying. +The most important principle of web applications that implement REST is that the interaction between clients and servers are stateless; every request should encapsulate all of the required information. Servers should be able to restart at anytime without the clients being notified. In addition, requests can be responded by any server of the same service, which is ideal for cloud computing. Lastly, because it's stateless, clients can cache data for improving performance. + +Another important principle of REST is system delamination, which means that components in one layer have no way of interacting directly with components in other layers. This can limit system complexity and encourage independence in the underlying components. ![](images/8.3.rest2.png?raw=true) Figure 8.5 REST architecture -When the constraint condition of REST apply to the whole application, it can be extended to have huge amounts of clients. It also reduced interactive delay between clients and servers, simplified system architecture, improved visibility of sub-systems interaction. +When RESTful constraints are judiciously abided by, web applications can be scaled to accommodate massive numbers of clients. Using the REST architecture can also help reduce delays between clients and servers, simplify system architecture and improve the visibility of sub-system end points. ![](images/8.3.rest.png?raw=true) @@ -48,18 +53,20 @@ Figure 8.6 REST's expansibility. ## RESTful implementation -Go doesn't have direct support for REST, but because RESTful is HTTP-based, so we can use package `net/http` to achieve them own. Of course we have to do some modification in order to implement REST. REST uses different methods to handle corresponding resources, many existed applications are claiming to be RESTful, in fact, they didn't not really realize REST. I'm going to put these applications into several levels depends on the implementation of methods. +Go doesn't have direct support for REST, but since RESTful web applications are all HTTP-based, we can use the `net/http` package to implement it on our own. Of course, we will first need to make some modifications before we are able to fully implement REST. + +REST uses different methods to handle resources, depending on the interaction that's required with that resource. Many existing applications claim to be RESTful but they do not actually implement REST. I'm going to categorize these applications into several levels depends on which HTTP methods they implement. ![](images/8.3.rest3.png?raw=true) Figure 8.7 REST's level. -Above picture shows three levels that are implemented in current REST, we may not follow all the rules of REST when we develop our applications because sometimes its rules are not fit for all possible situations. RESTful uses every single HTTP method including `DELETE` and `PUT`, but in many cases, HTTP clients can only send `GET` and `POST` requests. +The picture above shows three levels that are currently implemented in REST. You may not choose to follow all the rules and constraints of REST when developping your own applications because sometimes its rules are not a good fit for all situations. RESTful web applications use every single HTTP method including `DELETE` and `PUT`, but in many cases, HTTP clients can only send `GET` and `POST` requests. -- HTML standard allows clients send `GET` and `POST` requests through links and forms, it's not possible to send `PUT` or `DELETE` requests without AJAX support. -- Some firewalls intercept `PUT` and `DELETE` requests, clients have to use POST in order to implement them. RESTful services in charge of finding original HTTP methods and restore them. +- HTML standard allows clients send `GET` and `POST` requests through links and forms. It's not possible to send `PUT` or `DELETE` requests without AJAX support. +- Some firewalls intercept `PUT` and `DELETE` requests and clients have to use POST in order to implement them. Fully RESTful services are in charge of finding the original HTTP methods and restoring them. -We now can simulate `PUT` and `DELETE` by adding hidden field `_method` in POST requests, but you have to convert in your servers before processing them. My applications are using this way to implement REST interfaces; sure you can easily implement standard RESTful in Go as following example: +We can simulate `PUT` and `DELETE` requests by adding a hidden `_method` field in our POST requests, however these requests must be converted on the server side before they are processed. My personal applications use this workflow to implement REST interfaces. Standard RESTful interfaces are easily implemented in Go, as the following example demonstrates: package main @@ -103,11 +110,11 @@ We now can simulate `PUT` and `DELETE` by adding hidden field `_method` in POST http.ListenAndServe(":8088", nil) } -This sample shows you have to write a REST application. Our resources are users, and we use different functions for different methods. Here we imported a third-party package `github.com/drone/routes`, we talked about how to implement customized router in previous chapters; this package implemented very convenient router mapping rules, and it's good for implementing REST architecture. As you can see, REST requires you have different logic process for different methods of same resources. +This sample code shows you how to write a very basic REST application. Our resources are users, and we use different functions for different methods. Here, we imported a third-party package called `github.com/drone/routes`. We've already covered how to implement a custom router in previous chapters -the `drone/routes` package implements some very convenient router mapping rules that make it very convenient for implementing RESTful architecture. As you can see, REST requires you to implement different logic for different HTTP methods of the same resource. ## Summary -REST is a kind of architecture style, it learnt successful experiences from WWW: stateless, centered on resources, fully used HTTP and URI protocols, provides unified interfaces. These superiority let REST become more popular web services standard. In a sense, by emphasizing the URI and the early Internet standards such as HTTP, REST is a large application Web-server era before the return. Currently Go For REST support is still very simple, by implementing a custom routing rules, we can think that a different method to achieve different handle, thus achieving a REST architecture. +REST is a style of web architecture, building on past successful experiences with WWW: statelessness, resource-centric, full use of HTTP and URI protocols and the provision of unified interfaces. These superior design considerations has allowed REST to become the most popular web services standard. In a sense, by emphasizing the URI and leveraging early Internet standards such as HTTP, REST has paved the way for large and scalable web applications. Currently, the support that Go has For REST is still very basic. However, by implementing custom routing rules and different request handlers for each type of HTTP request, we can achieve RESTful architecture in our Go webapps. ## Links diff --git a/en/eBook/08.4.md b/en/eBook/08.4.md index 9e252905..2259d222 100644 --- a/en/eBook/08.4.md +++ b/en/eBook/08.4.md @@ -1,25 +1,25 @@ # 8.4 RPC -In previous sections we talked about how to write network applications based on Sockets and HTTP, we learned that both of them are using "information exchange" model, which clients send requests and servers response. This kind of data exchange are based on certain format so both sides are able to understand. However, many independence applications do not use this model, but call services just like call normal functions. +In previous sections we talked about how to write network applications based on Sockets and HTTP. We learned that both of them use the "information exchange" model, in which clients send requests and servers respond to them. This kind of data exchange is based on a specific format so that both sides are able to communicate with one another. However, many independent applications do not use this model, but instead call services just like they would call normal functions. -RPC was intended to achieve the function call mode networking. Clients like calling native functions, and then packaged these parameters after passing through the network to the server, the server unpacked process execution, and executes the results back to the client. +RPC was intended to be the function call mode for networked systems. Clients execute RPCs like they call native functions, except they package the function parameters and send them through the network to the server. The server can then unpack these parameters and process the request, executing the results back to the client. -In computer science, a remote procedure call (RPC) is an inter-process communication that allows a computer program to cause a subroutine or procedure to execute in another address space (commonly on another computer on a shared network) without the programmer explicitly coding the details for this remote interaction. That is, the programmer writes essentially the same code whether the subroutine is local to the executing program, or remote. When the software in question uses object-oriented principles, RPC is called remote invocation or remote method invocation. +In computer science, a remote procedure call (RPC) is a type of inter-process communication that allows a computer program to cause a subroutine or procedure to execute in another address space (commonly on another computer on a shared network) without the programmer explicitly coding the details for this remote interaction. That is, the programmer writes essentially the same code whether the subroutine is local to the executing program, or remote. When the software in question uses object-oriented principles, RPC is called remote invocation or remote method invocation. ## RPC working principle ![](images/8.4.rpc.png?raw=true) -Figure 8.8 RPC working principle. +Figure 8.8 RPC working principle -Normally, a RPC call from the client to the server has following ten steps: +Normally, an RPC call from client to server has the following ten steps: - 1. Call the client handle, execute transfer arguments. - 2. Call local system kernel to send network messages. - 3. Send messages to remote hosts. - 4. The server receives handle and arguments. - 5. Execute remote processes. -- 6. Return execute result to corresponding handle. +- 6. Return execution result to corresponding handle. - 7. The server handle calls remote system kernel. - 8. Messages sent back to local system kernel. - 9. The client handle receives messages from system kernel. @@ -27,22 +27,22 @@ Normally, a RPC call from the client to the server has following ten steps: ## Go RPC -Go has official support for RPC in standard library with three levels which are TCP, HTTP and JSON RPC. Note that Go RPC is not like other traditional RPC systems, it requires you to use Go applications on both sides of clients and servers because it encodes content through Gob. +Go has official support for RPC in its standard library on three levels, which are TCP, HTTP and JSON RPC. Note that Go RPC is not like other traditional RPC systems. It requires you to use Go applications on both client and server sides because it encodes content using Gob. -Functions of Go RPC have to follow following rules for remote access, otherwise corresponding calls will be ignored. +Functions of Go RPC have must abide by the following rules for remote access, otherwise the corresponding calls will be ignored. -- Functions are exported(capitalize). +- Functions are exported (capitalize). - Functions have to have two arguments with exported types. -- The first argument is for receiving from the client, and the second one has to be pointer type and is for replying to the client. +- The first argument is for receiving from the client, and the second one has to be a pointer and is for replying to the client. - Functions have to have a return value of error type. For example: func (t *T) MethodName(argType T1, replyType *T2) error -Where T, T1 and T2 must be able to encoded by package `encoding/gob`. +Where T, T1 and T2 must be able to be encoded by the `package/gob` package. -Any kind of RPC have to through network to transfer data, Go RPC can either use HTTP or TCP, the benefits of using HTTP is that you can reuse some function in package `net/http`. +Any kind of RPC has to go through a network to transfer data. Go RPC can either use HTTP or TCP. The benefits of using HTTP is that you can reuse some functions from the `net/http` package. ### HTTP RPC @@ -144,17 +144,17 @@ Client side code: } -We compile the client and the server side code separately, start server and start client, then you'll have something similar as follows after you input some data. +We compile the client and the server side code separately then start the server and client. You'll then have something similar as follows after you input some data. $ ./http_c localhost Arith: 17*8=136 Arith: 17/8=2 remainder 1 -As you can see, we defined a struct for return type, we use it as type of function argument in server side, and use as type of the second and third arguments in the client `client.Call`. This call is very important, it has three arguments, where the first one the name of function that is going to be called, and the second is the argument you want to pass, the last one is the return value(pointer type). So far we see that it's easy to implement RPC in Go. +As you can see, we defined a struct for the return type. We use it as type of function argument on the server side, and as the type of the second and third arguments on the client `client.Call`. This call is very important. It has three arguments, where the first one is the name of the function that is going to be called, the second is the argument you want to pass, and the last one is the return value (of pointer type). So far we see that it's easy to implement RPC in Go. ### TCP RPC -Let's try the RPC that is based on TCP, here is the serer side code: +Let's try the RPC that is based on TCP, here is the server side code: package main @@ -218,9 +218,9 @@ Let's try the RPC that is based on TCP, here is the serer side code: } } -The different between HTTP RPC and TCP RPC is that we have to control connections by ourselves if we use TCP RPC, then pass connections to RPC for processing. +The difference between HTTP RPC and TCP RPC is that we have to control connections by ourselves if we use TCP RPC, then pass connections to RPC for processing. -As you may guess, this is a blocking pattern application, you are free to use goroutine to extend this application for more advanced experiment. +As you may have guessed, this is a blocking pattern. You are free to use goroutines to extend this application as a more advanced experiment. The client side code: @@ -270,11 +270,11 @@ The client side code: } -The only difference in client side code is that HTTP client uses DialHTTP where TCP client uses Dial(TCP). +The only difference in the client side code is that HTTP clients use DialHTTP whereas TCP clients use Dial(TCP). ### JSON RPC -JSON RPC encodes data to JSON instead of gob, let's see an example of Go JSON RPC server side code sample: +JSON RPC encodes data to JSON instead of gob. Let's see an example of a Go JSON RPC on the server: package main @@ -339,7 +339,7 @@ JSON RPC encodes data to JSON instead of gob, let's see an example of Go JSON RP } } -JSON RPC is based on TCP, it hasn't support HTTP yet. +JSON RPC is based on TCP and doesn't support HTTP yet. The client side code: @@ -391,7 +391,7 @@ The client side code: ## Summary -Go has good support of HTTP, TPC, JSON RPC implementation, we can easily develop distributed web applications; however, it is regrettable that Go hasn't support for SOAP RPC which some third-party packages did it on open source. +Go has good support for HTTP, TPC and JSON RPC implementation which allow us to easily develop distributed web applications; however, it is regrettable that Go doesn't have built-in support for SOAP RPC, although some open source third-party packages do offer this. ## Links diff --git a/en/eBook/08.5.md b/en/eBook/08.5.md index 76122c4e..560e9469 100644 --- a/en/eBook/08.5.md +++ b/en/eBook/08.5.md @@ -1,8 +1,8 @@ # 8.5 Summary -In this chapter, I introduced you several main stream web application development model. In section 8.1, I described the basic networking programming: Socket programming. Because the direction of the network being rapid evolution, and the Socket is the cornerstone of knowledge of this evolution, you must be mastered as a developer. In section 8.2, I described HTML5 WebSocket, the increasingly popular feature, the server can push messages through it, simplified the polling mode of AJAX. In section 8.3, we implemented a simple RESTful application, which is particularly suited to the development of network API; due to rapid develop of mobile applications, I believe it will be a trend. In section 8.4, we learned about Go RPC. +In this chapter, I introduced you to several mainstream web application development models. In section 8.1, I described the basics of network programming sockets. Because of the rapid evolution of network technology and infrastructure, and given that the Socket is the cornerstone of these changes, you must master the concepts behind socket programming in order to be a competent web developer. In section 8.2, I described HTML5 WebSockets which support full-duplex communications between client and server and eliminate the need for polling with AJAX. In section 8.3, we implemented a simple application using the REST architecture, which is particularly suitable for the development of network APIs; due to the rapid rise of mobile applications, I believe that RESTful APIs will be an ongoing trend. In section 8.4, we learned about Go RPCs. -Go provides good support above four kinds of development methods. Note that package `net` and its sub-packages is the place where network programming tools of Go are. If you want more in-depth understanding of the relevant implementation details, you should try to read source code of those packages. +Go provides excellent support for the four kinds of development methods mentioned above. Note that the `net` package and its sub-packages is the place where Go's network programming tools Go reside. If you want a more in-depth understanding of the relevant implementation details, you should try reading the source code of those packages. ## Links