Skip to content
This repository has been archived by the owner on Mar 14, 2022. It is now read-only.

Commit

Permalink
Persist a record in the repository
Browse files Browse the repository at this point in the history
Ref #99
  • Loading branch information
jcoyne authored and eefahy committed Jan 31, 2018
1 parent e7997e1 commit 59e3a85
Show file tree
Hide file tree
Showing 11 changed files with 207 additions and 61 deletions.
15 changes: 14 additions & 1 deletion .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,22 @@ jobs:
- run:
name: Run Unit Tests
command: go test -v ./... -short
- run:
name: Install AWS CLI
command: |
sudo apt-get -y -qq update
sudo apt-get -y -qq install awscli
- run:
name: Create table
command: AWS_ACCESS_KEY_ID=999 AWS_SECRET_ACCESS_KEY=999 aws dynamodb create-table
--endpoint-url=http://localhost:4569 --table-name resources
--region localstack
--attribute-definitions "AttributeName=id,AttributeType=S"
--key-schema "AttributeName=id,KeyType=HASH"
--provisioned-throughput=ReadCapacityUnits=10,WriteCapacityUnits=10
- run:
name: Start server
command: go run cmd/tacod/main.go --port 3000
command: cd cmd/tacod && AWS_ACCESS_KEY_ID=999 AWS_SECRET_KEY=999 go run main.go --port 3000
background: true
- run:
name: wait for server
Expand Down
30 changes: 17 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,9 @@ $ go get github.com/sul-dlss-labs/taco
## Running the Go Code locally without a build
```shell
$ go run main.go
$ cd cmd/tacod
$ AWS_ACCESS_KEY_ID=999999 AWS_SECRET_KEY=1231 go run main.go
```
## Building to TACO Binary
Expand Down Expand Up @@ -70,16 +70,26 @@ $ awslocal dynamodb create-table --table-name resources \
--provisioned-throughput=ReadCapacityUnits=100,WriteCapacityUnits=100
```
And add a stub record:
```
$ awslocal dynamodb put-item --table-name resources --item '{"id": {"S":"99"}, "title":{"S":"Ta-da!"}}'
Now start the API server:
```shell
% AWS_ACCESS_KEY_ID=999999 AWS_SECRET_KEY=1231 ./tacod
```
Then you can interact with it using `curl`:
```shell
% TACO_ENV=production AWS_ACCESS_KEY_ID=999999 AWS_SECRET_KEY=1231 ./tacod
curl -X POST -H "Content-Type: application/json" -d '{"title":"value1", "sourceId":"value2"}' http://localhost:8080/v1/resource
```
Now visit: http://localhost:8080/v1/resource/99
it will return a response like:
```json
{"id":"fe1f66a9-5285-4b28-8240-0482c8fff6c7"}
```
Then you can use the returned identifier to retrieve the original:
```shell
curl -H "Content-Type: application/json" http://localhost:8080/v1/resource/fe1f66a9-5285-4b28-8240-0482c8fff6c7
```
## API Code Structure
Expand All @@ -104,12 +114,6 @@ go install

Do this prior to generating code.

### To run the API code

```shell
$ go run main.go
```

### Non-generated code

The API code generation does **not** touch the following, which we are writing locally:
Expand Down
2 changes: 2 additions & 0 deletions config/development.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,5 @@ db:
region: "localstack"
endpoint: "localhost:4569"
disable_ssl: true
resource_repository:
table_name: "resources"
2 changes: 2 additions & 0 deletions config/production.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,5 @@ db:
region: "us-east-2"
endpoint: "https://dynamodb.us-east-2.amazonaws.com"
disable_ssl: false
resource_repository:
table_name: "resources"
2 changes: 2 additions & 0 deletions config/test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,5 @@ db:
region: "localstack"
endpoint: "localhost:4569"
disable_ssl: true
resource_repository:
table_name: "resources"
40 changes: 35 additions & 5 deletions handlers/deposit_resource.go
Original file line number Diff line number Diff line change
@@ -1,25 +1,55 @@
package handlers

import (
"fmt"

"github.com/go-openapi/runtime/middleware"
"github.com/google/uuid"
"github.com/sul-dlss-labs/taco"
"github.com/sul-dlss-labs/taco/generated/models"
"github.com/sul-dlss-labs/taco/generated/restapi/operations"
"github.com/sul-dlss-labs/taco/persistence"
)

// NewDepositResource -- Accepts requests to create resource and pushes them to Kinesis.
func NewDepositResource(rt *taco.Runtime) operations.DepositNewResourceHandler {
return &depositResourceEntry{}
return &depositResourceEntry{rt: rt}
}

type depositResourceEntry struct{}
type depositResourceEntry struct {
rt *taco.Runtime
}

// Handle the delete entry request
func (d *depositResourceEntry) Handle(params operations.DepositNewResourceParams) middleware.Responder {
// TODO: This should be a DRUID
resourceID, _ := uuid.NewRandom()

response := &models.DepositNewResourceOKBody{ID: resourceID.String()}
resourceID := mintID()

if err := d.persistResource(resourceID, params); err != nil {
// TODO: handle this with an error response
panic(err)
}

response := &models.DepositNewResourceOKBody{ID: resourceID}
return operations.NewDepositNewResourceOK().WithPayload(response)
}

func (d *depositResourceEntry) persistResource(resourceID string, params operations.DepositNewResourceParams) error {
resource := d.persistableResourceFromParams(resourceID, params)
fmt.Println("Saving")
return d.rt.Repository().SaveItem(resource)
}

func (d *depositResourceEntry) persistableResourceFromParams(resourceID string, params operations.DepositNewResourceParams) *persistence.Resource {
resource := &persistence.Resource{ID: resourceID}
// TODO: Expand this mapping:
resource.Title = *params.Payload.Title
resource.SourceID = *params.Payload.SourceID
return resource
}

func mintID() string {
// TODO: This should be a DRUID
resourceID, _ := uuid.NewRandom()
return resourceID.String()
}
71 changes: 71 additions & 0 deletions handlers/deposit_resource_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package handlers

import (
"errors"
"net/http"
"testing"

"github.com/appleboy/gofight"
"github.com/stretchr/testify/assert"
"github.com/sul-dlss-labs/taco/persistence"
)

func mockErrorRepo() persistence.Repository {
return &fakeErroringRepository{}
}

type fakeErroringRepository struct{}

func (f *fakeErroringRepository) GetByID(id string) (*persistence.Resource, error) {
return nil, nil
}

func (f *fakeErroringRepository) SaveItem(resource *persistence.Resource) error {
return errors.New("not found")
}

func TestCreateResourceHappyPath(t *testing.T) {
r := gofight.New()
repo := mockRepo(nil)

r.POST("/v1/resource").
SetJSON(gofight.D{
"id": "oo000oo0001",
"sourceId": "bib12345678",
"title": "My work",
}).
Run(setupFakeRuntime(repo),
func(r gofight.HTTPResponse, rq gofight.HTTPRequest) {
assert.Equal(t, http.StatusOK, r.Code)
assert.Equal(t, 1, len(repo.(*fakeRepository).CreatedResources))

})
}

func TestCreateResourceMissingSourceId(t *testing.T) {
r := gofight.New()
r.POST("/v1/resource").
SetJSON(gofight.D{
"id": "oo000oo0001",
"title": "My work",
}).
Run(setupFakeRuntime(mockRepo(nil)),
func(r gofight.HTTPResponse, rq gofight.HTTPRequest) {
assert.Equal(t, http.StatusUnprocessableEntity, r.Code)
})
}

// TODO: Handle errors
// func TestCreateResourceFailure(t *testing.T) {
// r := gofight.New()
// r.POST("/v1/resource").
// SetJSON(gofight.D{
// "id": "oo000oo0001",
// "sourceId": "bib12345678",
// "title": "My work",
// }).
// Run(setupFakeRuntime(mockErrorRepo()),
// func(r gofight.HTTPResponse, rq gofight.HTTPRequest) {
// assert.Equal(t, http.StatusUnprocessableEntity, r.Code)
// })
// }
44 changes: 11 additions & 33 deletions handlers/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,26 +10,31 @@ import (
"github.com/stretchr/testify/assert"
"github.com/sul-dlss-labs/taco"
"github.com/sul-dlss-labs/taco/config"
"github.com/sul-dlss-labs/taco/generated/models"
"github.com/sul-dlss-labs/taco/persistence"
)

func mockRepo(record *models.Resource) persistence.Repository {
return &fakeRepository{record: record}
func mockRepo(record *persistence.Resource) persistence.Repository {
return &fakeRepository{record: record, CreatedResources: []persistence.Resource{}}
}

type fakeRepository struct {
record *models.Resource
record *persistence.Resource
CreatedResources []persistence.Resource
}

func (f fakeRepository) GetByID(id string) (*models.Resource, error) {
func (f *fakeRepository) GetByID(id string) (*persistence.Resource, error) {

if f.record != nil {
return f.record, nil
}
return nil, errors.New("not found")
}

func (f *fakeRepository) SaveItem(resource *persistence.Resource) error {
f.CreatedResources = append(f.CreatedResources, *resource)
return nil
}

func setupFakeRuntime(repo persistence.Repository) http.Handler {
config.Init("../config/test.yaml")
rt, _ := taco.NewRuntimeForRepository(viper.GetViper(), repo)
Expand All @@ -39,7 +44,7 @@ func setupFakeRuntime(repo persistence.Repository) http.Handler {
func TestRetrieveHappyPath(t *testing.T) {
r := gofight.New()
r.GET("/v1/resource/99").
Run(setupFakeRuntime(mockRepo(new(models.Resource))),
Run(setupFakeRuntime(mockRepo(new(persistence.Resource))),
func(r gofight.HTTPResponse, rq gofight.HTTPRequest) {
assert.Equal(t, http.StatusOK, r.Code)
})
Expand All @@ -53,30 +58,3 @@ func TestRetrieveNotFound(t *testing.T) {
assert.Equal(t, http.StatusNotFound, r.Code)
})
}

func TestCreateResourceHappyPath(t *testing.T) {
r := gofight.New()
r.POST("/v1/resource").
SetJSON(gofight.D{
"id": "oo000oo0001",
"sourceId": "bib12345678",
"title": "My work",
}).
Run(setupFakeRuntime(mockRepo(nil)),
func(r gofight.HTTPResponse, rq gofight.HTTPRequest) {
assert.Equal(t, http.StatusOK, r.Code)
})
}

func TestCreateResourceMissingSourceId(t *testing.T) {
r := gofight.New()
r.POST("/v1/resource").
SetJSON(gofight.D{
"id": "oo000oo0001",
"title": "My work",
}).
Run(setupFakeRuntime(mockRepo(nil)),
func(r gofight.HTTPResponse, rq gofight.HTTPRequest) {
assert.Equal(t, http.StatusUnprocessableEntity, r.Code)
})
}
10 changes: 9 additions & 1 deletion handlers/retrieve_resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package handlers
import (
"github.com/go-openapi/runtime/middleware"
"github.com/sul-dlss-labs/taco"
"github.com/sul-dlss-labs/taco/generated/models"
"github.com/sul-dlss-labs/taco/generated/restapi/operations"
"github.com/sul-dlss-labs/taco/persistence"
)
Expand All @@ -21,9 +22,16 @@ type resourceEntry struct {
func (d *resourceEntry) Handle(params operations.RetrieveResourceParams) middleware.Responder {
resource, err := d.repository.GetByID(params.ID)
if err == nil {
return operations.NewRetrieveResourceOK().WithPayload(resource)
// TODO: expand this mapping
response := buildResponse(resource)
return operations.NewRetrieveResourceOK().WithPayload(response)
} else if err.Error() == "not found" {
return operations.NewRetrieveResourceNotFound()
}
panic(err)
}

// TODO: expand this mapping
func buildResponse(resource *persistence.Resource) *models.Resource {
return &models.Resource{ID: resource.ID, Title: &resource.Title, SourceID: &resource.SourceID}
}
Loading

0 comments on commit 59e3a85

Please sign in to comment.