Skip to content

Commit 733a67a

Browse files
committed
finish commit
1 parent 078fe96 commit 733a67a

5 files changed

Lines changed: 303 additions & 29 deletions

File tree

README.md

Lines changed: 250 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,52 +1,276 @@
11
# RestaurantGraphQL API
2-
3-
The RestaurantGraphQL API is a GraphQL-based API designed to handle multiple restaurants in a shop store. It provides various features such as searching for restaurants in a city, finding the nearest restaurant, retrieving a list of foods offered by a restaurant, and more. This README file provides an overview of the API and instructions on how to use it.
2+
This API uses GraphQL to expose details about restaurants and their menus. It allows users to search for restaurants, view food items and reviews, and (for admins) manage restaurant and food data.
43

54
## Features
5+
- Search restaurants by city, cuisine, name, price range, and proximity
6+
- View restaurant details: name, address, contact info, opening hours
7+
- Calculate distance to a restaurant
8+
- Get food menu items: name, description, price
9+
- Create, update and delete menu items (for admins)
10+
- View customer reviews
11+
- Create reviews (for authenticated users)
12+
- Manage users and assign roles (for superadmins)
13+
14+
## Queries
15+
- `restaurants` - Search and filter restaurants
16+
- `restaurant` - Get a specific restaurant
17+
- `food` - Get a food item
18+
- `foods` - Get all menu items for a restaurant
19+
- `reviews` - Get reviews for a restaurant
20+
- `user` - Get the authenticated user
21+
22+
## Mutations
23+
- `createRestaurant`
24+
- `updateRestaurant`
25+
- `deleteRestaurant`
26+
- `createFood`
27+
- `updateFood`
28+
- `deleteFood`
29+
- `createReview`
30+
- `changeRole`
31+
# Usage
632

7-
The RestaurantGraphQL API offers the following features:
33+
## Usage
834

9-
- Search in a city: Users can search for restaurants in a specific city by providing the city name as a parameter.
10-
- Distance calculation: The API can calculate the distance between a given location and all the restaurants, enabling users to find the nearest restaurant.
11-
- Retrieve restaurant details: Users can retrieve detailed information about a specific restaurant, including its name, address, contact details, opening hours, and more.
12-
- Get a list of foods: The API allows users to fetch a list of foods offered by a restaurant, including their names, descriptions, prices, and any other relevant details.
13-
- Filtering: Users can apply various filters while searching for restaurants, such as cuisine type, price range, ratings, and more.
35+
### Clone the repo
36+
Clone this repository to get the source code:
1437

15-
## Installation
38+
```
39+
git clone https://github.com/basemax/RestaurantGraphqlApi
40+
```
1641

17-
To run the RestaurantGraphQL API locally, follow these steps:
42+
### Install dependencies
43+
Run `npm install` to install Node dependencies:
44+
45+
```
46+
npm install
47+
```
1848

19-
Clone the repository:
49+
### Run in development
50+
Run the app using Docker Compose:
2051

21-
```bash
22-
git clone https://github.com/BaseMax/RestaurantGraphQL
2352
```
53+
sudo docker-compose -f docker-compose.dev.yml up
54+
```
2455

25-
Navigate to the project directory:
56+
This will start the app in development mode, with hot reloading enabled.
2657

27-
```bash
28-
cd RestaurantGraphQL
58+
The GraphQL playground will be available at `http://localhost:3000/graphql`
59+
60+
61+
# Examples
62+
Queries:
63+
64+
1. Get all restaurants:
65+
```graphql
66+
{
67+
restaurants {
68+
name
69+
location {
70+
latitude
71+
longitude
72+
}
73+
}
74+
}
2975
```
3076

31-
Install the dependencies:
77+
2. Get a specific restaurant by ID:
78+
```graphql
79+
{
80+
restaurant(id: "1") {
81+
name
82+
cuisine
83+
openingHours {
84+
day
85+
hours
86+
}
87+
}
88+
}
89+
```
3290

33-
```bash
34-
npm install
91+
3. Get foods for a restaurant:
92+
```graphql
93+
{
94+
foods(restaurantId: "1") {
95+
name
96+
description
97+
price
98+
}
99+
}
35100
```
36101

37-
Set up the environment variables:
102+
4. Get reviews for a restaurant:
103+
```graphql
104+
{
105+
reviews(restaurantId: "1") {
106+
rating
107+
comment
108+
}
109+
}
110+
}
111+
```
38112

39-
- Create a `.env` file in the project root.
40-
- Define the necessary environment variables, such as the database connection details and API keys.
113+
5. Search restaurants by city:
114+
```graphql
115+
{
116+
restaurants(query: {
117+
city: "Paris"
118+
}) {
119+
name
120+
}
121+
}
122+
```
41123

42-
Start the server:
124+
Mutations:
43125

44-
```bash
45-
npm start
126+
6. Create a new restaurant:
127+
```graphql
128+
mutation {
129+
createRestaurant(input: {
130+
name: "La Table"
131+
location: {
132+
longitude: 2.3456
133+
latitude: 48.8534
134+
}
135+
}) {
136+
id
137+
}
138+
}
139+
```
140+
141+
7. Update a restaurant:
142+
```graphql
143+
mutation {
144+
updateRestaurant(input: {
145+
id: "1"
146+
name: "New Restaurant Name"
147+
}) {
148+
name
149+
}
150+
}
151+
```
152+
153+
8. Create a new food item:
154+
```graphql
155+
mutation {
156+
createFood(input: {
157+
name: "Steak Frites"
158+
price: 20
159+
restaurantId: "1"
160+
}) {
161+
id
162+
}
163+
}
46164
```
47165

48-
The API will be available at http://localhost:3000.
166+
9. Create a new review:
167+
```graphql
168+
mutation {
169+
createReview(input: {
170+
restaurantId: "1"
171+
rating: 5
172+
comment: "Great food and service!"
173+
}) {
174+
id
175+
}
176+
}
177+
```
178+
179+
10. Change a user's role:
180+
```graphql
181+
mutation {
182+
changeRole(newRole: admin, userId: "2") {
183+
role
184+
}
185+
}
186+
```
187+
188+
Hope this helps! Let me know if you have any other questions.
189+
# API Documentation
190+
191+
This API uses GraphQL to provide data about restaurants and their menus.
192+
193+
## Queries
194+
195+
### Restaurant queries
196+
197+
- `restaurants(query: SearchRestaurantsInput)` - Returns all restaurants matching the search parameters. You can search by:
198+
- `name`
199+
- `city`
200+
- `cuisine`
201+
- `minPrice`
202+
- `maxPrice`
203+
- `nearBy { radius, latitude, longitude }`
204+
205+
- `restaurant(id: ID!)` - Returns a single restaurant object by ID.
206+
207+
- `distance(location: LocationInput!)` - Returns the distance between a given location and the restaurant.
208+
209+
### Food menu queries
210+
211+
- `food(id: ID!)` - Returns a single food item by ID.
212+
213+
- `foods(restaurantId: ID!, pagination: Pagination)` - Returns all food items for a restaurant, with pagination. Pagination parameters are:
214+
- `limit`
215+
- `skip`
216+
217+
### Review queries
218+
219+
- `reviews(restaurantId: ID!, pagination: Pagination)` - Returns all reviews for a restaurant, paginated.
220+
221+
- `user` - Returns the current authenticated user object.
222+
223+
## Mutations
224+
225+
### Restaurant mutations
226+
227+
- `createRestaurant(input: CreateRestaurantInput!)` - Creates a new restaurant. Input fields are:
228+
- `name`
229+
- `location { latitude, longitude }`
230+
- `address`
231+
- `rating`
232+
- `cuisine`
233+
- `contact { email, phone }`
234+
- `openingHours [ { day, hours } ]`
235+
236+
- `updateRestaurant(input: UpdateRestaurantInput!)` - Updates an existing restaurant. Requires the `id` field.
237+
238+
- `deleteRestaurant(id: String!)` - Requires admin role.
239+
240+
### Food menu mutations
241+
242+
- `createFood(input: CreateFoodInput!)` - Requires admin role. Input fields are:
243+
- `name`
244+
- `description`
245+
- `price`
246+
- `restaurantId`
247+
248+
- `updateFood(input: UpdateFoodInput!)` - Requires admin role.
249+
250+
- `deleteFood(id: String!)` - Requires admin role.
251+
252+
### Review mutations
253+
254+
- `createReview(input: CreateReviewInput!)` - Requires authentication. Input fields are:
255+
- `restaurantId`
256+
- `rating`
257+
- `comment`
258+
259+
### User mutations
260+
261+
- `changeRole(newRole: Role!, userId: String!)` - Requires superadmin role. Changes a user's role.
262+
263+
Let me know if you have any other questions about the API! I can expand on any part in more detail.
264+
## Security
265+
Roles:
266+
267+
- `user` - Basic access
268+
- `admin` - Manage restaurants and menu
269+
- `superadmin` - Manage all users and roles
270+
271+
Authentication uses JWT tokens.
49272

273+
Let me know if you have any other questions!
50274
## Usage
51275

52276
To interact with the RestaurantGraphQL API, you need a GraphQL client or an API testing tool. Here's an example using cURL:

src/modules/users/users.module.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
import { Module } from '@nestjs/common';
22
import { DbModule } from '../db/db.module';
33
import { UsersService } from './users.service';
4+
import { UsersResolver } from './users.resolver';
45

56
@Module({
67
imports: [DbModule],
7-
providers: [UsersService],
8+
providers: [UsersService, UsersResolver],
89
exports: [UsersService],
910
})
1011
export class UsersModule {}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import { UseGuards } from '@nestjs/common';
2+
import { Args, ID, Mutation, Query, Resolver } from '@nestjs/graphql';
3+
import { AuthGuard } from '../auth/auth.guard';
4+
import { MinRole } from '../auth/min-role.decorator';
5+
import { UserAuth, UserData } from '../auth/user-data.decorator';
6+
import { Role, User } from './user.model';
7+
import { UsersService } from './users.service';
8+
9+
@Resolver()
10+
export class UsersResolver {
11+
constructor(private service: UsersService) { }
12+
@MinRole(Role.superadmin)
13+
@UseGuards(AuthGuard)
14+
@Mutation(() => User)
15+
async changeRole(
16+
@UserData() user: UserAuth,
17+
@Args('newRole', { type: () => Role }) role: Role,
18+
@Args('userId', { type: () => String }) id: string,
19+
20+
) {
21+
return await this.service.changeRole(user, role, id);
22+
}
23+
@MinRole(Role.superadmin)
24+
@UseGuards(AuthGuard)
25+
@Query(() => [User])
26+
async getAllUsers() {
27+
return await this.service.getAll();
28+
}
29+
}

src/modules/users/users.service.ts

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1-
import { BadRequestException, Inject, Injectable } from '@nestjs/common';
1+
import { BadRequestException, Inject, Injectable, NotFoundException } from '@nestjs/common';
22
import * as argon2 from 'argon2';
33
import { Collection, Db } from 'mongodb';
44
import { mapOID, mapOIDIfNotNull, objectIdOrThrow } from 'src/utils';
5+
import { UserAuth } from '../auth/user-data.decorator';
56
import { RegisterUserInput } from './dto/register.input';
67
import { Role, User } from './user.model';
78

@@ -14,16 +15,27 @@ interface DbUser {
1415

1516
@Injectable()
1617
export class UsersService {
18+
getAll(): Promise<User[]> {
19+
return this.collection.find().toArray().then(e => e.map(mapOID));
20+
}
21+
async changeRole(user: UserAuth, role: Role, id: string): Promise<User> {
22+
const userExists = await this.getUserById(id);
23+
if (!userExists)
24+
throw new NotFoundException("user not found");
25+
const { value } = await this.collection.findOneAndUpdate({ _id: objectIdOrThrow(id) }, { $set: { role } }, { returnDocument: "after" })
26+
return mapOID(value!)
27+
}
1728
private collection: Collection<DbUser>;
1829
constructor(@Inject('DATABASE_CONNECTION') db: Db) {
1930
this.collection = db.collection('users');
2031
}
32+
2133
getUserById(id: string): Promise<User | null> {
2234
return this.collection
2335
.findOne({ _id: objectIdOrThrow(id) })
2436
.then(mapOIDIfNotNull);
2537
}
26-
38+
2739
getUserByEmail(email: string): Promise<User | null> {
2840
return this.collection.findOne({ email: email }).then(mapOIDIfNotNull);
2941
}

0 commit comments

Comments
 (0)