Skip to content

doutorfinancas/pun-sho

Repository files navigation

pun-sho

Latest Release CircleCI codecov Github Actions APACHE-2.0 License CodeFactor

PUNy-SHOrtener - Yet Another URL Shortener

Panchooooo

Spelled pan‧cho - ˈpãnʲ.t͡ʃo

But, Why?

because

props to XKCD

We decided that we need something that doesn't exist on every other project (mix all of them, and you would have it).

So, we decided to make yet another URL shortener.

Usage

You can clone this repo or use one of the precompiled binaries available in the release section

You can also use docker, pre-made images are available for you at docker pull ghcr.io/doutorfinancas/pun-sho:latest or you can:

# this API_PORT is defined in .env file or put it in env itself
export API_PORT=8080
docker run --env-file=.env -p 8080:${API_PORT} -t ghcr.io/doutorfinancas/pun-sho:latest pun-sho 

You should also copy the .env.example to .env and fill the values for the database. you can use either cockroach or postgres as value for the DB_ADAPTOR

If you want to use cockroach, you can create a free account here

Bellow are a few examples of how to use the API. You can find the documentation here

Create a short link

read -r -d '' BODY <<EOF
{                
  "link": "https://www.google.pt/",
  "TTL": "2023-03-25T23:59:59Z",
  "redirection_limit": 5,
  "qr_code": {
    "create": true,
    "width" : 50,
    "height": 50,
    "foreground_color": "#000000",
    "background_color": "#ffffff",
    "shape": "circle"
  }
}
EOF

# you could use "background_color": "transparent" to request a png without background
# by setting env property QR_PNG_LOGO to a png filepath, 
# it will overlay the logo on qrcode center

curl -XPOST http://localhost:8080/api/v1/short \
  -H 'token: ThisIsA5uper$ecureAPIToken' \
  -H 'Content-Type: application/json' \
  -d $BODY

This would render an answer like:

{
  "id":"4b677dfe-e17a-46e7-9cd2-25a45e8cb19c",
  "link":"https://www.google.pt/",
  "TTL":"2023-03-25T23:59:59Z",
  "redirection_limit": 5,
  "created_at":"2023-03-20T10:50:38.399449Z",
  "deleted_at":null,
  "accesses":null,
  "qr_code": "data:image/png;base64,ASfojih134kjhas9f8798134lk2fasf...",
  "short_link":"https://env.configured.domain/s/SEdeyZByeP",
  "visits":0,
  "redirects":0
}

Edit a short link

It's also possible to edit a shortlink, by using the PATCH method

read -r -d '' BODY <<EOF
{                
  "link": "https://www.google.pt/",
  "TTL": "2023-03-25T23:59:59Z",
  "redirection_limit": 5,
  "cancel": false,
}
EOF

curl -XPATCH http://localhost:8080/api/v1/short/4b677dfe-e17a-46e7-9cd2-25a45e8cb19c \
  -H 'token: ThisIsA5uper$ecureAPIToken' \
  -H 'Content-Type: application/json' \
  -d $BODY

The response is equal to the POST one:

{
  "id":"4b677dfe-e17a-46e7-9cd2-25a45e8cb19c",
  "link":"https://www.google.pt/",
  "TTL":"2023-03-25T23:59:59Z",
  "redirection_limit": 5,
  "created_at":"2023-03-20T10:50:38.399449Z",
  "deleted_at":null,
  "accesses":null,
  "qr_code": "data:image/png;base64,ASfojih134kjhas9f8798134lk2fasf...",
  "short_link":"https://env.configured.domain/s/SEdeyZByeP",
  "visits":0,
  "redirects":0
}

Preview QR code

If you want to preview the QR code only, you can use the preview endpoint with the same body as above No TTL exists in that endpoint though (as its only preview mode), and the link is exactly the one you sent

read -r -d '' BODY <<EOF
{                
  "link": "https://www.google.pt/",
  "qr_code": {
    "create": true,
    "width" : 50,
    "height": 50,
    "foreground_color": "#000000",
    "background_color": "#ffffff",
    "shape": "circle"
  }
}
EOF

curl -XPOST http://localhost:8080/api/v1/preview \
  -H 'token: ThisIsA5uper$ecureAPIToken' \
  -H 'Content-Type: application/json' \
  -d $BODY 

Get statistics from a visited link

curl -H 'token: ThisIsA5uper$ecureAPIToken' http://localhost:8080/api/v1/short/c62cbe57-7e45-4e87-a7c1-11cfb006870b 

This would render an answer like ("visits" and "redirects" will only be equal to 1 if you access the link once):

{
  "id":"c62cbe57-7e45-4e87-a7c1-11cfb006870b",
  "link":"https://www.google.pt/",
  "TTL":"2023-03-25T23:59:59Z",
  "redirection_limit": 5,
  "created_at":"2023-03-19T18:56:06.8404Z",
  "deleted_at":null,
  "accesses": [
    {
      "created_at":"2023-03-19T18:56:09.615403Z",
      "meta": {
        "meta_collection": [
          {
            "name":"Accept-Encoding",
            "values":["gzip, deflate, br"]
          },
          {
            "name":"Accept-Language",
            "values":["pt-PT,pt;q=0.9,en-GB;q=0.8,en;q=0.7,en-US;q=0.6,es;q=0.5"]
          }
        ]
      },
      "user_agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36",
      "ip":"127.0.0.1",
      "extra":"Map: map[]",
      "os":"macOS 10.15.7",
      "browser":"Chrome 110.0.0.0",
      "status":"redirected"
    }
  ],
  "short_link":"https://env.configured.domain/s/SE345ZByeP",
  "visits":1,
  "redirects":1
}

Get a list of links

curl -H 'token: ThisIsA5uper$ecureAPIToken' http://localhost:8080/api/v1/short/?limit=20&offset=0

Which will return a list of short links, using pagination.

Deleting a link to make it inaccessible

curl -H 'token: ThisIsA5uper$ecureAPIToken' -XDELETE http://localhost:8080/api/v1/short/c62cbe57-7e45-4e87-a7c1-11cfb006870b

Tests

You can execute all the tests of the application by using make test.

If you want to only execute one of the types we have, then you can run:

  • make test/go for Go tests
  • make test/http-requests for http-requests tests (uses Docker but you can, locally, execute them through Intellij IDEA or through http-client cli).

DB migrations

This project uses database migrations. For any changes on the DB structure to be dealt with or replicated or rolled-back we use a migration tool.

Install golang-migrate

# cockroach
go install -tags 'cockroachdb' github.com/golang-migrate/migrate/v4/cmd/migrate@latest
# postgres
go install -tags 'postgres' github.com/golang-migrate/migrate/v4/cmd/migrate@latest

Create new migration files

make migration/create

Migrate

To go versions up:

make migration/up

To go versions down:

make migration/clean

Releases

We are currently working actively in the project and as such there still isn't a closed API.

However, we are already using it in production, in our own projects.

We consider this to be an MVP and as such use it at your own risk.

we will be releasing 0.X until we bind a contract to the API

Next Steps

  • Define stable contract version
  • Add GUI (web based) with:
    • Base login page
    • Dashboard with overview
    • Ability to track a specific link data
    • Show list of links with filters (by date range, status)
  • Allow better security (variable API Key, oauth2 or even simple jwt)
  • Add GitHub pages with openapi/swagger definition #19