Skip to content

Commit

Permalink
Added configuration for the auto populating headers and auto recogniz…
Browse files Browse the repository at this point in the history
…ing the input

Closes #21, #22
  • Loading branch information
stevenklassen8376 committed Mar 27, 2021
1 parent 827e71b commit 5184d6c
Show file tree
Hide file tree
Showing 4 changed files with 106 additions and 8 deletions.
74 changes: 74 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,76 @@
# crest
Command line REST client

### Configuration Files

The operation of this program can be modified by the existance of configuration files. Specifically,
you can place a `.crestconfig.json` file in your home directory, or in the directory from which
you are running `crest`. (Say, for example, the project directory where you are developing your
web service.) In this way you can customize the program operation for the needs of a given
project.

A configuration file in the local directory will override any settings found in the global file (the one
in your home directory), and many of the settings can also be overridden by command line
options.

The configuration files are JSON files consisting of a single dictionary where each key is
one of the following, and the contents are as described.

E.g.

{
"Private": true,
"URLPrefix": "http://mytestserver.local:8080/api/v2"
}

#### AutoPopulateRequestHeaders

By default `crest` adds a number of request headers automatically. They can be overridden
by manually specifying headers of the same name, but you can turn off the auto headers
completely by setting this to `false`. In that case only the headers that are absolutely required
for the HTTP protocol will be added.

e.g. `"AutoPopulateRequestHeaders": false` (Default is `true`)

This is also turn off if `--no-auto-headers` is specified on the command line.

#### AutoRecognizeRequestContent

By default `crest` will attempt to identify the contents of the standard input and set the
`Content-Type` header appropriately. However, there are the following limitations:

1. Presently only JSON and XML data are recognized.
2. If the data is too large (by default over 2048 bytes), then it will be sent as chunked data
to avoid keeping the entire contents in memory at once. In this case it will not be
recognized.

By turning this off no `Content-Type` header will be added automatically, and you will
need to add it manually via the command line options.

e.g. `"AutoRecognizeRequestContent": false` (Default is `true`)

This is also turn off if `--no-auto-headers` is specified on the command line.

#### Private

By default `crest` adds a `User-Agent` key that includes information about the machine you
are running on. For example: `Crest/1.0.0 (macOS; Version 11.2.3 (Build 20D91); x86_64)`.
If you set `Private` to `true`, then the details will be left out and the `User-Agent` will simply
be reported as `Crest`. (You can override this as well by specifying your own `User_Agent` header
either in the configuration files or via the command line.)

E.g. `"Private": true` (Default is `false`)

#### URLPrefix

This can be used to set a prefix that will automatically be prepended to the URL given on the command
line. This is likely to be most useful in the local `.crestconfig.json` where you can set it to be
the common part of the web service you are testing. This can save you a lot of typing.

Note that the `URLPrefix` will be ignored if the command line URL begins with `http:` or
`https:`.

E.g. `"URLPrefix": "http://mytestserver.local:8080/api/v2"` (Default is empty)

In this example, if you run the command `crest /contract/id871` it will actually perform
a `GET` to the URL `http://mytestserver.local:8080/api/v2/contract/id871`.
10 changes: 8 additions & 2 deletions Sources/CrestLib/Configuration.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,10 @@ import Foundation


public struct Configuration {
var URLPrefix: String? = nil
var autoPopulateRequestHeaders: Bool? = nil
var autoRecognizeRequestContent: Bool? = nil
var isPrivate: Bool? = nil
var urlPrefix: String? = nil

static var shared = Configuration()

Expand All @@ -20,7 +23,10 @@ public struct Configuration {
manager.load(file: filename, relativeFrom: .customPath(homeDirectory))
.load(file: filename, relativeFrom: .pwd)
.load(overloads)
shared.URLPrefix = manager["URLPrefix"] as? String
shared.autoPopulateRequestHeaders = manager["AutoPopulateRequestHeaders"] as? Bool
shared.autoRecognizeRequestContent = manager["AutoRecognizeRequestContent"] as? Bool
shared.isPrivate = manager["Private"] as? Bool
shared.urlPrefix = manager["URLPrefix"] as? String

print("!! config: \(shared)")
}
Expand Down
21 changes: 16 additions & 5 deletions Sources/CrestLib/Operation.swift
Original file line number Diff line number Diff line change
Expand Up @@ -39,18 +39,27 @@ public struct Operation {

private func urlAsString() -> String {
if url.scheme == nil {
if let prefix = Configuration.shared.URLPrefix {
if let prefix = Configuration.shared.urlPrefix {
return prefix + url.absoluteString
}
}
return url.absoluteString
}

private func addHeadersToRequest(_ request: inout HTTPClient.Request) {
let platform = Platform()
request.headers.add(name: "Host", value: "\(request.host):\(request.port)")
request.headers.add(name: "User-Agent", value: "Crest/\(VERSION) (\(platform.operatingSystem); \(platform.operatingSystemVersion); \(platform.hardware))")
request.headers.add(name: "Accept", value: "*/*")
if Configuration.shared.autoPopulateRequestHeaders ?? true {
request.headers.add(name: "User-Agent", value: getUserAgent())
request.headers.add(name: "Accept", value: "*/*")
}
}

private func getUserAgent() -> String {
if Configuration.shared.isPrivate ?? false {
return "Crest"
}
let platform = Platform()
return "Crest/\(VERSION) (\(platform.operatingSystem); \(platform.operatingSystemVersion); \(platform.hardware))"
}

// This "ugliness" is needed for the streaming requests since we need the stream
Expand Down Expand Up @@ -88,7 +97,9 @@ public struct Operation {
} else if (try? XMLDocument(data: data)) != nil {
contentType = "application/xml"
}
request.headers.add(name: "Content-Type", value: contentType)
if Configuration.shared.autoRecognizeRequestContent ?? true {
request.headers.add(name: "Content-Type", value: contentType)
}
request.body = .string(s)
return
}
Expand Down
9 changes: 8 additions & 1 deletion Sources/crest/main.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,12 @@ struct Crest: ParsableCommand {
version: CrestLib.VERSION
)

@Option(name: .shortAndLong, help: "The HTTP method (defaults to GET)")
@Option(name: .shortAndLong, help: "The HTTP method (defaults to GET).")
var method: HTTPMethod = .GET

@Flag(help: "Turn off the auto-population of headers.")
var noAutoHeaders = false

@Argument(help: "The URL of the service to contact.")
var url: String

Expand All @@ -37,6 +40,10 @@ struct Crest: ParsableCommand {

func commandLineOverrides() -> [String: Any?] {
var overrides = [String: Any?]()
if noAutoHeaders {
overrides["AutoPopulateRequestHeaders"] = false
overrides["AutoRecognizeRequestContent"] = false
}
return overrides
}
}
Expand Down

0 comments on commit 5184d6c

Please sign in to comment.