# 7. REST API (Connecting Frontend to Backend)

## REST API Design Principles

In this section we will explore how to design, structure and maintain effective [REST API](https://blog.postman.com/rest-api-examples/)s using NestJS. REST (Representational State Transfer) is a popular architecture for client-server communication, and NestJS gives us all the tools to make robust REST APIs that are readable, scalable and easy to work with.

As our backend connects to the Flutter frontend using HTTP requests, a well-structured REST API is essential for clean integration and developer efficiency.

### Understanding Rest Endpoints

Each REST endpoint represents a resource. In our project, resources include things like users and dietary restrictions. These resources follow predictable URL patterns and support standard HTTP methods.

<figure><img src="https://3191976129-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FuNe0Bz4zOAJoU0XMQXnd%2Fuploads%2FmRQ17E0ZsqOZo8TqjSAu%2Fimage.png?alt=media&#x26;token=f848c158-78d4-4a07-877f-f43b55817f9a" alt=""><figcaption><p>(Singh, 2024)</p></figcaption></figure>

Each route should follow a \*\*noun-based, pluralised structure\*\*, e.g., <kbd>/users</kbd>, <kbd>/dietary-restrictions</kbd>.

To keep things consistent for our frontend, it's important to structure API responses in a predictable format.

```json
Example Structure:
{
  "status": "success",
  "data": {
    "id": 1,
    "name": "Jane Doe",
    "email": "jane@example.com"
  }
}
```

### Common API considerations

When building your API endpoints, keep these points in mind

* **Validation:** validate user input with DTO classes using class-validator decorators like @IsEmail, @IsString to prevent malformed data
* **Error Handling:** Always catch and return error messages. Use HttpException in service or controller logic
* **Status Codes:**
  * **200:** Request succeeded
  * **201:**  Resource created
  * **400:** Invalid request data
  * **404:** Resource not found
  * **500:** Internal server error

### Dio Client

As explained in the NestJS section, our frontend and and backend communicate through HTTP requests and responses. In order to connect to the HTTP client we are going to be using Dio, which means dart input output.&#x20;

We need to download the Dio dependency in order to access this in Flutter. In **pubspec.yaml** file add the following line and then in your terminal, run `flutter pub get` be sure you are in the frontend folder.

{% code title="pubspec.yaml" %}

```yaml
dependencies:
 dio: ^5.3.2
 flutter:
   sdk: flutter
```

{% endcode %}

In lib, create a new folder called **core,** this folder will be in charge of all core objects relevant across all domains of the app. Inside this folder create file named **dio\_client.dart.** The content of this file should be as followed:

{% code title="dio\_client.dart" %}

```dart
import 'package:dio/dio.dart';

class DioClient {
  static final DioClient _instance = DioClient._internal();

  factory DioClient() => _instance;

  late final Dio dio;

  DioClient._internal() {
    dio = Dio(
      BaseOptions(
        baseUrl: 'http://localhost:3000', // use 'http://10.0.2.2:3000' for android studio
        connectTimeout: const Duration(seconds: 5),
        receiveTimeout: const Duration(seconds: 5),
        headers: {'Content-Type': 'application/json'},
      ),
    );
  }
}
```

{% endcode %}

What this file is doing is making a **dio** object that follows the base URL of our server. All data transfer and communication will happen across this URL.&#x20;

### Services

Similar to the services we created in our NestJS **user.service.ts** file, we are going to create a user service for the flutter app, which will handle getting and sending all of user data.

To do this, inside of the **lib** directory create a folder named **services**, and inside this folder create a file named **user\_service.dart.** We want to create methods which handle getting all of the users from the backend database, and another method to create a new user and send the information to our database.&#x20;

First, create a class which imports the DIoClient we made in the earlier step.&#x20;

{% code title="user\_service.dart" %}

```dart
import 'package:dio/dio.dart';
import '../core/dio_client.dart';

class UserService {
  final Dio _dio = DioClient().dio;
}
```

{% endcode %}

Inside of this UserService class we want to first create a method that will handle getting all of the users from our database. Add this method to the class.

```dart
  Future<List<dynamic>> getUsers() async {
    final response = await _dio.get('/user');
    return response.data;
  }
```

The return type in Dart is specified at the start of the method. For this method the return type **Future** needs to be used as retrieving data is an asynchronous function. Future is Darts way of saying that the data may not be retrieved instantly, but in the future. We know that the users will come in a list based off of how we are sending it using Prisma seen in section 5. Lastly, the dynamic type is used as the number of users may change and is not constant. Inside this method, our code is making a get request on the url /user and then returning the data it recieves.&#x20;

Next lets make a method for creating a user. Add this next method to the User Service class.&#x20;

```dart
  Future<Map<String, dynamic>> createUser({
    required String name,
    required String email,
    required String password,
  }) async {
    final response = await _dio.post(
      '/user',
      data: {'name': name, 'email': email, 'password': password},
    );
    return response.data;
  }
```

The function returns a map where each key is a string and each value can be of any type. This structure is commonly used to represent JSON data, such as the response from an API. For example, when a user is created, the response might include fields like "id", "name", and "email", all stored in a Map\<String, dynamic> so they can be accessed easily in your Dart code.

{% code title="Sample JSON data" %}

```dart
{
  "id": 1,
  "name": "Jane",
  "email": "jane@example.com",
  "createdAt": "2025-03-30T10:00:00Z"
}
```

{% endcode %}

Now that we have all of the necessary code to connect our front end to the backend. Lets design our screen.
