A simple media storage server for storing images and videos of various formats.
This project provides a basic template for building a Go media storage server. It includes CRUD functionality for both folders and images. The images are stored within a folder which creates a more structured storage system. URLs are generated for use in displaying the media stored. The /images
endpoints can be used to store both image and video media.
All endpoints will be preceded by the version. Excluding the /uploads
endpoint which will remain constant throughout the versions.
Acceptable version endpoints are...
- /v1/
- Image & video storage.
- Folders for sorting images.
- Metadata storage in a database.
- Generate a URL to display the media stored.
- Generate reports and have them sent to your email.
- Cache for quick media and folder retrieval.
- Duplicate images are stored only once on the disk.
- Supported media formats: [JPEG, PNG, WEBP, BMP, TIFF, ICO, MP4]
Follow these steps to get the project up and running on your local machine.
- Go (1.16 or higher)
- PostgreSQL database
- Git (optional)
- Clone the repository (if you haven't already):
git clone https://github.com/Azpect3120/MediaStorageServer.git
- Set up your PostgreSQL database and configure the connection details in the
.env
file:
# This URL can be found in the dashboard of most PSQL hosts,
# or it can be constructed using the required pieces
db_url=your-connection-url-here
# For more information visit this link:
# https://www.hostinger.com/tutorials/how-to-use-free-google-smtp-server
smtp_email=your-email-here
smtp_password=your-email-app-password-here
- Install dependencies:
go mod tidy
- Define port (optional):
The port can be changed from the default (:3000) to whatever port you would like, this can be done by updating your environment.
export MSS_PORT="<port>"
NOTE: Updating the .env file will also update the port.
MSS_PORT="<port>"
- Build and run the server:
go build -o ./bin/server cmd/mediaStorageServer/main.go
./bin/server
Your media storage server should now be running on http://localhost:3000
.
The server's port can be changed in the cmd/mediaStorageServer/main.go
file:
err := server.Run("NEW PORT HERE")
Once the server is up and running you will need to connect to a PostgreSQL database. If you would like the code to work out of the box, you may copy the database schema provided below.
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
CREATE TABLE IF NOT EXISTS folders (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
name VARCHAR(32) UNIQUE,
createdAt TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE IF NOT EXISTS images (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
folderId UUID REFERENCES folders(id) ON DELETE CASCADE,
name TEXT,
size BIGINT,
type TEXT,
uploadedAt TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
To create a folder to begin storing images, send a POST
request to the /folders
endpoint.
NOTE: The name provided must be unique. Response will return an error if the name is invalid.
{
"name": "folder-name-here"
}
Ex. Response
{
"folder": {
"ID": "generated-id-here",
"Name": "folder-name-here",
"CreatedAt": "timestamp"
},
"status": 201
}
Folder meta data and images can be viewed by sending a GET
request to the /folders/<folder_id>
endpoint.
NOTE: If a folder is not found, a PSQL error will be returned with a 400
error code.
GET http://localhost:3000/<version>/folders/<folder_id>
Ex. Response
{
"folder": {
"ID": "generated-id-here",
"Name": "folder-name-here",
"CreatedAt": "timestamp"
},
"count": 1,
"images": [
{
"ID": "image-id",
"FolderId": "generated-id-here",
"Name": "image-name.jpg",
"Size": 940184,
"Format": "image/jpeg",
"UploadedAt": "timestamp",
"Path": "uploads/generated-id-here/image-id.jpg"
}
],
"status": 200
}
Folder name can be updated by sending a PUT
request to the /folders/<folder_id>
endpoint.
NOTE: Folder names must be valid, if a name is provided that is not valid, it will be cleaned as best as possible. If it cannot be cleaned then an error will be thrown.
{
"name": "newFolderName"
}
Ex. Response
{
"folder": {
"ID": "folderIDHere",
"Name": "newFoldername",
"CreatedAt": "timestamp"
},
"status": 200
}
A folder can be deleted by sending a DELETE
request to the /folders/<folder_id>
endpoint. Nothing is returned from this request unless an error is encountered.
NOTE: Images will be deleted when its parent folder is deleted.
DELETE http://localhost:3000/<version>/folders/<folder_id>
Images can be uploaded through forms on a web application. Each "flavor" or framework will do it slightly differently the only information that must remain constant is that the image must be uploaded from a form with the name media_upload
. Send a POST
request to the /images/<folder_id>
endpoint with the form data. The endpoint response will be stored in the data
variables in the following examples.
HTML Example
<input type="file" id="fileInput" />
<button onclick="uploadFile()"> Upload </button>
<script>
function uploadFile() {
const fileInput = document.getElementById("fileInput");
const file = fileInput.files[0];
const formData = new FormData();
formData.append("media_upload", file);
fetch("http://localhost:3000/<version>/images/<folder_id>", {
method: "POST",
body: formData,
})
.then(res => res.json())
.then(data => console.log(data));
}
</script>
React Example
import React, { useState } from "react";
function FileUploadComponent () {
const [file, setFile] = useState(null);
const handleFileChange = (event) => {
setFile(event.target.files[0]);
};
uploadFile = () => {
if (!file) {
console.error("No file selected.");
return;
}
const formData = new FormData();
formData.append("media_upload", file);
fetch("http://localhost:3000/<version>/images/<folder_id>", {
method: "POST",
body: formData,
})
.then(res => res.json())
.then(data => console.log(data));
};
return (
<>
<input type="file" onChange={handleFileChange} />
<button onClick={uploadFile}> Upload </button>
</>
)
}
export default FileUploadComponent;
Ex. Response
{
"image": {
"ID": "image-id",
"FolderId": "generated-id-here",
"Name": "image-name.jpg",
"Size": 940184,
"Format": "image/jpeg",
"UploadedAt": "timestamp",
"Path": "uploads/generated-id-here/image-id.jpg"
}
}
An images metadata can be viewed by sending a GET
request to the /images/<image_id>
endpoint. The path
property that is returned can be used to display the image.
GET http://localhost:3000/<version>/images/<image_id>
Ex. Response
{
"image": {
"ID": "image-id",
"FolderId": "generated-id-here",
"Name": "image-name.jpg",
"Size": 940184,
"Format": "image/jpeg",
"UploadedAt": "timestamp",
"Path": "uploads/generated-id-here/image-id.jpg"
},
"status": 200
}
In web applications, the images can be displayed using their path, which can be found in the image metadata. Simply use the path as the src
attribute in any web application.
<img src="http://localhost:3000/uploads/<folder_id>/<image_id>" alt="Media Storage Image">
An image can be deleted by sending a DELETE
request to the /images/<image_id>
endpoint. Nothing is returned from this request unless an error is encountered.
DELETE http://localhost:3000/<version>/images/<image_id>
A folder report can be generated and sent to your email by sending a GET
request to the /reports/:id/:email
endpoint.
GET http://localhost:3000/<version>/reports/<folder_id>/<your_email>
Contributions are welcome! If you'd like to contribute to this project, please follow these steps:
- Fork the project.
- Create a new branch for your feature or bug fix.
- Make your changes.
- Test your changes thoroughly.
- Create a pull request.
The project is licensed under username the MIT License