# Just Requests

The basic dispatch documentation contains decent material on creating requests. A request, and underneath the async-http-client request object, needs a method and target url, headers and optionally a body.

dispatch provides several ways to create these requests. There is even a periodic table that was built to describe the different methods that are sometimes encoded using symbols [here](http://www.flotsam.nl/dispatch-periodic-table.html).

async-http-client creates requests using a `RequestBuilder` which is a mutable object that you call methods on to mutate. That's not as functional as would be desired so dispatch's `Req` objects wraps a builder object much in the same way `Http` wraps an async-http-client object. A "function" is added to the request that configures the underlying request in some way. Once you issue a request in dispatch, a real async-http-client request object is created using the async-http-client request builder and the chain of functions to configure the request are run. This makes the scala dispatch `Req` object immutable. Because they are immutable, you can create a basic request that has the configuration you need for your program and use that request a trusted base to derive other requests.

## Creating the Basic Request

The default `Req` in dispatch performs some checks so that if you just added some text as the request body but never set the content type, it will set the content type for you.

You always start defining a request by setting the host or url that you want to target. dispatch only provides this as this starting point for all requests. You can create the basic request a few different ways although they produce the same request concept:

```scala
 host("localhost", 9000) 
res11: Req = Req(<function1>, Properties(NoBody))
@ :/("localhost") 
res12: Req = Req(<function1>, Properties(NoBody))
@ url("localhost") 
res13: Req = Req(<function1>, Properties(NoBody))
@ :/("localhost", 9000) 
res14: Req = Req(<function1>, Properties(NoBody))
```

Once you have a basic request, you can continue to modify the URL through dispatch's `UrlVerbs`:

```scala
@ host("localhost") / "blah" 
res15: Req = Req(<function1>, Properties(NoBody))
@ host("localhost") / "blah" / "hah/nah" 
res16: Req = Req(<function1>, Properties(NoBody))
```

and so on. Note that characters embedded in the string parameter will be escaped. If you need the url from a request, just call `yourrequest.url`. To ensure that https is used (SSL) add `.secure`:

```scala
@ (host("localhost") / "blah" / "hah/nah").secure.url 
res18: String = "https://localhost/blah/hah%2Fnah"
```

You can see from the above that the http was change (or in this case added) to https. This will use SSL. If you need to configure the client ot use specific a SSL configration, you will need to configure the `Http` client.

A convenience function is provided to add path segments from `Option[String]`:

```scala
 (host("localhost:9000") /? Some("blah")).url 
res19: String = "http://localhost:9000/blah"
@ (host("localhost:9000") /? None).url 
res20: String = "http://localhost:9000/"
```

Once you create a request you can continue to add path segments to it or change the URL entirely. That way, you can create your base request with the base URL and customize it for each call as needed by adding the complete path prior to sending it to the server.

## More Request Building: Method

Using various combinators, called "verbs" in dispatch, you build up your request object using functions that take `Req` and return a `Req` object. You can do this since requests are mutable. You build up your requests to add a method, headers and a body. The default request as you saw above has a property of NoBody which is an internal property for the `Req` object that helps with some default setting. You can mostly ignore it.

So once you have a `Req` object you use combinators to further customize it until you have your basic request object or you are ready to issue it using dispatch's `Http` client.

Using combinators, you con change your request to have different methods:

```scala
@ host("http://localhost:9000").HEAD 
res21: Req = Req(<function1>, Properties(NoBody))
@ host("http://localhost:9000").HEAD.toRequest 
res22: com.ning.http.client.Request = http://http//localhost:9000/    HEAD    headers:
@ host("http://localhost:9000").OPTIONS.toRequest 
res23: com.ning.http.client.Request = http://http//localhost:9000/    OPTIONS    headers:
@ host("http://localhost:9000").POST.toRequest 
res24: com.ning.http.client.Request = http://http//localhost:9000/    POST    headers:
```

I have used `toRequest` which converts the `Req` object to a async-http-client request object so it prints out more clearly. You can see from the first `.HEAD` that the default string output just shows that `Req` is built around a function that configures a basic async-http-client request object once one is provided to `Req`. You should not need to use `.toRequest` in your production code.

You can also set the method using a traditionally named method call `.setMethod`.

There are a few, not many, methods that set various aspects of a request and automatically change the request method type e.g. setting a parameter on a GET request automatically converts it to a POST method.

## More Request Building: Headers and Cookies

In addition to a method, you need to add a header. There are multiple methods to add headers.

The basic approach to add headers is:

```scala
@ host("http://localhost:9000").addHeader("Content-Type", "application/soap+xml").toRequest 
res32: com.ning.http.client.Request = http://http//localhost:9000/    GET    headers:    Content-Type:application/soap+xml
@ (host("http://localhost:9000") <:< Map("Content-Type" -> "application/soap+xml")).toRequest 
res34: com.ning.http.client.Request = http://http//localhost:9000/    GET    headers:    Content-Type:application/soap+xml
```

You can use `addHeader` or `<:<` which can many headers from a Map at once.

If you use `.setHeader` or `.setHeaders` you will be setting the headers explicitly and wipe out any other headers.

The special header `Content-Type` can be set, if you desired to set it this way, using:

```scala
@ host("http://localhost:9000").setContentType("application/soap+xml", "utf-8").toRequest 
res43: com.ning.http.client.Request = http://http//localhost:9000/    GET    headers:    Content-Type:application/soap+xml; charset=utf-8
```

There is only one way to add a cookie:

```scala
@ import com.ning.http.client.cookie.Cookie
@ val cookie = new Cookie("JSESSION", "1234", "", ".github.com", "/", 219384848, -1, true, true) 
cookie: Cookie = JSESSION=; domain=.github.com; path=/; expires=219384848; secure; HTTPOnly
@ host("http://localhost:9000").addCookie(cookie).toRequest 
res41: com.ning.http.client.Request = http://http//localhost:9000/    GET    headers:
```

## More Request Building: Query Parameters and Parameters

There are a few `Req` methods to add URL parameters.

```scala
@ (host("http://localhost:9000").GET <<? Map("name" -> "foo")).toRequest 
res45: com.ning.http.client.Request = http://http//localhost:9000/?name=foo    GET    headers:
@ (host("http://localhost:9000").GET <<? Map("name" -> "foo", "answer" -> "maybe")).toRequest 
res46: com.ning.http.client.Request = http://http//localhost:9000/?name=foo&answer=maybe    GET    headers:
@ host("http://localhost:9000").GET.addQueryParameter("name" , "foo").toRequest 
res47: com.ning.http.client.Request = http://http//localhost:9000/?name=foo    GET    headers:
```

The `<<?` with the `?` suggests query parameters versus POST parameters. All of the query parameters can be set explicitly and any existing parameters removed using `.setQueryParameters`:

```scala
@ host("http://localhost:9000").GET.addQueryParameter("name" , "foo").setQueryParameters(Map("answers" -> Seq("maybe,couldbe,havetobe"))).toRequest 
res49: com.ning.http.client.Request = http://http//localhost:9000/?answers=maybe%2Ccouldbe%2Chavetobe    PUT    headers:
```

You can see that in `.setQueryParameters` you model multiple query parameter values as a sequence and set it explicitly unlike some of the other APIs for setting query parameters.

POST parameters typically go into the body. If you add parameters (not query parameters) dispatch will change your GET to a POST automatically:

```scala
@ (host("http://localhost:9000").GET << Map("answers" -> "maybe")).toRequest 
res52: com.ning.http.client.Request = http://http//localhost:9000/    POST    headers:    formParams:    answers:maybe
```

You can also use `.addParameter` and `.setParameters` just like with the query parameters.

If you need a valueless query parameter e.g. `yoururl?myparam` instead of a `youurl?myparam=somevalue` you can use `null` as the value for the query parameter value in the map (`<<? Map("myparam" -> null)`. It's very unscala but I think its fine here because its just a marker value and null is not being used in logic per se. We should probably have a `<<?` method that handles `Map[String, Option[String]]` but that map might be pain to create all the time.

## More Request Building: Body

Setting the body is important of course. You can add a string to the body quite easily:

```scala
 (host("http://localhost:9000").GET << "my body").toRequest 
res57: com.ning.http.client.Request = http://http//localhost:9000/    POST    headers:    Content-Type:text/plain; charset=UTF-8
```

You should notice that we made the initial request a GET and it was turned into a POST. If the initial request was a PUT it would remain a PUT. The `.toRequest` does not print out the body but you can also see that with a string, dispatch automatically set the content ype to `text/plain`.

There are a few explicit methods such as `.setBody` to set the body and they work as expected or to even set a body part if your request is multi-part.

async-http-client also has the concept of a body generator, which can produce a body as needed while allowing the client to control buffering:

```java
 public interface BodyGenerator {
    Body createBody() throws IOException;
}

public interface Body {
    long getContentLength();
    long read(ByteBuffer buffer)
      throws IOException;
    void close() throws IOException;
}
```

We do not show an example of this in these notes but the intent is clear. You can also get the body, as a string, from a file using dispatch's convenience function `Req.<<<` as in `myrequest <<< yourfile` or `.setBody(yourfile)`.

## More Request Building: Misc

You can modify the request with additional features such as:

* proxy server: `.setProxyServer(...)`
* virtual host: `.setVirtualHost(...)`
* realm: `.setRealm(...)`
* authentication: An example is `host(yourhost).as(user, password)`

See the async-http-client docs for the parameters of each call.
