# NextJS + MongoDB setup

**Prerequisites:** [**Set-up NextJS**](/cloud-computing-2023-simpre/seminar-1/set-up-nextjs-project.md) **si** [**Set-up Cloud Storage MongoDB**](/cloud-computing-2023-simpre/seminar-1/set-up-cloud-storage-mongodb.md)

## 1. Initializarea conexiunii NextJS - MongoDB

Pentru ca scopul nostru este configurarea si utilizarea tehnologiilor cloud, nu invatarea unor noi limbaje de programare, majoritatea codului "boilerplate" si functiilor utile vor fi puse la dispozitie de mine si le puteti folosi in proiecte.

### 1.1. Adaugarea fisierului .env

In fisierul .env vom stoca date secrete (cum ar fi connection string-ul pentru BD), care nu ne dorim sa fie versionate cu git (stocate in cod) si sa ajunga publice.

* Accesati proiectul NextJS
* <mark style="color:red;">**Modificati fisierul .gitignore. Adaugati pe ultima linie: .env**</mark>
* In root-ul proiectului, creati fisierul .env

```
# .env
NODE_ENV=development

NEXT_ATLAS_URI=mongodb+srv://<user>:<password>@cluster0.8qqv1kp.mongodb.net/?retryWrites=true&w=majority
NEXT_ATLAS_DATABASE=<your_database_name>

```

* Copiati continutul de mai sus si inlocuiti userul, parola si numele bazei de date create (**ATENTIE: Numele bazei de date !== Numele colectiei create**). Save

### 2.2 Configurarea conexiunii la BD

* In terminal, in folderul proiectului curent, rulati **npm i mongodb**
* Creati in root-ul proiectului un folder cu denumirea lib
* In folderul lib, creati fisierul mongodb.js
* Copy and paste the following

```javascript
// lib/mongodb.js
import { MongoClient, } from 'mongodb';

const uri = process.env.NEXT_ATLAS_URI;
const options = {
	useUnifiedTopology: true,
	useNewUrlParser: true,
};

let mongoClient = null;
let database = null;

if (!process.env.NEXT_ATLAS_URI) {
	throw new Error('Please add your Mongo URI to .env.local');
}

export async function connectToDatabase() {
	try {
		if (mongoClient && database) {
			return { mongoClient, database, };
		}
		if (process.env.NODE_ENV === 'development') {
			if (!global._mongoClient) {
				mongoClient = await (new MongoClient(uri, options)).connect();
				global._mongoClient = mongoClient;
			} else {
				mongoClient = global._mongoClient;
			}
		} else {
			mongoClient = await (new MongoClient(uri, options)).connect();
		}
		database = await mongoClient.db(process.env.NEXT_ATLAS_DATABASE);
		return { mongoClient, database, };
	} catch (e) {
		console.error(e);
	}
}
```

* In root-ul proiectului, creati folderul js
* In folderul js, creati folderul utils
* In folderul utils, creati fisierul functions.js
* Copy and paste the following

```javascript
// js/utils/functions.js
import {connectToDatabase,} from '@/lib/mongodb.js';

export const getCollection = async collectionName => {
	const {database,} = await connectToDatabase();
	return database.collection(collectionName);
};
```

### 2.3 Configurarea API-ului NextJS

* Tot in folderul utils, creati fisierul apiMethods.js

```javascript
// js/utils/apiMethods.js
export const sendOk = (res, data) => {
	res.status(200).json(
		{
			'data': data,
		}
	);
};

export const sendNotFound = (res, message) => {
	res.status(404).json(
		{
			'error': message,
		}
	);
};

export const sendBadRequest = (res, message) => {
	res.status(400).json(
		{
			'error': message,
		}
	);
};

export const sendUnauthorized = (res, message) => {
	res.status(401).json(
		{
			'error': message,
		}
	);
};

export const sendMethodNotAllowed = res => {
	res.status(405).json(
		{
			'error': 'Method not allowed',
		}
	);
};
```

* Pana acum, structura de fisiere din proiect ar trebui sa arate astfel

<figure><img src="/files/LKJXtTYY4pgIh1rcSo8s" alt=""><figcaption></figcaption></figure>

* In folderul pages/api creati fisierul records.js. Acesta va reprezenta ruta /api/records si va asigura conexiunea si accesul backend - baza de date

```javascript
// pages/api/records.js
import {sendMethodNotAllowed, sendOk,} from '@/js/utils/apiMethods.js';
import {getCollection} from "@/js/utils/functions";
import {ObjectId,} from 'mongodb';
const COLLECTION_NAME = 'records';

const getRecords = async () => {
	const collection = await getCollection(COLLECTION_NAME);
	return collection.find({}).toArray();
}

const getRecord = async (id) => {
	const collection = await getCollection(COLLECTION_NAME);
	return collection.findOne({_id: new ObjectId(id)});
}

const postRecord = async (record) => {
	const collection = await getCollection(COLLECTION_NAME);
	return collection.insertOne(record);
}

const putRecord = async (record) => {
	const collection = await getCollection(COLLECTION_NAME);
	const id = record._id;
	delete record._id;
	return collection.updateOne({_id: new ObjectId(id)}, {$set: record});
}

const deleteRecord = async (id) => {
	const collection = await getCollection(COLLECTION_NAME);
	return collection.deleteOne({_id: new ObjectId(id)});
}

export default async function handler(req, res) {

	const isAllowedMethod = req.method === 'GET' || req.method === 'POST' || req.method === 'PUT' || req.method === 'DELETE';
	if(!isAllowedMethod) {
		return sendMethodNotAllowed(res);
	}

	if(req.method === 'GET' && req.query.id) {
		const id = req.query.id;
		const record = await getRecord(id);
		return sendOk(res, record);
	}
	else if(req.method === 'GET') {
		const records = await getRecords();
		return sendOk(res, records);
	}
	else if(req.method === 'POST') {
		const record = req.body;
		const result = await postRecord(record);
		return sendOk(res, result);
	}
	else if(req.method === 'PUT') {
		const record = req.body;
		const result = await putRecord(record);
		return sendOk(res, result);
	}
	else if(req.method === 'DELETE') {
		const id = req.query.id;
		const result = await deleteRecord(id);
		return sendOk(res, result);
	}
}
```

* Acum putem testa cu Postman ca endpoint-ul nostru functioneaza. Adresa endpoint-ului este <http://localhost:3000/api/records>


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://gurita-alexandru.gitbook.io/cloud-computing-2023-simpre/seminar-1/nextjs-+-mongodb-setup.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
