Wednesday, July 26, 2017

Phil Sturgeon Rest API Notes

First Document the API

1. Start with the resources. List all the resources and it's attributes in a text document. Skip defining relationships on the user.
2. Use data structures that can be used in requests and responses. Use JSON API specification in the data structures.
3. Convert the draft document of resources to data structures using API Blueprint syntax.
4. Use apiary.io to document the API using markdown.
5. Use MSON.
6.  You can show success and failure cases by using multiple transactions. Request . Request .

https://philsturgeon.uk/api/2016/11/22/apis-documentation-first/

Mocking APIs with API Blueprint

1. Apiary provides mocking server. No coding needed.
2. If you don't want to pay apiary. You can use drakov.

npm install -g drakov
drakov -f yourapi.apib

3. Use http CLI to test teh response.

http GET http://localhost:3000/products --json

https://philsturgeon.uk/api/2016/12/02/mocking-apis-with-api-blueprint/

Rails Serialization for REST APIs

1. Use active model serializers with json_api adapter.

https://philsturgeon.uk/api/2016/12/11/building-rest-apis-with-rails-basic-serialization/

Keeping API Documentation is Up to Date with Code

1. npm install -g dredd

2. dredd init

3. Use seeds to populate the database.

4. Run the dredd in test environment.

RAILS_ENV=test rake db:drop db:create db:migrate db:seed
dredd

5. Create a Makefile to simplify and run make docs_test.

# Makefile
.PHONY: docs_test
docs_test:
  @echo "Seeding database for documentation testing"
  @RAILS_ENV=test rake db:drop db:create db:migrate db:seed:dredd
  @echo "Running dredd... check logs/dredd.log for more information"
  @RAILS_ENV=test dredd > log/dredd.log && echo "Documentation is all good!"

https://philsturgeon.uk/api/2016/12/21/building-rest-apis-with-rails-documentation-testing/

https://philsturgeon.uk/api/2017/01/03/building-apis-with-rails-handling-errors-nicely/

Sunday, July 23, 2017

Create a Hosted Zone using CLI

Install AWS CLI

pip install --upgrade --user awscli
aws --version


aws-cli/1.11.123 Python/2.7.10 Darwin/14.5.0 botocore/1.5.86

Configure AWS CLI

$ aws configure
AWS Access Key ID [None]: YOUR-ACCESS-KEY-ID  
AWS Secret Access Key [None]: YOUR-SECRET-ACCESS-KEY
Default region name [None]: us-east-1
Default output format [None]:

Provide the access key ID and secret access key when prompted. Accept defaults for region and format (json).

Create a Hosted Zone in Route 53

If you registered your domain with Amazon, they will automatically create a hosted zone with a set of name servers. Otherwise, you can create the name servers using Amazon CLI like this:

aws route53 create-hosted-zone --name www.clickplan.net --caller-reference 2017-07-23-13:35

{
    "HostedZone": {
        "ResourceRecordSetCount": 2, 
        "CallerReference": "2017-07-23:15:35", 
        "Config": {
            "PrivateZone": false
        }, 
        "Id": "/hostedzone/Z3F02TIXYMYTDY", 
        "Name": "www.clickplan.net."
    }, 
    "DelegationSet": {
        "NameServers": [
            "ns-1438.awsdns-51.org", 
            "ns-975.awsdns-57.net", 
            "ns-150.awsdns-18.com", 
            "ns-1978.awsdns-55.co.uk"
        ]
    }, 
    "Location": "https://route53.amazonaws.com/2013-04-01/hostedzone/Z3F02TIXYMYTDY", 
    "ChangeInfo": {
        "Status": "PENDING", 
        "SubmittedAt": "2017-07-24T01:36:35.194Z", 
        "Id": "/change/CO73DYX4SHITQ"
    }

}

You can see that the status is pending. It will take some time for this to complete. I checked the status in the AWS console. You can see that clickplan.biz ns records was created by Amazon, since that domain was registered on Amazon. We see the ns records for the domain registered on namecheap below that we created using AWS CLI.



After few hours, we can run the following command to check the resource record sets:

aws route53 list-resource-record-sets --hosted-zone-id Z3F02TIXYMYTDY

{
    "ResourceRecordSets": [
        {
            "ResourceRecords": [
                {
                    "Value": "ns-1438.awsdns-51.org."
                }, 
                {
                    "Value": "ns-975.awsdns-57.net."
                }, 
                {
                    "Value": "ns-150.awsdns-18.com."
                }, 
                {
                    "Value": "ns-1978.awsdns-55.co.uk."
                }
            ], 
            "Type": "NS", 
            "Name": "www.clickplan.net.", 
            "TTL": 172800
        }, 
        {
            "ResourceRecords": [
                {
                    "Value": "ns-1438.awsdns-51.org. awsdns-hostmaster.amazon.com. 1 7200 900 1209600 86400"
                }
            ], 
            "Type": "SOA", 
            "Name": "www.clickplan.net.", 
            "TTL": 900
        }
    ]
}

You can see that there are two resource records have been created. One is of type NS and the other is SOA.

Retrieve a list of hosted zones.

$ aws route53 list-hosted-zones
{
    "HostedZones": [
        {
            "ResourceRecordSetCount": 2, 
            "CallerReference": "RISWorkflow-RD:3b4397e2-1ea4-4809-bb0c-b1c1714c4527", 
            "Config": {
                "Comment": "HostedZone created by Route53 Registrar", 
                "PrivateZone": false
            }, 
            "Id": "/hostedzone/Z5PP9SH99T8H9", 
            "Name": "clickplan.biz."
        }, 
        {
            "ResourceRecordSetCount": 2, 
            "CallerReference": "2017-07-23:15:35", 
            "Config": {
                "PrivateZone": false
            }, 
            "Id": "/hostedzone/Z3F02TIXYMYTDY", 
            "Name": "www.clickplan.net."
        }
    ]

}

The first record was created by Amazon when I registered clickplan.biz domain with Amazon domain registration. The second record was created by the command we ran using CLI for the clickplan.net domain that was registered with namecheap.

TO BE TESTED

The next step is to create a record set (A record and CNAME). The A record must point to the Elastic Beanstalk instance. 

 To create a new record set, first create a JSON file to describe the new record:

{
  "Comment": "CNAME record set for the zone.",
  "Changes": [
    {
      "Action": "CREATE",
      "ResourceRecordSet": {
        "Name": "clickplan.net.",
        "Type": "CNAME",
        "TTL": 60,
        "ResourceRecords": [
          {
            "Value": "www.clickplan.net"
          }
        ]
      }
    }
  ]
}

aws route53 change-resource-record-sets --hosted-zone-id 1234567890ABC --change-batch file:///path/to/record.json
{
  "ChangeInfo": {
    "Status": "PENDING",
    "Comment": "A new record set for the zone.",
    "SubmittedAt": "2017-07-24T00:00:00.000Z",
    "Id": "/change/CHANGEID123"
  }
}

The status of adding the new record is currently pending. Poll the server to get the updated status:

$ aws route53 get-change --id CHANGEID123
{
  "ChangeInfo": {
    "Status": "INSYNC",
    "Comment": "A new record set for the zone.",
    "SubmittedAt": "2013-12-06T00:00:00.000Z",
    "Id": "/change/CHANGEID123"
  }
}

A new record has been created and has been propagated to all hosts.

To create a A record:

Create the JSON file with the following:

{
    "Comment": "Create A record to point to Elastic Beanstalk",
    "Changes": [
        {
            "Action": "UPSERT",
            "ResourceRecordSet": {
                "Name": "www.clickplan.net",
                "Type": "A",
                "TTL": 300,
                "ResourceRecords": [
                    {
                        "Value": "This must be elastic beanstalk : FIGURE OUT THIS PART"
                    }
                ]
            }
        }
    ]
}

aws route53 change-resource-record-sets --hosted-zone-idZ1W9BXXXXXXXLB --change-batch file:///root/change-resource-record-sets.json

Check status:

aws route53 get-change --id C2JAIG0XXXXXXX

Helpful output to create JSON file for the aws cli command:

$ aws route53 change-resource-record-sets --generate-cli-skeleton
{
    "HostedZoneId": "", 
    "ChangeBatch": {
        "Comment": "", 
        "Changes": [
            {
                "Action": "UPSERT", 
                "ResourceRecordSet": {
                    "Name": "", 
                    "Type": "SPF", 
                    "SetIdentifier": "", 
                    "Weight": 0, 
                    "Region": "eu-west-1", 
                    "GeoLocation": {
                        "ContinentCode": "", 
                        "CountryCode": "", 
                        "SubdivisionCode": ""
                    }, 
                    "Failover": "PRIMARY", 
                    "MultiValueAnswer": true, 
                    "TTL": 0, 
                    "ResourceRecords": [
                        {
                            "Value": ""
                        }
                    ], 
                    "AliasTarget": {
                        "HostedZoneId": "", 
                        "DNSName": "", 
                        "EvaluateTargetHealth": true
                    }, 
                    "HealthCheckId": "", 
                    "TrafficPolicyInstanceId": ""
                }
            }
        ]
    }

}

# This is an example that creates an A record.
$ aws route53 change-resource-record-sets --cli-input-json '{
    "HostedZoneId": "Z35CNAMBBVZ957",
    "ChangeBatch": {
        "Comment": "This is a test and may be deleted.",
        "Changes": [
            {
                "Action": "CREATE",
                "ResourceRecordSet": {
                    "Name": "noah-test.zephyrhealth.com",
                    "Type": "A",
                    "TTL": 600,
                  "ResourceRecords": [
                    {
                      "Value": "192.168.0.1"
                    }
                  ]
                }
            }
        ]
    }
}'

# You may want to test your new A record using `host`:
$ host noah-test.zephyrhealth.com
noah-test.zephyrhealth.com has address 192.168.0.1

# This updates an existin A record.
$ aws route53 change-resource-record-sets --cli-input-json '{
    "HostedZoneId": "Z35CNAMBBVZ957",
    "ChangeBatch": {
        "Comment": "This is a test A and may be deleted.",
        "Changes": [
            {
                "Action": "UPSERT",
                "ResourceRecordSet": {
                    "Name": "noah-test.zephyrhealth.com",
                    "Type": "A",
                    "TTL": 600,
                  "ResourceRecords": [
                    {
                      "Value": "192.168.1.2"
                    }
                  ]
                }
            }
        ]
    }
}'

# This creates an alias (CNAME) to an A record.
$ aws route53 change-resource-record-sets --cli-input-json '{
    "HostedZoneId": "Z35CNAMBBVZ957",
    "ChangeBatch": {
        "Comment": "This is a test CNAME and may be deleted.",
        "Changes": [
            {
                "Action": "CREATE",
                "ResourceRecordSet": {
                    "Name": "noah-test-cname.zephyrhealth.com",
                    "Type": "CNAME",
                    "TTL": 600,
                  "ResourceRecords": [
                    {
                      "Value": "noah-test.zephyrhealth.com"
                    }
                  ]
                }
            }
        ]
    }
}'

References

AWS CLI Reference

Example for Good Error Message


Technical error code is not useful to the end user. The error page tells the user exactly what they can do to recover from this error.

John Sonmez Book : The Complete Software Developer’s Career Guide

A good way to deal with micromanagers:


Friday, July 21, 2017

Bose SoundTouch Bluetooth Setup on Mac OS

Go to system preferences and click on Pair.  Click on the bluetooth button on the Bose remote till you see 'Ready to Pair'.

You can see the connection established screen on the Bose SoundTouch app.

You can ignore the 'Not Connected' message in the Mac system preferences. It will work fine.