Shurly, this is a URL shortener with API management

Overview

Shurly

Shurly, this is a URL shortener with API management

Features

  • Management of destinations through a REST'ish API
  • Permanent/temporary redirects; permanent redirect can not be changed after creation
  • Add notes to destinations to keep track of where destinations are being used
  • Track all hits on destinations, with user agent and ip addres (if possible)
  • Audit log for all creative/destructive management actions

Quick usage

# Create destination
curl -v -H 'Content-Type: application/json' \
    -H 'Authorization: Bearer tokentokentoken' \
    -d '{ "slug": "the-one", "url": "https://www.example.com/" }' \
    http://localhost:7000/api/destinations

# The redirect
curl -v http://localhost:7000/the-one

# Response:
# < HTTP/2 307
# < Location: https://www.example.com/

Getting started

There are a couple of ways to run this, all depending on your preference:

Shurly can be directly installed with cargo install shurly, this will place a shurly binary in your path (if the Cargo installation directly is in your PATH).

Building it yourself is also possible, of course, there are a couple more options. To start, you need to clone the repo.

git clone [email protected]:workplacebuddy/shurley.git

Then it's only a cargo run away. If Docker has your preference, then building it is also possible.

docker build --tag shurly .

Running it is the same as for all Docker container.

docker run --rm --interactive --tty --publish 7000:7000 shurly .

# for short
docker run --rm -it -p 7000:7000 shurly .

Usage

Shurly has a very simple REST'ish interface to management the destinations and its properties.

The root

Everything that is not matched by an API route will be handled by the root as a fallback, this root will look up a destination based on its path and will either redirect to that destination or show a 404.

Redirects are done based on the isPermanent property of a destination; Permanent redirects are done with the 308 (Permanent Redirect) status code and the temporary redirect uses the 307 (Temporary Redirect) redirect. Both will set the Location header to the associated URL.

Management

Only authorized users can manage destinations and need to get a token to access the other API endpoints.

curl -v -H 'Content-Type: application/json' \
    -d '{ "username": "admin", "password": "verysecret" }' \
    http://localhost:7000/api/users/token

# < { "data": { "type": "Bearer", "access_token": "some token" } }

To create destinations the /api/destinations URL can be posted to with a payload to describe what needs to happen when.

curl -v -H 'Content-Type: application/json' \
    -H 'Authorization: Bearer tokentokentoken' \
    -d '{ "slug": "some-easy-name", "url": "https://www.example.com/" }' \
    http://localhost:7000/api/destinations

# < { "data": { "id": "<uuid>", "slug": "some-easy-name" ... } }

Optionally you can send the isPermanent property, to indicate what kind of redirect should be used. Permanent redirects can not be changed after they are created.

Updating a destination happens in the same fashion.

curl -v XPATCH -H 'Content-Type: application/json' \
    -H 'Authorization: Bearer tokentokentoken' \
    -d '{ "url": "https://www.example.com/", "isPermanent": true }' \
    http://localhost:7000/api/destinations/<uuid>

# < { "data": { "id": "<uuid>", "slug": "some-easy-name" ... } }

The slug can not be changed after creation. Changing the isPermanent flag to true is possible, not the other way around. When isPermanent is true, updating the url will fail.

To remove the destination, a DELETE endpoint is available.

curl -v XDELETE \
    -H 'Authorization: Bearer tokentokentoken' \
    http://localhost:7000/api/destinations/<uuid>

This will soft-delete the destination; creating a new destination with the same slug is not possible: creativity is key.

There are a bunch more interactions available, but this should get you going.

With a PostgreSQL database

By default Shurly runs its database in memory, loosing all data when it exits. This is not an ideal scenario when running Shurly in a production setting. This is why Shurly also comes with support for storing its database in a PostgreSQL database. To use this there is an optional feature that can be added to the installation.

# Directly with Cargo
cargo install shurly --features postgres

# Run locally
cargo run --features postgres

# Docker build (running is the same)
docker build --build-arg SHURLY_FEATURES=postgres --tag shurly .

An extra requirement is needed to actually run Shurly with a database, that is an actual database. This can be setup separately, or the Docker Compose setup can be used, which will run a PostgreSQL server container.

A simple docker compose up will get you started. Use docker compose up --build to rebuild the Shurly image.

The Docker Compose setup also runs the Docker version of Shurly, this might not be ideal for fast development iterations. Docker Compose provides the option to only run a single container of the setup.

# `the-data` is the name of the PostgreSQL service
docker compose up the-data

When running it without Docker, there needs to be a DATABASE_URL environment variable.

Pre-built Docker images

For those who like to use Docker, but don't want to go through the hassle of building the images; pre-built images are available:

Configuration

When running with the defaults, missing configuration has a sane default oris automatically generated. For development this is fine, but running it in production has a different set of requirements. All configuration is done through environment variables.

Setup logging

tracing is used for all logging (optional)

RUST_LOG=shurly=debug,tower_http=debug

Encoding secrets

Secret for encoding JWT tokens, make sure this is long enough (optional, default: some random string)

JWT_SECRET=

Database connection

Connection string for PostgreSQL server (only required for postgres feature). When running the Docker Compose setup this will be provided.

DATABASE_URL=

The actual server

To communicate with the outside world, Shurly needs to bind to an address to accept connections.

# Address for Shurly to bind to
ADDRESS=0.0.0.0:7000

# Override just the port to run Shurly on
PORT=7000

Initial user credentials

On the first run there is a user created with some randomly generated credentials; These credentials are displayed in the server log. The initial credentials can be changed with the INITIAL_USERNAME and INITIAL_PASSWORD environment variables. When using these variables, they will not be output to the log.

  • INITIAL_USERNAME: Username of the first user for the first run (optional, default: some UUIDv4)
  • INITIAL_PASSWORD: Password of the first user for the first run (optional, default: something random)

The environment variables can be set in a .env file, see .env.default for an example.

PostgreSQL database migrations

Shurly uses SQLx for all PostgreSQL database interactions, migrations are run automatically on start up.

The migration files can be found in ./migrations and are sorted on filename.

Development

Working with migrations can be a bit of a hassle, the project does not build properly without a valid database connection and the right schema. The Docker image uses the SQLX_OFFLINE=true environment variable to use the cached data inside the sqlx-data.json file. Running a compiled version of Shurly will automatically run the migrations -- getting it compiled is the trick :)

Using the SQLx CLI adds a couple of nicities to work with migrations.

  • Install with: cargo install sqlx-cli, or with other options.
  • Make sure the DATABASE_URL environment variable is set
  • To start: cargo sqlx migrate run
  • To revert: cargo sqlx migrate revert

Things to to (maybe)

  • Endpoints to expose some statistics, data is already captured
  • Track incoming parameters in hits, maybe?
  • Add aliases for destinations, so hits count for the original
  • A somewhat attractive 404 page, or a default destination?
  • Description of all the API endpoints
  • Run tests with the postgres feature

And, don't call me Shirly.

You might also like...
Revolt backend API server, built with Rust.

Delta Description Delta is a blazing fast API server built with Rust for Revolt. Features: Robust and efficient API routes for running a chat platform

A wrapper for the Google Cloud DNS API

cloud-dns is a crate providing a client to interact with Google Cloud DNS v1

Obtain (wildcard) certificates from let's encrypt using dns-01 without the need for API access to your DNS provider.

Agnos Presentation Agnos is a single-binary program allowing you to easily obtain certificates (including wildcards) from Let's Encrypt using DNS-01 c

Podman-api-rs - Rust interface to Podman (libpod).

podman-api Rust interface to Podman Usage Add the following to your Cargo.toml file [dependencies] podman-api = "0.1" SSL Connection To enable HTTPS c

An implementation of the ZITADEL gRPC API in Rust.

An implementation of the ZITADEL gRPC API in Rust. Complemented with other useful elements such as ServiceAccount auth.

Hammerspoon plugin and API to interact with Yabai socket directly

Yabai.spoon NOTE: no longer using it or intending to maintain it see #2. Yabai.spoon is lua 5.4 library to interact with yabai socket directly within

๐Ÿ”Œ A curseforge proxy server, keeping your API key safe and sound.

๐Ÿ”Œ CFPROXY - The curseforge proxy server Curseforge has locked down their API and now restricts access without authentification. This spells trouble f

๐Ÿ“Š Collect cloud usage data, so that it can be combined with impact data of Boavizta API.
๐Ÿ“Š Collect cloud usage data, so that it can be combined with impact data of Boavizta API.

cloud-scanner Collect aws cloud usage data, so that it can be combined with impact data of Boavizta API. โš  Very early Work in progress ! At the moment

Stream API for tokio-udp.

UDPflow Stream API for tokio-udp. TCP-like UDP stream use tokio::net::UdpSocket; use tokio::io::{AsyncReadExt, AsyncWriteExt}; use udpflow::{UdpListen

Releases(v0.1.1)
  • v0.1.1(Jul 29, 2022)

    Add user friendly error pages

    When a slug/destination can not be found, show a proper message to the user -- the error code along is not enough, a browser doesn't show those


    Full Changelog: https://github.com/workplacebuddy/shurly/compare/v0.1.0...v0.1.1

    Source code(tar.gz)
    Source code(zip)
  • v0.1.0(Jul 27, 2022)

    Shurly

    Shurly, this is a URL shortener with API management

    Features

    • Management of destinations through a REST'ish API
    • Permanent/temporary redirects; permanent redirect can not be changed after creation
    • Add notes to destinations to keep track of where destinations are being used
    • Track all hits on destinations, with user agent and ip addres (if possible)
    • Audit log for all creative/destructive management actions
    Source code(tar.gz)
    Source code(zip)
Owner
WorkplaceBuddy
Work better with Microsoft 365
WorkplaceBuddy
High-performance link shortener

shorty High-performance link shortener written in Rust ?? Hosting In addition to being easy to build from source, shorty is available as a Docker imag

Caleb Denio 49 Jan 3, 2023
A simple cross-platform remote file management tool to upload and download files over HTTP/S

A simple cross-platform remote file management tool to upload and download files over HTTP/S

sexnine 13 Dec 30, 2022
A SOAP client for Brazilian Central Bank's Time Series Management System

A SOAP client for Brazilian Central Bank's Time Series Management System

Felipe Noronha 3 May 4, 2022
Modrinth API is a simple library for using Modrinth's API in Rust projects

Ferinth is a simple library for using the Modrinth API in Rust projects. It uses reqwest as its HTTP(S) client and deserialises responses to typed structs using serde.

null 20 Dec 8, 2022
The Safe Network Core. API message definitions, routing and nodes, client core api.

safe_network The Safe Network Core. API message definitions, routing and nodes, client core api. License This Safe Network repository is licensed unde

MaidSafe 101 Dec 19, 2022
Proxy copilot api to openai's gpt-4 api

Proxying Copilot API to OpenAI's GPT-4 API Usage Start the Server export GHU_TOKEN=ghu_xxxx; ./copilot2chat Or sh start.sh start # start the server th

Smark 3 Dec 6, 2023
Docker daemon API in Rust

Bollard: an asynchronous rust client library for the docker API Bollard leverages the latest Hyper and Tokio improvements for an asynchronous API cont

Niel Drummond 439 Jan 3, 2023
A pure Rust implementation of WebRTC API

A pure Rust implementation of WebRTC API

WebRTC.rs 2.7k Jan 7, 2023
ZeroNS: a name service centered around the ZeroTier Central API

ZeroNS: a name service centered around the ZeroTier Central API ZeroNS provides names that are a part of ZeroTier Central's configured networks; once

ZeroTier, Inc. 327 Dec 20, 2022
A rust client and structures to interact with the Clever-Cloud API.

Clever-Cloud Software Development Kit - Rust edition This crate provides structures and client to interact with the Clever-Cloud API. Status This crat

Clever Cloud 6 Jun 3, 2022