<commit_before># 3: Input validation and status codes

So far we've just assumed that all the HTTP requests our server receives are good.
And if there's something that you should never do when writing web servers is trusting your input!

In this chapter we'll see how to extract the information sent in different parts of the HTTP request.
Once we have that information we'll see how can validate them, and how we can signal different errors.

Let's start!

## Reading parameters from the URL

We've seen how we can route a request to different handlers depending on the path.
Now we're going to see how to extract then ones in the query part of the request, aka the data after `?`.

The `http.Request` type has a method `FormValue` with the following docs:

    func (r *Request) FormValue(key string) string

    FormValue returns the first value for the named component of the query. POST and PUT body parameters take precedence over URL query string values. FormValue calls ParseMultipartForm and ParseForm if necessary and ignores any errors returned by these functions. If key is not present, FormValue returns the empty string. To access multiple values of the same key, call ParseForm and then inspect Request.Form directly.

That's easy! So if we want to obtain the value of a parameter `q` in the URL `/hello?msg=world`
we can write the next program.

[embedmd]:# (examples/handlers/main.go /func paramHandler/ /^}/)
```go
func paramHandler(w http.ResponseWriter, r *http.Request) {
	name := r.FormValue("name")
	if name == "" {
		name = "friend"
	}
	fmt.Fprintf(w, "Hello, %s!", name)
}
```

### Exercise Hello, parameter

Write a web server that will answer to requests to `/hello?name=world` with an HTTP response with the text `Hello, world!`.
If the `name` is not present it should print `Hello, friend!`.

You can test it with your own browser, but let's try a couple things with `curl` too.
Before running these think about what you expect to see and why.

```bash
$ curl "localhost:8080/hello?name=world"

$ curl "localhost:8080/hello?name=world&name=francesc"

$ curl -X POST -d "name=francesc" "localhost:8080/hello"

$ curl -X POST -d "name=francesc" "localhost:8080/hello?name=potato"
```

Think about how would you make your program print all the values given to `name`.

## Reading from the Request body

Similarly to how we read from the `Body` in the `http.Response` a couple of chapter before we can read
the body of the `http.Request`.

Note that even though the type of `Body` in `http.Request` is `io.ReadCloser` the body will be automatically
closed at the end of the execution of the http handler, so don't worry about it.

There's many ways we can read from an `io.Reader`, but for now you can use `io.ReadAll`,
which returns a `[]byte` and an `error` if something goes wrong.

[embedmd]:# (examples/handlers/main.go /func bodyHandler/ /^}/)
```go
func bodyHandler(w http.ResponseWriter, r *http.Request) {
	b, err := ioutil.ReadAll(r.Body)
	if err != nil {
		fmt.Fprintf(w, "could not read body: %v", err)
		return
	}<commit_msg>Replace io.ReadAll with ioutil.ReadAll<commit_after># 3: Input validation and status codes

So far we've just assumed that all the HTTP requests our server receives are good.
And if there's something that you should never do when writing web servers is trusting your input!

In this chapter we'll see how to extract the information sent in different parts of the HTTP request.
Once we have that information we'll see how can validate them, and how we can signal different errors.

Let's start!

## Reading parameters from the URL

We've seen how we can route a request to different handlers depending on the path.
Now we're going to see how to extract then ones in the query part of the request, aka the data after `?`.

The `http.Request` type has a method `FormValue` with the following docs:

    func (r *Request) FormValue(key string) string

    FormValue returns the first value for the named component of the query. POST and PUT body parameters take precedence over URL query string values. FormValue calls ParseMultipartForm and ParseForm if necessary and ignores any errors returned by these functions. If key is not present, FormValue returns the empty string. To access multiple values of the same key, call ParseForm and then inspect Request.Form directly.

That's easy! So if we want to obtain the value of a parameter `q` in the URL `/hello?msg=world`
we can write the next program.

[embedmd]:# (examples/handlers/main.go /func paramHandler/ /^}/)
```go
func paramHandler(w http.ResponseWriter, r *http.Request) {
	name := r.FormValue("name")
	if name == "" {
		name = "friend"
	}
	fmt.Fprintf(w, "Hello, %s!", name)
}
```

### Exercise Hello, parameter

Write a web server that will answer to requests to `/hello?name=world` with an HTTP response with the text `Hello, world!`.
If the `name` is not present it should print `Hello, friend!`.

You can test it with your own browser, but let's try a couple things with `curl` too.
Before running these think about what you expect to see and why.

```bash
$ curl "localhost:8080/hello?name=world"

$ curl "localhost:8080/hello?name=world&name=francesc"

$ curl -X POST -d "name=francesc" "localhost:8080/hello"

$ curl -X POST -d "name=francesc" "localhost:8080/hello?name=potato"
```

Think about how would you make your program print all the values given to `name`.

## Reading from the Request body

Similarly to how we read from the `Body` in the `http.Response` a couple of chapter before we can read
the body of the `http.Request`.

Note that even though the type of `Body` in `http.Request` is `io.ReadCloser` the body will be automatically
closed at the end of the execution of the http handler, so don't worry about it.

There's many ways we can read from an `io.Reader`, but for now you can use `ioutil.ReadAll`,
which returns a `[]byte` and an `error` if something goes wrong.

[embedmd]:# (examples/handlers/main.go /func bodyHandler/ /^}/)
```go
func bodyHandler(w http.ResponseWriter, r *http.Request) {
	b, err := ioutil.ReadAll(r.Body)
	if err != nil {
		fmt.Fprintf(w, "could not read body: %v", err)
		return
	}
{'fraction_non_alphanumeric': 0.08708367181153534, 'fraction_numerical': 0.005523964256701868, 'mean_word_length': 4.288659793814433, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5282801', 'n_tokens_mistral': 1832, 'n_tokens_neox': 1730, 'n_words': 905}