Skip to content

Commit

Permalink
Merge pull request #79 from blakeroberts-wk/INFENG-6103-allow-no-orig…
Browse files Browse the repository at this point in the history
…in-header-requests

INFENG-6103 allow no origin header requests
  • Loading branch information
rmconsole3-wf authored Aug 13, 2018
2 parents e504a05 + 0a32588 commit d26de9a
Show file tree
Hide file tree
Showing 9 changed files with 85 additions and 26 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
.idea
vendor/
glide.lock
4 changes: 2 additions & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
language: go

go:
- 1.3
- 1.4
- "1.5"
- "1.10"
- tip

before_install: go get golang.org/x/tools/cmd/cover
Expand Down
27 changes: 27 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
FROM golang:1.10.3-alpine3.8

## github credentials
RUN apk add --update bash curl git openssh py-pip
ARG GIT_SSH_KEY
RUN git config --global [email protected]:.insteadOf https://github.com/
RUN mkdir ~/.ssh; ssh-keyscan -t rsa github.com > ~/.ssh/known_hosts
RUN chmod -R 700 ~/.ssh; echo "${GIT_SSH_KEY}" > ~/.ssh/id_rsa; chmod 600 ~/.ssh/id_rsa
RUN eval "$(ssh-agent -s)" && ssh-add ~/.ssh/id_rsa

#install glide
RUN go get -u github.com/Masterminds/glide

WORKDIR /go/src/github.com/Workiva/go-rest
COPY . /go/src/github.com/Workiva/go-rest

# install dependencies
RUN glide install

# run tests
RUN go test $(glide novendor)

# artifacts
ARG BUILD_ARTIFACTS_AUDIT=/go/src/github.com/Workiva/go-rest/glide.lock

# no-op container
FROM scratch
18 changes: 9 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,17 @@ For documentation, see [godoc](http://godoc.org/github.com/Workiva/go-rest/rest)

## Installation

```
$ go get github.com/Workiva/go-rest/rest
```bash
go get github.com/Workiva/go-rest/rest
```

## Contributing

Requirements to commit here:
- Branch off master, PR back to master.
- [gofmt](http://golang.org/cmd/go/#hdr-Run_gofmt_on_package_sources) your code. Unformatted code will be rejected.
- Follow the style suggestions found [here](https://code.google.com/p/go-wiki/wiki/CodeReviewComments).
- Unit test coverage is required.
- Good docstrs are required for at least exported names, and preferably for all functions.
- Good [commit messages](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html) are required.

- Branch off master, PR back to master.
- [gofmt](http://golang.org/cmd/go/#hdr-Run_gofmt_on_package_sources) your code. Unformatted code will be rejected.
- Follow the style suggestions found [here](https://code.google.com/p/go-wiki/wiki/CodeReviewComments).
- Unit test coverage is required.
- Good docstrs are required for at least exported names, and preferably for all functions.
- Good [commit messages](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html) are required.
8 changes: 4 additions & 4 deletions documentation.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,15 @@ At Workiva, we require standardized REST endpoints across all our services. This

go-rest provides the tooling to build RESTful services rapidly and in a way that meets our internal API specification. Because it takes care of a lot of the boilerplate involved with building these types of services and offers some useful utilities, we're opening go-rest up to the open-source community. The remainder of this post explains go-rest in more detail, how it can be used to build REST APIs, and how we use it at Workiva.

# Composition and Extension
## Composition and Extension

go-rest is designed to be composable and pluggable. It makes no assumptions about your stack and doesn't care what libraries you're using or what your data model looks like. This is important to us at Workiva because it means we don't dictate down to developers what they need to use to solve their problems or force any artificial design constraints. Some services are running on App Engine and use its datastore. Others run off App Engine and don't necessarily use the datastore for persistence or entity modeling. go-rest is suited to either situation.

Several pieces of go-rest are pluggable, meaning custom implementations can be provided. JSON is arguably the most common serialization format for REST APIs and it's what we use at Workiva, so the framework ships with JSON response serialization out of the box. Other response serializers, e.g. YAML or XML, can be provided.

go-rest supports a notion of middleware, which are essentially just functions invoked on API requests. This has a wide range of application, ranging from authentication to logging and stats. For example, we use OAuth2 middleware to ensure authorized resource access.

# Building Stable APIs
## Building Stable APIs

In order to provide fine-grained control over API input and output, go-rest uses a concept of REST rules. Rules provide schema validation and type coercion for request input and fine-grained control over response output. They can specify types in which input and output values should be coerced. If coercion fails, a meaningful error will be returned in the response. Rule validation is also built in to ensure the names and types specified on rules match up with their corresponding struct properties.

Expand All @@ -24,15 +24,15 @@ A useful property of stable REST APIs is endpoint versioning. go-rest provides s

We use a [SemVer](http://semver.org/)-like approach to managing endpoint versions. REST rules allow us to accomplish this quite easily. If endpoint stability isn't a concern, you can neglect to specify rule versions or simply return full resource representations. This can be useful for rapid prototyping.

# Generating API Documentation
## Generating API Documentation

Using the REST rules described above has a beneficial side effect: they provide a means of self-documentation. go-rest can use rules to generate documentation for your REST API. This documentation describes what endpoints are available and the payloads they expect, including what fields there are, which of these are required, and the expected types as well as what the response looks like. The beautiful thing is you get this all for *free*.

We make extensive use of this documentation for several reasons. First, it acts as a contract for services. We write integration tests which verify our endpoints behave as they say they do. Second, they minimize unneeded communication between teams. We publish API documentation internally and people can look at this to understand how a service is used rather than going to the team directly. Third, and related to the first point, they promote building stable, high-quality APIs. By making this information visible, we expose the surface area of the API and document how it changes. This also forces teams to be held accountable for the services they provide.

![Generated Documentation](docs_example.png)

# Going Forward
## Going Forward

go-rest serves as a foundational piece for building production-quality REST APIs and is intended to fit into existing applications with ease. It lays much of the groundwork needed and allows for more frictionless development.

Expand Down
19 changes: 19 additions & 0 deletions glide.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package: github.com/Workiva/go-rest
import:
- package: github.com/gorilla/context
version: ~1.1.1
- package: github.com/gorilla/mux
version: ~1.6.2
- package: github.com/hoisie/mustache
version: 6375acf62c69d9d3ad20fd0599d82ca94ea12284
- package: golang.org/x/net
subpackages:
- context
testImport:
- package: github.com/stretchr/testify
version: ~1.2.2
subpackages:
- assert
- mock
- package: gopkg.in/yaml.v1
version: ~2.2.1
19 changes: 13 additions & 6 deletions rest/middleware/cors.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,25 +13,32 @@ import (
// a MiddlewareError if the request should be terminated.
func NewCORSMiddleware(originWhitelist []string) rest.Middleware {
return func(w http.ResponseWriter, r *http.Request) *rest.MiddlewareError {
origin := r.Header.Get("Origin")
if origin == "" && r.Method != "OPTIONS" {
return nil
}

originMatch := false
if origin := r.Header.Get("Origin"); checkOrigin(origin, originWhitelist) {
if checkOrigin(origin, originWhitelist) {
w.Header().Set("Access-Control-Allow-Origin", origin)
w.Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE")
w.Header()["Access-Control-Allow-Headers"] = r.Header["Access-Control-Request-Headers"]
w.Header().Set("Access-Control-Allow-Credentials", "true")
originMatch = true
}

var err *rest.MiddlewareError
if r.Method == "OPTIONS" {
err = &rest.MiddlewareError{Code: http.StatusOK}
} else if !originMatch {
err = &rest.MiddlewareError{
return &rest.MiddlewareError{Code: http.StatusOK}
}

if !originMatch {
return &rest.MiddlewareError{
Code: http.StatusBadRequest,
Response: []byte("Origin does not match whitelist"),
}
}
return err

return nil
}
}

Expand Down
9 changes: 9 additions & 0 deletions rest/middleware/cors_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,3 +64,12 @@ func TestCORSMiddlewareOptionsRequest(t *testing.T) {
err := NewCORSMiddleware([]string{"foo.com"})(w, req)
assert.Equal(t, http.StatusOK, err.Code)
}

// Ensures that CORSMiddleware doesn't return an error when a request is given
// without an Origin header.
func TestCORSMiddlewareNoOrigin(t *testing.T) {
req, _ := http.NewRequest("GET", "http://example.com/foo", nil)
w := httptest.NewRecorder()
err := NewCORSMiddleware([]string{"blah.wdesk.org", "*.wdesk.com"})(w, req)
assert.Nil(t, err)
}
5 changes: 0 additions & 5 deletions smithy.yml

This file was deleted.

0 comments on commit d26de9a

Please sign in to comment.