Skip to content

Commit

Permalink
test: long url
Browse files Browse the repository at this point in the history
  • Loading branch information
AdrianLThomas committed Mar 19, 2024
1 parent 180a97b commit a4fb758
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 10 deletions.
13 changes: 10 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,28 +3,35 @@ A Cloudflare Worker that utilises D1 (SQLite) to create a short url for a provid
This project is an excuse to try out some new tools (namely Cloudflare Workers and D1). However, it also serves as an example of how you can build, deploy and test via CI.

# Building
`.github/workflows` describes the process in a repeatable way.

`.github/workflows` describes the process in a repeatable way.

# Local Development

`package.json` contains some commands for local development. `npm i && npm start` _should_ just work.

# The Design

## Architecture

TODO add diagram

## Shortfalls

### Hashing algorithm

Some decisions have been made in order to keep the project fun, but which would limit real life usage:

- MD5 hashing used (known to eventually conflict)
- The MD5 hash is also split to reduce the size, further increasing the risk of conflict

I may improve this at some point as it's own challenge, but the problem stands today.

## Positives

On the flip side, there's some positives:

- Using Cloudflare Workers is serverless, so less to worry about in terms of scaling
- Using Cloudflare D1, also serverless (SQLite) with automatic read replicas

The Wrangler tooling also works very nicely for local development.


6 changes: 3 additions & 3 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,15 @@ export default {
if (!urlParam) {
return new Response('Invalid url', { status: 400 });
}
let longUrl = ""
let longUrl = '';

// convert to a string - TODO introduce Joi or Zod for validation
try {
longUrl = new URL(urlParam).toString();
} catch (e) {
return new Response('Invalid url', { status: 400 });
}

// hash it
const hashBuffer = await crypto.subtle.digest('MD5', new TextEncoder().encode(longUrl));
const hashArray = Array.from(new Uint8Array(hashBuffer)); // convert buffer to byte array
Expand Down
29 changes: 25 additions & 4 deletions test/integration/create-url.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ describe('Worker', () => {

expect(resp.status).toBe(400);
});

it('should return 400 for invalid url', async () => {
const resp = await worker.fetch('/api/shorten?url=woop', {
method: 'POST',
Expand All @@ -50,8 +50,29 @@ describe('Worker', () => {
expect(resp.status).toBe(400);
});

// should return the same url if it is already shortened (x2 times)
// should return a shortened url for a very long url
// should return a shortened url for a url with special characters
it('should return the same url if it is already shortened (x2 times)', async () => {
const shortenUrl = async () =>
await worker.fetch('/api/shorten?url=https://example.com', {
method: 'POST',
});

const [first, second] = await Promise.all([shortenUrl(), shortenUrl()]);

expect(first.json()).toEqual(second.json());
});

it('should return a shortened url for a very long url', async () => {
const resp = await worker.fetch('/api/shorten?url=https://example-example-example-example-example-example-example-example-example-example-example-example-example-example.com?somequerystring=onetwothree&another=fourfivesixseveneight', {
method: 'POST',
});
const text = await resp.json();

expect(text).toEqual({
shortUrl: 'NjEyZT',
});
expect(resp.status).toBe(200);
});

// should return 400 if attempting to shorten an already shortened url
// should only store a url once if already shortened
});

0 comments on commit a4fb758

Please sign in to comment.