|
@ -25,7 +25,7 @@ |
|
|
</code></pre> |
|
|
</code></pre> |
|
|
<p>As a starting point our |
|
|
<p>As a starting point our |
|
|
<code>main.go</code> file looks like this:</p> |
|
|
<code>main.go</code> file looks like this:</p> |
|
|
<pre><code> package main |
|
|
|
|
|
|
|
|
<pre class="prettyprint"><code class="language-go"> package main |
|
|
|
|
|
|
|
|
import ( |
|
|
import ( |
|
|
"fmt" |
|
|
"fmt" |
|
@ -42,25 +42,25 @@ |
|
|
<code>http.HandleFunc</code> |
|
|
<code>http.HandleFunc</code> |
|
|
</a> method.</p> |
|
|
</a> method.</p> |
|
|
<p>It is very simple to use and its signature is easy to understand.</p> |
|
|
<p>It is very simple to use and its signature is easy to understand.</p> |
|
|
<pre><code> func HandleFunc(pattern string, handler func(ResponseWriter, *Request)) |
|
|
|
|
|
|
|
|
<pre class="prettyprint"><code class="language-go"> func HandleFunc(pattern string, handler func(ResponseWriter, *Request)) |
|
|
</code></pre> |
|
|
</code></pre> |
|
|
<p>Which basically means, |
|
|
<p>Which basically means, |
|
|
<code>http.HandleFunc("/url", routingFunction)</code> where |
|
|
<code>http.HandleFunc("/url", routingFunction)</code> where |
|
|
<code>routingFunction</code> looks like this:</p> |
|
|
<code>routingFunction</code> looks like this:</p> |
|
|
<pre><code> func routingFunction(w http.ResponseWriter, req *http.Request) { |
|
|
|
|
|
|
|
|
<pre class="prettyprint"><code class="language-go"> func routingFunction(w http.ResponseWriter, req *http.Request) { |
|
|
fmt.Fprint(w, "Hello HTTP") |
|
|
fmt.Fprint(w, "Hello HTTP") |
|
|
} |
|
|
} |
|
|
</code></pre> |
|
|
</code></pre> |
|
|
<p>With |
|
|
<p>With |
|
|
<code>fmt.Fprint()</code> we can pass an |
|
|
|
|
|
<code>http.ResponseWriter</code> and a message to display. Our browser will now look like this when we visit the |
|
|
|
|
|
<code>/url</code> endpoint.</p> |
|
|
|
|
|
|
|
|
<code class="prettyprint">fmt.Fprint()</code> we can pass an |
|
|
|
|
|
<code class="prettyprint">http.ResponseWriter</code> and a message to display. Our browser will now look like this when we visit the |
|
|
|
|
|
<code class="prettyprint">/url</code> endpoint.</p> |
|
|
<p> |
|
|
<p> |
|
|
<img src="https://leviolson.com/images/step2-browser-output.png" alt="Browser Output for Step 2 - Hello HTTP"> |
|
|
<img src="https://leviolson.com/images/step2-browser-output.png" alt="Browser Output for Step 2 - Hello HTTP"> |
|
|
</p> |
|
|
</p> |
|
|
<p>Here is what |
|
|
<p>Here is what |
|
|
<code>main.go</code> looks like at this point:</p> |
|
|
|
|
|
<pre><code> package main |
|
|
|
|
|
|
|
|
<code class="prettyprint">main.go</code> looks like at this point:</p> |
|
|
|
|
|
<pre class="prettyprint"><code class="language-go"> package main |
|
|
|
|
|
|
|
|
import ( |
|
|
import ( |
|
|
"fmt" |
|
|
"fmt" |
|
@ -83,13 +83,13 @@ |
|
|
<p>So let's add a |
|
|
<p>So let's add a |
|
|
<code>NotFound</code> page when we don't match a pattern in |
|
|
<code>NotFound</code> page when we don't match a pattern in |
|
|
<code>HandleFunc</code>. It's as simple as:</p> |
|
|
<code>HandleFunc</code>. It's as simple as:</p> |
|
|
<pre><code> func notFound(w http.ResponseWriter, req *http.Request) { |
|
|
|
|
|
|
|
|
<pre class="prettyprint"><code class="language-go"> func notFound(w http.ResponseWriter, req *http.Request) { |
|
|
http.NotFound(w, req) |
|
|
http.NotFound(w, req) |
|
|
} |
|
|
} |
|
|
</code></pre> |
|
|
</code></pre> |
|
|
<p>Here is what |
|
|
<p>Here is what |
|
|
<code>main.go</code> looks like after that:</p> |
|
|
<code>main.go</code> looks like after that:</p> |
|
|
<pre><code> package main |
|
|
|
|
|
|
|
|
<pre class="prettyprint"><code class="language-go"> package main |
|
|
|
|
|
|
|
|
import ( |
|
|
import ( |
|
|
"fmt" |
|
|
"fmt" |
|
@ -124,7 +124,7 @@ |
|
|
<code>:id</code> is an identifier used to get the user profile from our persistance layer (i.e. our database).</p> |
|
|
<code>:id</code> is an identifier used to get the user profile from our persistance layer (i.e. our database).</p> |
|
|
<p>We'll start by creating a new method for this GET request called |
|
|
<p>We'll start by creating a new method for this GET request called |
|
|
<code>userProfile</code>:</p> |
|
|
<code>userProfile</code>:</p> |
|
|
<pre><code> func userProfile(w http.ResponseWriter, req *http.Request) { |
|
|
|
|
|
|
|
|
<pre class="prettyprint"><code class="language-go"> func userProfile(w http.ResponseWriter, req *http.Request) { |
|
|
userID := req.URL.Path[len("/user/"):] |
|
|
userID := req.URL.Path[len("/user/"):] |
|
|
fmt.Fprintf(w, "User Profile: %q", userID) |
|
|
fmt.Fprintf(w, "User Profile: %q", userID) |
|
|
} |
|
|
} |
|
@ -140,7 +140,7 @@ |
|
|
</p> |
|
|
</p> |
|
|
<p>Let's add this new route in our |
|
|
<p>Let's add this new route in our |
|
|
<code>main</code> function:</p> |
|
|
<code>main</code> function:</p> |
|
|
<pre><code> func main() { |
|
|
|
|
|
|
|
|
<pre class="prettyprint"><code class="language-go"> func main() { |
|
|
http.HandleFunc("/hello", helloHTTP) |
|
|
http.HandleFunc("/hello", helloHTTP) |
|
|
http.HandleFunc("/user/", userProfile) |
|
|
http.HandleFunc("/user/", userProfile) |
|
|
http.HandleFunc("/", notFound) |
|
|
http.HandleFunc("/", notFound) |
|
@ -158,7 +158,7 @@ |
|
|
<p>Ok, so we have introduced some pretty severe holes in the security of our new HTTP router. As mentioned in a note above, |
|
|
<p>Ok, so we have introduced some pretty severe holes in the security of our new HTTP router. As mentioned in a note above, |
|
|
treating the |
|
|
treating the |
|
|
<code>req.URL.Path</code> as a byte slice and just taking the last half is a terrible idea. So let's fix this:</p> |
|
|
<code>req.URL.Path</code> as a byte slice and just taking the last half is a terrible idea. So let's fix this:</p> |
|
|
<pre><code> var validPath = regexp.MustCompile("^/(user)/([0-9]+)$") |
|
|
|
|
|
|
|
|
<pre class="prettyprint"><code class="language-go"> var validPath = regexp.MustCompile("^/(user)/([0-9]+)$") |
|
|
|
|
|
|
|
|
func getID(w http.ResponseWriter, req *http.Request) (string, error) { |
|
|
func getID(w http.ResponseWriter, req *http.Request) (string, error) { |
|
|
m := validPath.FindStringSubmatch(req.URL.Path) |
|
|
m := validPath.FindStringSubmatch(req.URL.Path) |
|
@ -170,7 +170,7 @@ |
|
|
} |
|
|
} |
|
|
</code></pre> |
|
|
</code></pre> |
|
|
<p>Now we can use this method in our code:</p> |
|
|
<p>Now we can use this method in our code:</p> |
|
|
<pre><code> func userProfile(w http.ResponseWriter, req *http.Request) { |
|
|
|
|
|
|
|
|
<pre class="prettyprint"><code class="language-go"> func userProfile(w http.ResponseWriter, req *http.Request) { |
|
|
userID, err := getID(w, req) |
|
|
userID, err := getID(w, req) |
|
|
if err != nil { |
|
|
if err != nil { |
|
|
return |
|
|
return |
|
@ -182,4 +182,4 @@ |
|
|
<p>For now, I'm calling this "Basic HTTP Routing in Golang" article finished. But I do plan to add more to it as time |
|
|
<p>For now, I'm calling this "Basic HTTP Routing in Golang" article finished. But I do plan to add more to it as time |
|
|
allows. Additionally, I'd like to create a more advanced article that discusses the ability to respond to not only GET |
|
|
allows. Additionally, I'd like to create a more advanced article that discusses the ability to respond to not only GET |
|
|
requests, but also POST, PUT, and DELETE HTTP methods. Look for an "Advanced HTTP routing in Golang" article |
|
|
requests, but also POST, PUT, and DELETE HTTP methods. Look for an "Advanced HTTP routing in Golang" article |
|
|
in the future. Thanks for reading this far. I wish you well in your Go endeavors.</p> |
|
|
|
|
|
|
|
|
in the future. Thanks for reading this far. I wish you well in your Go endeavors.</p> |