Hi, I'm Emran Hossain
Full-Stack Software Engineer
Building robust and scalable web applications with modern technologies. Passionate about creating efficient, user-friendly solutions.

About Me
A versatile full-stack software engineer with two years of professional experience building modern web applications and scalable backend systems.
My Expertise
Specialized in full-stack development with Next.js, Node.js, and TypeScript. Experienced in building responsive UIs, RESTful APIs, GraphQL, and database integration.
Experience
Currently working as a Software Engineer at Gain Solutions, with previous experience at ARITS Limited. Also providing freelance services on Fiverr since 2020.
Education
Bachelor of Science in Computer Science and Engineering from North South University, Dhaka, Bangladesh. Graduated in June 2023.
I'm a passionate software engineer with a strong foundation in both frontend and backend development. My journey in software engineering began during my university years, and I've since grown into a versatile developer capable of building complete web applications from concept to deployment.
I enjoy solving complex problems and continuously learning new technologies to improve my skills. When I'm not coding, I'm exploring new tech trends, contributing to open-source projects, or helping clients achieve their business goals through effective software solutions.
Skills & Expertise
A comprehensive set of technical skills and technologies I've worked with throughout my career.
Work Experience
My professional journey as a software engineer across different companies and roles.
Software Engineer | Backend
- Designed and optimized EasyDesk's backend, building performant GraphQL APIs with ms response times.
- Developed serverless functions on AWS Lambda, managed AWS EC2 for scalability, and containerized microservices with Docker.
- Focused on security, encryption, and authentication, ensuring a reliable and efficient system.
Software Engineer | Fullstack
- Spearheaded the development of sophisticated, responsive user interfaces, integrating advanced features like real-time data synchronization, global state management, and multi-factor authentication.
- Enhanced backend solutions with Next.js, implementing Drizzle ORM for seamless database interactions, leading to improved data consistency and query performance.
- Utilized OpenAI's free tiers for automatic topic extraction from blog content, enabling intelligent content categorization and improved SEO.
Junior Software Engineer | Fullstack
- Designed over a dozen of complex and responsive UIs, implementing advanced features like global state management and authentication systems.
- Developed and published a couple of reusable npm packages.
- Built multiple backend solutions using Next.js for file handling, integrating databases such as MongoDB and PostgreSQL, and applied cryptography for data security.
Internship Trainee | Frontend
- Developed web applications using Next.js, focusing on server-side rendering and creating engaging user interfaces with versatile animation libraries.
- Gained experience in building and integrating RESTful API endpoints and managed data fetching and state with modern libraries in front-end applications.
Freelancer | WordPress Developer
- Delivered high-quality WordPress development services, focusing plugin integration, and responsive design.
- Enhanced website functionality through API integrations, and performance optimizations.
- Skilled in implementing e-commerce solutions using WooCommerce, SEO enhancements, and content management systems to meet specific client needs.
Featured Projects
A selection of projects I've worked on throughout my career, showcasing my technical skills and problem-solving abilities.
easydesk.app
Backend | Dec 2024
Backend system with high-performance GraphQL APIs and AWS infrastructure
- Developed high-performance GraphQL APIs with millisecond response times, leveraging Node.js, AWS Lambda, and EC2 for scalability and efficiency.
- Optimized backend architecture, implementing secure authentication, encryption, and Docker-based deployments to enhance system reliability.
betterbangladesh.io
Backend | Aug 2024
Robust backend infrastructure with MongoDB integration and secure authentication
- Developed a robust backend infrastructure using Next.js and TypeScript, integrating MongoDB for data storage and JWT for authentication.
- Implemented file handling, dynamic file serving, CRUD APIs, and secure authentication/authorization mechanisms for efficient data operations and user management.
aritsltd.com
Frontend | Feb 2024
Modern frontend with WordPress CMS integration and optimized content delivery
- Built the front-end using Next.js and TypeScript, utilizing WordPress as a backend CMS, combining modern web technologies with robust content management.
- Features a mix of static pages and dynamic content (blogs, case studies) optimized through Incremental Static Regeneration, balancing performance with up-to-date information.
@aritslimited/commitlint
Developer | Nov 2023
Custom commit linting tool with Jira integration
- Created a customized commit linting tool that integrates with Jira, enforcing commit message standards and automating issue tracking in the development workflow.
- Provides optional branch naming convention enforcement and requires specific environment variables for Jira integration, offering easy installation and configuration through npm or other package managers.
deep-object-key-alternator
Developer | Oct 2023
Tool for recursively transforming nested object structures
- Developed a tool for recursively transforming nested object structures by renaming keys based on a custom mapping.
- Versatile tool that handles both individual objects and arrays, maintaining array structure while allowing deep key renaming.
merlinapp.co.uk
Fullstack | Mar 2023
Fullstack application with microservice architecture and advanced security features
- Built & collaborated a fullstack application with Next.js 13/TypeScript, PostgreSQL, and Docker, employing a microservice architecture for scalability and maintainability.
- Implemented advanced features including a custom file server, robust cryptography for security, and efficient data handling across microservices.
Latest Articles
Technical articles and tutorials I've published on Medium, sharing insights and solutions from my development experience.
Mastering GraphQL Development with VSCode and Node.js
Thu, 16 Jan 2025
GraphQL has become a game-changer for APIs, offering developers flexibility and efficiency in querying data. Implementing best practices can significantly boost your productivity if you're working on a Node.js project with GraphQL and using Visual Studio Code (VSCode) as your IDE. This guide will walk you through setting up your environment and adopting effective practices for a seamless GraphQL development experience. Photo by GuerrillaBuzz on Unsplash 1. Configure Your GraphQL Environment in VSCode VSCode, with its vast ecosystem of extensions, makes working with GraphQL intuitive. Follow these steps to set up your environment: a. Install Essential VSCode Extensions GraphQL: Language Feature Support: This extension provides IntelliSense, autocompletion, and error highlighting for .graphql files. GraphQL: Syntax Highlighting: Adds syntax highlighting for .graphql files, making them easier to read. b. Configure VSCode for Non-Standard File Extensions If your .graphql files don't have the .graphql extension, you must inform VSCode. Add the following to your workspace settings (.vscode/settings.json): "files.associations": { "*.graphql": "graphql", "*.gql": "graphql", "*.graphqls": "graphql" } This ensures proper syntax highlighting and IntelliSense for your schema files. 2. Organize Your GraphQL Files Well-structured files improve maintainability and collaboration. Here's a suggested structure: src/ ├── graphql/ │ ├── resolvers/ │ │ ├── userResolvers.js │ │ ├── productResolvers.js │ └── typeDefs/ │ ├── user.graphql │ ├── product.graphql ├── server.js Resolvers: Store the business logic for your API. TypeDefs: Keep schema definitions in the dedicated .graphql files. 3. Use a Configuration File A configuration file helps tools like graphql-cli VSCode extensions understand your GraphQL project structure. For example: .graphqlrc.yaml schema: './src/graphql/typeDefs/*.graphql' extensions: languageService: cacheSchemaFileForLookup: true This configuration enables schema autocompletion and error checking across your project. 4. Automate Schema Validation Ensuring your GraphQL schema is valid is critical. Use tools like graphql-cli or eslint-plugin-graphql for validation. a. Install Required Packages npm install --save-dev graphql-cli eslint-plugin-graphql b. Add Validation Scripts In your package.json: "scripts": { "validate:schema": "graphql validate-schema", "lint:graphql": "eslint --ext .js,.graphql src/" } Run these commands regularly to catch issues early. 5. Enable Hot Reloading for GraphQL Hot reloading saves time by automatically reloading your server when schema files change. Use nodemon to enable this feature: Install Nodemon npm install --save-dev nodemon Update nodemon.json { "watch": ["src/graphql/typeDefs/*", "src/graphql/resolvers/*"], "ext": "js,graphql", "exec": "node src/server.js" } Start your server with npx nodemon. 6. Utilize Strong Typing with TypeScript For Node.js projects, TypeScript enhances the developer experience by providing type safety. Tools like graphql-code-generator can generate TypeScript types from your schema. Install GraphQL Code Generator npm install --save-dev @graphql-codegen/cli @graphql-codegen/typescript Generate Types Configure a codegen.yml file: schema: './src/graphql/typeDefs/*.graphql' generates: src/graphql/generated/types.ts: plugins: - typescript Run the generator: npx graphql-codegen 7. Debugging GraphQL Queries VSCode makes debugging GraphQL queries easy with the following tips: a. Use GraphQL Playground GraphQL Playground allows you to test queries and mutations. Many GraphQL server implementations, like apollo-server-express, include this feature by default. b. Enable Logging Add logging middleware to your Express.js server to log incoming GraphQL queries and their execution times: app.use('/graphql', (req, res, next) => { console.log(`GraphQL Query: ${req.body.query}`); next(); }); 8. Optimize Performance a. Caching Use tools like dataloader to batch and cache database requests efficiently. b. Schema Stitching For large-scale projects, use schema stitching or federation to manage multiple schemas. Final Thoughts GraphQL and VSCode form a powerful combination for Node.js developers. You can create a smooth, productive workflow by setting up your environment, organizing files, and automating validation. Adopting these best practices will help you write clean, efficient, and maintainable GraphQL code, whether you're building simple APIs or complex applications.
How to Start Coding: Beginner-Friendly Programming Languages
Wed, 8 Jan 2025
Photo by Chris Ried on Unsplash Starting your coding journey can feel overwhelming, but choosing the correct programming language can make all the difference. Some languages are easier to learn for beginners due to their simplicity, readability, and supportive communities. This guide introduces you to the most beginner-friendly programming languages to help you get started with confidence. Python Why Python? Python is among the most recommended languages for beginners due to its clean syntax and versatility. It’s widely used in web development, data analysis, artificial intelligence, and more. Key Features: Simple and readable syntax. Extensive libraries and frameworks. Tremendous community support for learning resources. Example: print("Hello, World!") This one-liner prints “Hello, World!” demonstrating Python’s simplicity. JavaScript Why JavaScript? JavaScript is essential for web development and allows you to build interactive websites. It’s beginner-friendly and highly versatile. Key Features: It runs directly in the browser — no setup is needed. Large community with abundant tutorials. Great for building dynamic websites. Example: console.log("Hello, World!"); This prints “Hello, World!” to the browser console. Scratch Why Scratch? Scratch is a visual programming language designed for absolute beginners and kids. It’s perfect for understanding programming concepts without writing code. Key Features: Drag-and-drop interface. Encourages creative projects like games and animations. Free and easy to use. Example: Drag the “When green flag clicked” block to start your program. Connect a “Say Hello” block to display a message. HTML & CSS Why HTML & CSS? While not traditional programming languages, HTML and CSS are foundational for web development. They’re beginner-friendly and provide quick, visual results. Key Features: Easy to learn and implement. Immediate results in any browser. Forms the building blocks of the web. Example: <!DOCTYPE html> <html> <head> <title>Hello, World!</title> </head> <body> <h1>Hello, World!</h1> </body> </html> This creates a simple webpage displaying “Hello, World!”. Ruby Why Ruby? Ruby is known for its elegant syntax and beginner-friendly nature. It’s popular in web development, especially with the Ruby on Rails framework. Key Features: Readable and intuitive. Encourages best coding practices. Active and supportive community. Example: puts "Hello, World!" This one-liner outputs “Hello, World!” showcasing Ruby’s simplicity. Java Why Java? Java is an excellent choice for beginners looking to dive into object-oriented programming. It’s widely used in mobile app development, particularly for Android. Key Features: Platform-independent (write once, run anywhere). Strongly typed, which helps beginners learn coding discipline. Extensive documentation and community support. Example: public class Main { public static void main(String[] args) { System.out.println("Hello, World!"); } } This prints “Hello, World!” to the console, demonstrating Java’s structured nature. C Why C? C is a foundational language that teaches you the basics of programming, including memory management and low-level operations. Key Features: Highly efficient and fast. Builds a strong foundation for learning other languages like C++ and Python. Often used in system programming. Example: #include <stdio.h> int main() { printf("Hello, World!\n"); return 0; } This prints “Hello, World!” and introduces you to the structure of C programs. Topics to Explore as a Beginner Once you’ve chosen a programming language, practicing and learning key concepts is vital to building a strong foundation. Here are some essential topics to explore: File System Handling: Learn how to read, write, and manipulate files. Understand file paths and directories. Form Submissions: Understand how to handle form inputs and validate data. Explore methods for sending and receiving data on the web. Data Sorting: Learn basic sorting algorithms like bubble sort, selection sort, and merge sort. Understand how sorting improves data processing. Maps and Sets: Use data structures like maps and sets to store and retrieve data efficiently. Learn their applications in problem-solving. Hashmaps: Understand hash functions and their use in implementing hashmaps. Learn how hashmaps provide constant-time data access. Basic Algorithms: Practice simple algorithms like searching (linear, binary) and recursion. Build a strong problem-solving mindset. Debugging and Error Handling: Learn how to debug code and handle errors gracefully. Explore tools and techniques for identifying and fixing bugs. APIs and Networking: Understand how to interact with APIs and fetch data. Explore concepts like HTTP requests and JSON. Version Control: Get familiar with Git and version control systems. Learn how to manage and collaborate on coding projects. By mastering these topics, you’ll be well-equipped to take on more advanced challenges and create robust applications. Tips for Beginners Start Small: Focus on mastering the basics before diving into complex projects. Practice Regularly: Consistent practice is key to improving your skills. Build Projects: Apply your knowledge by creating small projects like calculators, to-do lists, or simple games. Join a Community: Participate in online forums, coding groups, or local meetups for support and motivation. Use Free Resources: Platforms like Codecademy, freeCodeCamp, and Khan Academy offer excellent beginner courses. Final Thoughts Beginning your coding journey is an exciting adventure. Selecting a beginner-friendly programming language allows you to establish a strong foundation and gradually take on more complex challenges. Keep in mind that the best language to start with is the one that aligns with your interests and goals. Happy coding!

Cybersecurity Trends to Watch in 2025
Mon, 6 Jan 2025
Cybersecurity is an ever-changing field, and as we look towards 2025, we are witnessing a range of new challenges and innovations that are reshaping the digital environment. As cyber threats grow increasingly sophisticated and pervasive, it becomes crucial for businesses, governments, and individuals to proactively adapt. This blog delves into the essential cybersecurity trends to monitor in 2025, offering an in-depth look at anticipated developments and strategies for effective preparation. AI-Powered Cyberattacks and Defenses Artificial intelligence (AI) plays a dual role in the realm of cybersecurity. On one hand, organizations leverage AI technologies to bolster their defense mechanisms, employing machine learning algorithms for threat detection, anomaly recognition, and automated response systems. On the other hand, malicious actors are increasingly harnessing AI to refine their tactics, employing sophisticated techniques to bypass security measures and execute more targeted and effective attacks. This dichotomy highlights the continuous arms race between cybersecurity professionals and cybercriminals in the evolving digital landscape. How AI is Shaping Threats: Automated Attacks: Hackers are deploying AI to automate phishing campaigns and develop adaptive malware that evolves to bypass security measures. Deepfakes: AI-generated deepfakes are used for social engineering attacks, such as impersonating CEOs to authorize fraudulent transactions. Defensive Strategies: AI-Powered Threat Detection: AI tools analyze vast datasets to identify unusual patterns and detect threats in real-time. Behavioral Analytics: Machine learning models monitor user behavior to identify anomalies and prevent insider threats. Rise of Quantum Computing Threats Quantum computing promises unparalleled computational power, but it also seriously threatens current encryption standards. Quantum computers could break widely used cryptographic algorithms, rendering traditional security measures obsolete. Preparing for the Quantum Era: Post-Quantum Cryptography: Organizations are adopting quantum-resistant encryption algorithms to safeguard sensitive data. Early Adoption: Governments and enterprises are investing in quantum-safe technologies to stay ahead of the curve. Increased Focus on Zero Trust Architecture The old way of protecting our digital information, often described as a “castle-and-moat” approach, is not enough anymore. Today, many experts are turning to a new method called Zero Trust Architecture (ZTA) to help defend against modern security threats. This approach assumes that threats could come from anywhere, even from inside the organization, and it focuses on verifying every user and device before granting access. Core Principles of Zero Trust: Verify Every Access: Authenticate and authorize every user and device, regardless of location. Least Privilege Access: Limit users to only the data and systems they need for their role. Continuous Monitoring: Regularly monitor all network activity to identify potential threats. Benefits: Reduces the attack surface. Improves resilience against insider threats. Simplifies compliance with regulations. Expansion of Cyber Insurance As cyberattacks grow in scale and sophistication, businesses turn to cyber insurance to mitigate financial losses. Trends in Cyber Insurance: Increased Premiums: Insurers are raising premiums due to the rising breach cost. Risk Assessments: Policies now require organizations to meet stringent security standards. Coverage for Ransomware: Specialized coverage options for ransomware attacks are becoming more common. What Organizations Should Do: Conduct thorough risk assessments. Implement best practices to qualify for better coverage. Regularly review and update insurance policies. Growing Threat of Ransomware-as-a-Service (RaaS) The ransomware landscape is evolving, with cybercriminals offering Ransomware-as-a-Service (RaaS) to less skilled attackers. Key Characteristics: Accessibility: RaaS platforms make ransomware attacks accessible to a broader range of threat actors. Profit Sharing: Developers earn a share of the profits from successful attacks. Combating RaaS: Strengthen backup and recovery plans. Educate employees on recognizing phishing attempts. Deploy advanced endpoint detection and response (EDR) solutions. IoT and OT Security Challenges The proliferation of Internet of Things (IoT) and Operational Technology (OT) devices has created new vulnerabilities. Risks: Weak Authentication: Many IoT devices lack strong security features. Legacy Systems: OT environments often use outdated systems that are difficult to secure. Solutions: Implement device management and network segmentation. Regularly update and patch IoT/OT devices. Use AI-driven monitoring tools to detect unusual activity. Greater Emphasis on Privacy Regulations Privacy regulations such as GDPR and CCPA have established a foundation for more stringent global data protection laws. What’s New in 2025: Emerging Regulations: New privacy laws are being introduced in Asia, Africa, and Latin America. Fines for Non-Compliance: Regulatory bodies are imposing heavier penalties for data breaches. Compliance Strategies: Conduct regular data audits. Implement privacy-by-design principles. Train employees on data protection best practices. Cybersecurity Workforce Shortages The demand for cybersecurity professionals continues to outpace supply, creating a global workforce shortage. Addressing the Gap: Upskilling Programs: Organizations are investing in training programs to reskill employees. Automation: Automating routine tasks to reduce reliance on human intervention. Diversity Initiatives: Encouraging women and underrepresented groups to enter the cybersecurity field. Real-Time Threat Intelligence Sharing Collaboration is key to combating cyber threats. Organizations are increasingly participating in threat intelligence-sharing networks. Benefits: Faster identification of emerging threats. Improved defense strategies through shared insights. Enhanced cross-industry collaboration. Best Practices: Join trusted threat intelligence platforms. Regularly update and act on shared intelligence. Maintain strong data-sharing policies. Human Factor in Cybersecurity Despite advanced technologies, human error remains a leading cause of cyber incidents. Reducing Human Risk: Comprehensive Training: Regular cybersecurity training for employees. Simulated Attacks: Conduct phishing simulations to assess awareness. User-Friendly Tools: Implement intuitive tools to reduce user errors. Final Thoughts Cybersecurity is like a game of chess. Just as a good player anticipates their opponent’s moves and adapts their strategy accordingly, organizations must stay ahead of evolving cyber threats by continuously assessing and improving their defenses. If you’re not thinking several steps ahead, you might find yourself in checkmate before you even realize it!

Unlocking GraphQL: Master Queries and Mutations for Modern APIs
Mon, 30 Dec 2024
GraphQL has transformed the way developers interact with APIs by providing a flexible, efficient, and user-friendly approach. In this blog, we will explore the fundamental concepts of GraphQL — queries and mutations. We’ll look into what they are, how they function, and why they are crucial for modern application development. What is GraphQL? GraphQL is a way to get information from websites or apps that was created by Facebook in 2012 and made available to everyone in 2015. Think of it as a smart way to ask for data. Unlike traditional methods, where you might have to visit different web pages to gather different pieces of information, GraphQL lets you ask for exactly what you want all at once. This means you can get just the details you need in one simple request, making it quicker and easier to get the information you’re looking for. Key Features of GraphQL Single Endpoint: All requests are routed through a single endpoint. Flexible Queries: Fetch only the required fields, reducing over-fetching and under-fetching. Strongly Typed Schema: Enforces data structure and validation. Real-time Updates: Supports subscriptions for real-time updates. Understanding Queries in GraphQL A query in GraphQL is used to fetch data from the server. Think of it as the “read” operation in CRUD (Create, Read, Update, Delete). Anatomy of a Query Here’s a basic GraphQL query example: query { user(id: "1") { id name email } } Explanation: query: Specifies the operation type. user: Refers to the data entity. id: “1”: Acts as an argument to filter the user by ID. id, name, email: The specific fields to retrieve. Server Response The server responds with JSON: { "data": { "user": { "id": "1", "name": "John Doe", "email": "john.doe@example.com" } } } Benefits of Queries Precise data fetching. Reduced payload size. Simplifies client-side logic. Exploring Mutations in GraphQL A mutation in GraphQL is used to modify data on the server, encompassing create, update, and delete operations. Anatomy of a Mutation Here’s an example of a mutation to add a new user: mutation { addUser(input: { name: "Jane Doe", email: "jane.doe@example.com" }) { id name email } } Explanation: mutation: Specifies the operation type. addUser: The mutation name. input: The data being sent to the server. id, name, email: Fields to return after the operation. Server Response The server responds with the new user data: { "data": { "addUser": { "id": "2", "name": "Jane Doe", "email": "jane.doe@example.com" } } } Benefits of Mutations Structured and predictable data modifications. Immediate feedback via returned fields. Reduces the need for additional requests. How GraphQL Works Behind the Scenes Schema At the heart of GraphQL is its schema, which defines the types and operations available. Example Schema: type User { id: ID! name: String! email: String! } type Query { user(id: ID!): User } type Mutation { addUser(input: AddUserInput): User } input AddUserInput { name: String! email: String! } Resolver Functions Resolvers are functions that handle the logic for fetching or modifying data. Example Resolver for Queries: const resolvers = { Query: { user: (parent, args, context) => { return context.db.users.find((user) => user.id === args.id) } } } Example Resolver for Mutations: const resolvers = { Mutation: { addUser: (parent, { input }, context) => { const newUser = { id: generateId(), ...input } context.db.users.push(newUser) return newUser } } } Execution Flow Client sends a query or mutation. GraphQL parses and validates the request. Resolvers execute logic to fetch or modify data. Response is sent back to the client. Queries vs. Mutations Aspect Query Mutation ------------- ------------ --------------------------- Purpose Fetch data Modify data Operation Read Create, update, or delete Idempotency Yes No Structure Simple Includes input payload Real-World Use Cases Queries Fetch user profiles for a dashboard. Retrieve paginated lists of products. Load detailed information for a blog post. Mutations Registering a new user. Updating product stock levels. Deleting outdated records. Final Thoughts GraphQL is a tool that helps developers create better and more efficient ways for applications to communicate with each other. By learning to use GraphQL effectively, they can build strong, capable, and more enjoyable apps. This makes it easier for users to get the information they need and has a smoother experience. Are you ready to dive into GraphQL and transform how you build APIs? Start exploring today!
Next.js is a robust React framework that provides an excellent developer experience for building server-side rendered and statically generated web applications. By default, Next.js serves static files from the public directory bundled during build time. However, this approach only works for static resources that must be served at runtime. The Solution To serve these dynamically uploaded files, we can create a custom API route that reads the files from our chosen directory and serves them on demand. This approach gives us more control over how the files are served and allows us to implement additional features like image resizing and format conversion. Let’s dive into the code that makes this possible: import path from "path" import fs from "fs" import { NextRequest, NextResponse } from "next/server" import { fileTypeFromBuffer } from "file-type" import sharp from "sharp" export async function GET(req: NextRequest, res: NextResponse) { const DEFAULT_WIDTH = 1280 const DEFAULT_HEIGHT = 620 const DEFAULT_QUALITY = 75 const resource = req.nextUrl.searchParams.get("resource") const width = req.nextUrl.searchParams.get("w") ? parseInt(req.nextUrl.searchParams.get("w") || DEFAULT_WIDTH.toString()) : undefined const height = req.nextUrl.searchParams.get("h") ? parseInt(req.nextUrl.searchParams.get("h") || DEFAULT_HEIGHT.toString()) : undefined let quality = req.nextUrl.searchParams.get("q") ? parseInt(req.nextUrl.searchParams.get("q") || DEFAULT_QUALITY.toString()) : DEFAULT_QUALITY quality = quality > 100 ? 100 : quality console.log(__dirname, resource, width, height, quality) if (!resource) { return new NextResponse(null, { status: 400, }) } const filePath = path.join(process.cwd(), process.env.RESOURCE_PATH || "resources", resource as string) console.log("filePath >>> ", filePath) try { if (fs.existsSync(filePath)) { const fileBuffer = fs.readFileSync(filePath) // Synchronously read the file into a buffer const contentType = (await fileTypeFromBuffer(fileBuffer).then((e) => e?.mime)) || "application/gzip" // Extract the content type console.log("contentType >>> ", contentType) // + if the content type is an image, resize it to the specified dimensions & quality if (contentType.startsWith("image")) { let image = sharp(fileBuffer) if (width) { image = image.resize(width || undefined, height || undefined, { fit: "inside" }) } const resizedBuffer = await image.webp({ quality }).toBuffer() return new NextResponse(resizedBuffer, { headers: { "Content-Type": "image/webp", }, }) } // * return the file buffer as is return new NextResponse(fileBuffer, { headers: { "Content-Type": contentType, }, }) } return new NextResponse(null, { status: 404, }) } catch (error) { console.error("Error retrieving resource: ", error) return new NextResponse(null, { status: 500, }) } } Let’s break down this code and understand how it works: We import necessary modules, including path and fs for file system operations, NextRequest and NextResponse from Next.js, fileTypeFromBuffer to determine file types, and sharp for image processing. The GET function handles incoming requests to our API route. We extract query parameters from the request URL, including the resource name and optional width, height, and quality parameters for image resizing. We construct the file path using process.cwd() and an optional RESOURCE_PATH environment variable. If the file exists, we read it into a buffer and determine its content type. For image files, we use the sharp library to resize the image if width and height parameters are provided. We convert the image to WebP format for better performance. We serve the file buffer with the appropriate content type for non-image files. If the file doesn’t exist, we return a 404 status code. Any errors during this process are caught and result in a 500 status code. Using the API To use this API, you would typically make a GET request to the endpoint where this route is set up, including the necessary query parameters. For example: /api/resource?resource=example.jpg&w=800&h=600&q=80 This would serve the file “example.jpg” from your resources directory, resizing it to 800×600 pixels with 80% quality if it’s an image. Conclusion By implementing this custom API route, you can serve dynamically uploaded files in your Next.js application from any directory you choose. This approach gives you fine-grained control over how files are served and allows for on-the-fly image processing. Remember to secure this endpoint appropriately and consider implementing caching mechanisms for better performance in a production environment.
Get In Touch
Have a project in mind or want to discuss potential opportunities? Feel free to reach out!
Phone
+8801676987366
emranffl.biz@gmail.com
Location
Dhaka, Bangladesh
Send Me a Message
Fill out the form below and I'll get back to you as soon as possible.