diff --git a/module3/misc/intermission_work.md b/module3/misc/intermission_work.md index 7f8fc41fd..90e24bb9b 100644 --- a/module3/misc/intermission_work.md +++ b/module3/misc/intermission_work.md @@ -10,7 +10,7 @@ You must complete and submit all of these assignments. *It is due the Saturday b Submit your work here: [Survey Link](https://forms.gle/SzrTxMFjYUQLbqbY8) -You must use Ruby 3.2.2 and Rails 7.0.x for all of the work in this module. You can check your version by running `ruby -v` and `rails -v` in your terminal. +You must use Ruby 3.2.2 and Rails 7.1.x for all of the work in this module. You can check your version by running `ruby -v` and `rails -v` in your terminal. Note: If you are installing Ruby 3.2.2 for the first time, you WILL have to reinstall all of your gems. Gems reside on your computer per version of Ruby, and every time you add a new version of Ruby, you will have to reinstall all of your gems for that version of ruby. @@ -36,18 +36,27 @@ Everything we build in Mod 3 will focus on the theme of building and consuming A Here are some helpful videos and tutorials that you can use to familiarize yourself with both building and consuming APIs. The videos are using Rails 5, but the concepts are the same. The build an API in Rails Tutorial has been updated to use Rails 7. -#### Watch one -* [Instructor Dione Wilson demonstrates the process of building an API for 2006](https://vimeo.com/469621034/d0d5febb9d) -* [Instructor Ian Douglas demonstrates the process of building an API for 2005](https://vimeo.com/452734115/8b3bd1adf0) +To begin, familiarize yourself with the concept of an API by reading [this AWS article, _"What is an API?"_](https://aws.amazon.com/what-is/api/). For mod 3, we will focus on REST APIs. -#### Do all of these -* [Build an API in Rails Tutorial](https://github.com/turingschool/backend-curriculum-site/blob/gh-pages/module3/lessons/exercises/building_an_api.md) -* [Play with Postman in order to use the API you built out in the previous lesson.](https://learning.postman.com/docs/introduction/overview/) -* [Consuming an API](https://github.com/turingschool/backend-curriculum-site/blob/gh-pages/module3/lessons/consuming_an_api.md) -* Review your reflections on your M2 projects, and revise / add onto them. +Then, complete the following: -#### Stuff to Read and internalize -* [Sandi Metz' Rules for Developers](https://robots.thoughtbot.com/sandi-metz-rules-for-developers) +1. [Consuming an API](https://github.com/turingschool/backend-curriculum-site/blob/gh-pages/module3/lessons/consuming_an_api.md) +2. [Building an API in Rails Tutorial](https://github.com/turingschool/backend-curriculum-site/blob/gh-pages/module3/lessons/exercises/building_an_api.md) + * We recommend following along with this lesson by watching **one** of these videos: + * [Instructor Dione Wilson demonstrates the process of building an API for 2006](https://vimeo.com/469621034/d0d5febb9d) + * [Instructor Ian Douglas demonstrates the process of building an API for 2005](https://vimeo.com/452734115/8b3bd1adf0) +3. [Download & Install Postman](https://www.postman.com/downloads/). **NOTE:** do not use the web version, you will want to download it in order to use all features. +4. [Play with Postman in order to use the API you built out in the previous lesson.](https://learning.postman.com/docs/getting-started/overview/) +5. Review your reflections on your M2 projects, and revise / add onto them. + +### Read / Take Notes +* [Sandi Metz's _Rules for Developers_](https://robots.thoughtbot.com/sandi-metz-rules-for-developers) + +### Deeply Nested Collections + +When consuming APIs, the data is often returned in deeply nested collections, so you will need to tap into your Mod 1 skills to practice digging through them to retrieve the data you need. + +Fork and clone [Here Be Dragons](https://github.com/turingschool-examples/here-be-dragons). Get the tests to pass. This is something you'll turn in with your submission, so make sure you make a forked copy of it. ### Authentication / Authorization @@ -60,21 +69,14 @@ Write up some notes and ideas on the following: - how could we allow a user to "stay logged in for 7 days" even if your Rails app is restarted -### Deeply Nested Collections - -When consuming APIs, the data is often returned in deeply nested collections, so you will need to tap into your Mod 1 skills to practice digging through them to retrieve the data you need. - -Fork and clone [Here Be Dragons](https://github.com/turingschool-examples/here-be-dragons). Get the tests to pass. This is something you'll turn in with your submission, so make sure you make a forked copy of it. - - -### HTTP Request/Response +### HTTP Request/Response Review * On one piece of paper, write out all of the parts of an example `HTTP GET` request (Diagram the DNS look-up as well as how a Rails Application would handle the request via MVC) + * **Even better:** write your explanation as a metaphor * On a separate piece of paper, write out an example 200 response to that request with all of the parts -* **Bonus** write your explanation as a metaphor -### Rails "params" magic. +### Rails `"params"` magic How does "params" get built in Rails, and what precidence is given for query parameters (ie `?id=5` in a URL) versus dynamic placeholders (ie `/book/:id`) versus data sent in the body of a request from a form. @@ -90,7 +92,7 @@ Entering Module 3 with a solid understanding of ActiveRecord and SQL is key to g 1. Complete and understand the [Intermediate SQL II](https://gist.github.com/case-eee/5affe7fd452336cef2c88121e8d49f5d) challenges. -### Reading +--- # For further exploration @@ -98,11 +100,17 @@ If you have time, here are some activities that will be valuable not only in Mod ### Data Structures And Algorithms -We are going to be covering various data structures to prepare you for the job hunt and technical interviews. Complete this former M1 project, [Beat Box](https://backend.turing.edu/module1/projects/beat_box) +Read: [An Overview of Data Structures for Ruby Developers](https://www.rubyguides.com/2019/04/ruby-data-structures/) + +We are going to be covering various data structures to prepare you for the job hunt and technical interviews. Complete this former M1 project, [Beat Box](https://backend.turing.edu/module1/projects/beat_box). -If you've done Beat Box, let's get serious and have a [Date Night](https://backend.turing.edu/module1/projects/date_night) +If you've done Beat Box, let's get serious and have a [Date Night](https://backend.turing.edu/module1/projects/date_night)! +### Security -## Optional Reading on Security topics +* Read the docs on [Rails Security](https://guides.rubyonrails.org/security.html). We recommend focusing in particular on the sections regarding: + * Sessions + * CSRF + * User Management + * Injection -* [Rails Security](https://guides.rubyonrails.org/security.html) diff --git a/module3/projects/index.md b/module3/projects/index.md index a6b2388d2..ae8129688 100644 --- a/module3/projects/index.md +++ b/module3/projects/index.md @@ -3,10 +3,10 @@ layout: page title: Module 3 - Projects --- -* [Viewing Party Lite](./viewing_party_lite) - paired project, week 1 -* [Market Money](./market_money/) - solo project, week 2 -* [Consultancy Project](./consultancy) - group project, week 4 and 5 -* [Sweater Weather](./sweater_weather) - final solo project, week 6 +* paired project, week 1 +* solo project, week 2 +* [Consultancy Project](./consultancy) - group project, weeks 4 and 5 +* final solo project, week 6 ### Resources diff --git a/module3/projects/rails_engine_lite/evaluation.md b/module3/projects/rails_engine_lite/evaluation.md index ee1bed5c7..957a472d8 100644 --- a/module3/projects/rails_engine_lite/evaluation.md +++ b/module3/projects/rails_engine_lite/evaluation.md @@ -6,27 +6,27 @@ type: project --- _[Back to Rails Engine Lite Home](./index)_ -The 'eval' for this project is going to be a bit different than other projects in the past. We are relying on you to score yourself for this project. To do that, please submit [this form](https://forms.gle/1o1u5Ai2UYifwY9cA). +## Presentation +For the project evaluation, each project team should prepare a **10 minute video presentation**. Presentations longer than 10 minutes will not be reviewed and sent back for revision. Your presentation should cover the following points: -## Feedback Session Format +* Demonstration of functionality via Postman suites +* Technical quality and organization of the code, identifying code that should be refactored and how it would be refactored +* Running your application's test suite and a discussion of test coverage (happy/sad paths and any edge cases) +* Identifying the area(s) of code of which you are most proud, and an area where you would like specific feedback -Instead of a traditional eval, you will be meeting in small groups to get feedback from your peers as well as an instructor. The format of this feedback session will be: +_All_ team members are expected to participate equally in the presentation. Students should focus on practicing technical communication that is succinct and utilizes appropriate technical vocabulary. -Feedback Request: -Choose at least one part of your project that you’d like specific feedback on. Everyone will be asked to bring this to the feedback session, and you will be able to get feedback from your instructor as well as your peers in the feedback group. +Slides are not required, but encouraged as a way to facilitate the presentation along with sharing specific code examples. -## Rubric +Instructors will review the video presentation and do a brief code review (so please make sure you identify an area you’d like feedback in your video, so we can focus where you’d like it most). Scores and final comments will be sent to teams via Slack. -### Feedback Session -* Exceeds Expectations: Student comes prepared to answer all question/tasks outlined in the Feedback Session Format above. Student also participates with other peers to either ask further questions or offer additional feedback. -* Meets Expectations: Student comes prepared to answer all question/tasks outlined in the Feedback Session Format above. -* Below Expectations: Student participates in the feedback session, but does not come prepared to answer all questions/tasks outlined in the Feedback Session Format above. -* Well Below Expectations: Student is unprepared for the feedback session, and does not come prepared to participate. +## Rubric +Your project will be evaluated based on the following rubric: ### Feature Delivery -* Exceeds Expectations: Project completes all requirements and at least one extension. +* Exceeds Expectations: Project completes all requirements and at least two extensions. * Meets Expectations: Project completes all requirements * Below Expectations: Project fails to complete 1 - 2 required endpoints * Well Below Expectations: Project fails to complete more than 3 or more endpoints diff --git a/module3/projects/rails_engine_lite/index.md b/module3/projects/rails_engine_lite/index.md index 2dbd477de..9d80e2307 100644 --- a/module3/projects/rails_engine_lite/index.md +++ b/module3/projects/rails_engine_lite/index.md @@ -71,7 +71,7 @@ There are two ways to run the test suite: one endpoint at a time, or the whole s #### Running one endpoint at a time -As you develop your endpoints, run "rails s" and find the appropriate endpoint within the Postman collection you imported. For example, "Get All Merchants". When you select "Get All Merchants" from the list, you should see a Postman tab open, pre-populated with everything you need to connect to the endpoint in your code and see if it works correctly. +As you develop your endpoints, run `rails s` and find the appropriate endpoint within the Postman collection you imported. For example, "Get All Merchants". When you select "Get All Merchants" from the list, you should see a Postman tab open, pre-populated with everything you need to connect to the endpoint in your code and see if it works correctly. Click the "Send" button in the top right corner. diff --git a/module3/projects/rails_engine_lite/rails-engine-development.pgdump b/module3/projects/rails_engine_lite/rails_engine_development.pgdump similarity index 100% rename from module3/projects/rails_engine_lite/rails-engine-development.pgdump rename to module3/projects/rails_engine_lite/rails_engine_development.pgdump diff --git a/module3/projects/rails_engine_lite/requirements.md b/module3/projects/rails_engine_lite/requirements.md index 2864069a9..396f5f9f1 100644 --- a/module3/projects/rails_engine_lite/requirements.md +++ b/module3/projects/rails_engine_lite/requirements.md @@ -5,39 +5,46 @@ length: 1 week tags: type: project --- + + + _[Back to Rails Engine Lite Home](./index)_ -# 1. Set Up +# 1. Setup -1. Create a Rails API project called `rails-engine` (make sure you do not set up a "traditional" Rails project with a frontend, this is an API-only project). +1. Create a Rails API project called `rails_engine` (make sure you do not set up a "traditional" Rails project with a frontend, this is an API-only project). `rails new rails_engine -T -d="postgresql" --api` -2. Set Up [SimpleCov](https://github.com/colszowka/simplecov) to track test coverage in your rails-engine API project. +2. Set Up [SimpleCov](https://github.com/colszowka/simplecov) to track test coverage in your rails_engine API project. -3. Download [rails-engine-development.pgdump](https://raw.githubusercontent.com/turingschool/backend-curriculum-site/gh-pages/module3/projects/rails_engine/rails-engine-development.pgdump) and move it into the `/db/` folder in another folder called `/data/`, so your project files look like this: +3. Download [rails_engine_development.pgdump](https://raw.githubusercontent.com/turingschool/backend-curriculum-site/gh-pages/module3/projects/rails_engine/rails_engine_development.pgdump) and move it into the `/db/` folder in another folder called `/data/`, so your project files look like this: ``` /app /bin /config /db - /data <-- create this folder - rails-engine-development.pgdump <-- put the file in the data folder - seeds.rb <-- seeds.rb is in `/db/` folder, not `/db/data/` + /data <-- create this folder + rails_engine_development.pgdump <-- put the file in the data folder + seeds.rb <-- seeds.rb is in `/db/` folder, not `/db/data/` /lib /log etc ``` - this file is in a binary format and your browser may try to automatically download the file instead of viewing it -4. Set up your `db/seeds.rb` file with the following content: +1. Set up your `db/seeds.rb` file with the following content: ```ruby -cmd = "pg_restore --verbose --clean --no-acl --no-owner -h localhost -U $(whoami) -d rails-engine_development db/data/rails-engine-development.pgdump" +cmd = "pg_restore --verbose --clean --no-acl --no-owner -h localhost -U $(whoami) -d rails_engine_development db/data/rails_engine_development.pgdump" puts "Loading PostgreSQL Data dump into local database with command:" puts cmd system(cmd) ``` -5. Run `rake db:{drop,create,migrate,seed}` and you may see lots of output including some warnings/errors from `pg_restore` that you can ignore. If you're unsure about the errors you're seeing, ask an instructor. +1. Run `rails db:{drop,create,migrate,seed}` and you may see lots of output including some warnings/errors from `pg_restore` that you can ignore. If you're unsure about the errors you're seeing, ask an instructor. -6. Run `rails db:schema:dump` - Check to see that your `schema.rb` exists and has the proper tables/attributes that match the data in Postico. You can do the following to check to see if you have set up rails to effectively communicate with the database. +2. Run `rails db:schema:dump` - Check to see that your `schema.rb` exists and has the proper tables/attributes that match the data in Postico. You can do the following to check to see if you have set up rails to effectively communicate with the database. * Add a `customer.rb` file to your models directory * Create a `Customer` class that inherits from `ApplicationRecord` * run `rails c` to jump into your rails console. @@ -45,7 +52,7 @@ system(cmd) * run `Customer.last` to see the object: `#` * If this all checks out you should be good to go. -7. Use a tool like Postico to examine the 6 tables that were created. Pay careful attention to the data types of each field: +3. Use a tool like Postico to examine the 6 tables that were created. Pay careful attention to the data types of each field: * merchants * items * customers @@ -55,7 +62,10 @@ system(cmd) **NOTE** We updated this process to avoid confusion and taking a significant amount of time; the main learning goals of the project are the Rails API endpoints, not the process of importing CSV data. Avoid starting out with a Rake task to do the import and follow these instructions instead. If in doubt, ask your instructors first. -**NOTE** If your `rails new ...` project name from above is NOT exactly called "rails-engine" you will need to modify the `cmd` variable below to change the `-d` parameter from `rails-engine_development` to `_development` instead. If you have questions, ask your instructors. +**NOTE** If your `rails new ...` project name from above is NOT exactly called "rails_engine" you will need to modify the `cmd` variable to change the `-d` parameter from `rails_engine_development` to `_development` instead. If you have questions, ask your instructors. + + +Finally, commit your setup steps and push to a new repo. Share that new repo with your project partner(s). Be sure to add them as a collaborator. --- @@ -63,7 +73,7 @@ system(cmd) You will need to expose the data through a multitude of API endpoints. All of your endpoints should follow these technical expectations: -* All endpoints should be fully tested for happy path AND sad path. The Postman tests are not a substitute for writing your own tests. +* All endpoints should be fully tested for happy path AND sad path. **The Postman tests are not a substitute for writing your own tests.** * All endpoints will expect to return JSON data only * All endpoints should be exposed under an `api` and version (`v1`) namespace (e.g. `/api/v1/items`) * API will be compliant to the [JSON API spec](https://jsonapi.org/) and match our requirements below precisely @@ -146,12 +156,17 @@ You will need to expose the following RESTful API endpoints for the following: ## SECTION TWO: Non-RESTful Search Endpoints -You will get to choose from the following list: +You will get to choose ONE group of endpoint pairs from the following list: + +**A. One Merchant & All Items:** + * Find one MERCHANT based on search criteria, and + * Find all ITEMS based on search criteria -* ONE of following endpoint pairs: - * find one MERCHANT based on search criteria AND find all ITEMS based on search criteria - * OR: - * find one ITEM based on search criteria AND find all MERCHANTS based on search criteria +Or, + +**B. One Item & All Merchants:** + * Find one ITEM based on search criteria, and + * Find all MERCHANTS based on search criteria ## Your Project MVP @@ -160,19 +175,23 @@ In total, the MINIMUM requirement will be 11 endpoints: * section one has 9 endpoints * section two has 2 endpoints + +You may choose to divide these up between your project partners in whatever way seems best; you may also choose to implement the first story/stories _together_ to both have a solid understanding first, before dividing & conquering if you choose. + You can reference the [Wireframes](./wireframes) to get a better idea of how these endpoints might be used in a frontend application. --- # 3. API requests/responses, more detail -# SECTION ONE -## RESTful: Fetch all Items/Merchants +# SECTION ONE: RESTful requests + +

1. Fetch all Items/Merchants

These "index" endpoints for items and merchants should: * render a JSON representation of all records of the requested resource * always return an array of data, even if one or zero resources are found -* NOT include dependent data of the resource (eg, if you're fetching merchants, do not send any data about merchant's items or invoices) +* NOT include dependent data of the resource (e.g., if you're fetching merchants, do not send any data about merchant's items or invoices) * follow this pattern: `GET /api/v1/` Example JSON response for the Merchant resource: @@ -205,7 +224,10 @@ Example JSON response for the Merchant resource: } ``` -## RESTful: Fetch a single record +
+
+ +

2. Fetch a single record

This endpoint for Items and Merchants should: @@ -230,8 +252,11 @@ Example JSON response for the Item resource: Note that the `unit_price` is sent as numeric data, and not string data. +
+
+ -## RESTful: Create an Item +

3: Create an Item

This endpoint should: @@ -239,7 +264,7 @@ This endpoint should: * follow this pattern: `POST /api/v1/items` * accept the following JSON body with only the following fields: -``` +```json { "name": "value1", "description": "value2", @@ -269,7 +294,10 @@ Example JSON response for the Item resource: } ``` -## RESTful: Update an Item +
+
+ +

4: Update an Item

This endpoint should: @@ -279,7 +307,7 @@ This endpoint should: * accept the following JSON body with one or more of the following fields: The body should follow this pattern: -``` +```json { "name": "value1", "description": "value2", @@ -305,17 +333,23 @@ Example JSON response for the Item resource: } } ``` +
+
-## RESTful: Destroy an Item + +

5: Destroy an Item

This endpoint should: * destroy the corresponding record (if found) and any associated data * destroy any invoice if this was the only item on an invoice -* NOT return any JSON body at all, and should return a 204 HTTP status code -* NOT utilize a Serializer (Rails will handle sending a 204 on its own if you just `.destroy` the object) +* NOT return any JSON body at all, and should return a `204`` HTTP status code +* NOT utilize a Serializer (Rails will handle sending a `204` on its own if you just `.destroy` the object) + +
+
-## RESTful: Relationship Endpoints +

6. Relationship Endpoints

These endpoints should show related records for a given resource. The relationship endpoints you should expose are: @@ -324,12 +358,27 @@ These endpoints should show related records for a given resource. The relationsh * `GET /api/v1/items/:id/merchant` - return the merchant associated with an item * return a 404 if the item is not found +
+ +
--- # SECTION TWO ## Non-RESTful Search Endpoints -In addition to the standard RESTful endpoints described above, you will build the following endpoints which will NOT follow RESTful convention: +As a reminder, for Section Two you should choose a group of endpoints to implement, either: + +**A. One Merchant & All Items:** + * Find one MERCHANT based on search criteria, and + * Find all ITEMS based on search criteria + +Or, + +**B. One Item & All Merchants:** + * Find one ITEM based on search criteria, and + * Find all MERCHANTS based on search criteria + +Once you choose the group you are implementing, you will build the corresponding endpoints which will NOT follow RESTful convention. For example: * `GET /api/vi/items/find`, find a single item which matches a search term * `GET /api/vi/items/find_all`, find all items which match a search term @@ -338,18 +387,18 @@ In addition to the standard RESTful endpoints described above, you will build th These endpoints will make use of query parameters as described below: -#### "Find One" endpoints +

7. "Find One" endpoints

These endpoints should: * return a single object, if found * return the first object in the database in case-insensitive alphabetical order if multiple matches are found - * eg, if "Ring World" and "Turing" exist as merchant names, "Ring World" would be returned, even if "Turing" was created first + * e.g., if "Ring World" and "Turing" exist as merchant names, "Ring World" would be returned, even if "Turing" was created first * allow the user to specify a 'name' query parameter: * for merchants, the user can send `?name=ring` and it will search the `name` field in the database table * for items, the user can send `?name=ring` and it will search the `name` field in the database table * the search data in the `name` query parameter should require the database to do a case-insensitive search for text fields - * eg, searching for 'ring' should find 'Turing' and 'Ring World' + * e.g., searching for 'ring' should find 'Turing' and 'Ring World' * allow the user to send one or more price-related query parameters, applicable to items only: * `min_price=4.99` should look for anything with a price equal to or greater than $4.99 * `max_price=99.99` should look for anything with a price less than or equal to $99.99 @@ -357,14 +406,14 @@ These endpoints should: * for items, the user will send EITHER the `name` parameter OR either/both of the `price` parameters * users should get an error if `name` and either/both of the `price` parameters are sent -Valid examples: +### Valid examples: * `GET /api/v1/merchants/find?name=Mart` * `GET /api/v1/items/find?name=ring` * `GET /api/v1/items/find?min_price=50` * `GET /api/v1/items/find?max_price=150` * `GET /api/v1/items/find?max_price=150&min_price=50` -Invalid examples: +### Invalid examples: * `GET /api/v1//find` * parameter cannot be missing * `GET /api/v1//find?name=` @@ -390,7 +439,11 @@ Example JSON response for `GET /api/v1/merchants/find?name=ring` } ``` -#### "Find All" endpoints +
+ +
+ +

8. "Find All" endpoints

These endpoints will follow the same rules as the "find" endpoints. @@ -423,3 +476,134 @@ Example JSON response for `GET /api/v1/merchants/find_all?name=ring` ``` +
+ +--- + +# Extensions & Extra Practice + + +## External API Consumption + +
+ +

9. Get Item Images

+ +#### Details: +1. The endpoint should be in the pattern of `GET /api/v1/items/:id`, to add onto the "Fetch a Single Record" endpoint (#2 above). +2. You will need to utilize the [Unsplash API](https://unsplash.com/documentation) for this - specifically, the [Search Photos](https://unsplash.com/documentation#search-photos) endpoint. Supply a query that would work for this item's name, and use the API to retrieve an image to represent this item. +3. If an invalid image id is passed in, a 404 status as well as a descriptive error message should be sent back in the response. +4. The `data` top level key should always point to an array even if one or zero images were found for this image. +5. If no image is found, a link to a placeholder image URL can be used (see [placehold.co](https://placehold.co/)), using the `Text` option to include a URL-encoded string representing the Item's name in the placeholder image. + +
Example #1 😁
+ + **Request:** + ``` + GET /api/v1/item/1 + Content-Type: application/json + Accept: application/json + ``` + + **Response:** + `status: 200` + ```json + { + "data": { + "id": "1", + "type": "item", + "attributes": { + "name": "Super Widget", + "description": "A most excellent widget of the finest crafting", + "unit_price": 109.99, + "image_url": "https://api.unsplash.com/photos/eOLpJytrbsQ" //or, https://placehold.co/600x400?text=Super+Widget + } + } + } + ``` +
+
Example #2 😭
+ + **Request:** + ``` + GET /api/v1/item/123123123123 (where this is an invalid ID) + Content-Type: application/json + Accept: application/json + ``` + + **Response:** + `status: 404` + ```json + { + "errors": [ + { + "detail": "Couldn't find Item with 'id'=123123123123" + } + ] + } + ``` +
+ + --- + +
+ + + +

10. Get Merchant Images

+ +#### Details: +1. The endpoint should be in the pattern of `GET /api/v1/merchants/:id`, to add onto the "Fetch a Single Record" endpoint (#2 above). +2. You will need to utilize the [Unsplash API](https://unsplash.com/documentation) for this - specifically, the [Search Photos](https://unsplash.com/documentation#search-photos) endpoint. Supply a query that would work for this merchant's name, and use the API to retrieve an image to represent this merchant. +3. If an invalid image id is passed in, a 404 status as well as a descriptive error message should be sent back in the response. +4. The `data` top level key should always point to an array even if one or zero images were found for this image. +5. If no image is found, a link to a placeholder image URL can be used (see [placehold.co](https://placehold.co/)), using the `Text` option to include a URL-encoded string representing the merchant's name in the placeholder image. + +
Example #1 😁
+ + **Request:** + ``` + GET /api/v1/merchant/1 + Content-Type: application/json + Accept: application/json + ``` + + **Response:** + `status: 200` + ```json + { + "data": [ + { + "id": "1", + "type": "merchant", + "attributes": { + "name": "Mike's Awesome Store", + "image_url": "https://api.unsplash.com/photos/eOLpJytrbsQ" //or, https://placehold.co/600x400?text=Mike%27s\nAwesome\nStore + } + } + ] + }, + ``` +
+
Example #2 😭
+ + **Request:** + ``` + GET /api/v1/merchant/123123123123 (where this is an invalid ID) + Content-Type: application/json + Accept: application/json + ``` + + **Response:** + `status: 404` + ```json + { + "errors": [ + { + "detail": "Couldn't find merchant with 'id'=123123123123" + } + ] + } + ``` +
+
\ No newline at end of file diff --git a/module3/projects/viewing_party_solo/assets/rubocop.md b/module3/projects/viewing_party_solo/assets/rubocop.md new file mode 100644 index 000000000..699b5da17 --- /dev/null +++ b/module3/projects/viewing_party_solo/assets/rubocop.md @@ -0,0 +1,45 @@ +--- +title: Viewing Party Rubocop File +length: 2 weeks +type: project +--- + +Copy this code into a `rubocop.yml` at the root of your rails project. + +```yml + +require: rubocop-rails + +AllCops: + Exclude: + - 'bin/**/*' + - 'config/**/*' + - 'coverage/**/*' + - 'db/**/*' + - 'lib/**/*' + - 'log/**/*' + - 'node_modules/**/*' + - 'public/**/*' + - 'spec/**/*' + - 'tmp/**/*' + - 'vendor/**/*' + - './*' + +Style/FrozenStringLiteralComment: + Enabled: false + +Style/Documentation: + Enabled: false + +Style/ClassAndModuleChildren: + Enabled: false + +Style/SafeNavigation: + Enabled: false + +Metrics/AbcSize: + Enabled: false + +Rails/UniqueValidationWithoutIndex: + Enabled: false +``` diff --git a/module3/projects/viewing_party_solo/assets/vpl_dashboard.png b/module3/projects/viewing_party_solo/assets/vpl_dashboard.png new file mode 100644 index 000000000..7c57c7612 Binary files /dev/null and b/module3/projects/viewing_party_solo/assets/vpl_dashboard.png differ diff --git a/module3/projects/viewing_party_solo/assets/vpl_discover.png b/module3/projects/viewing_party_solo/assets/vpl_discover.png new file mode 100644 index 000000000..2fbc57e10 Binary files /dev/null and b/module3/projects/viewing_party_solo/assets/vpl_discover.png differ diff --git a/module3/projects/viewing_party_solo/assets/vpl_landing.png b/module3/projects/viewing_party_solo/assets/vpl_landing.png new file mode 100644 index 000000000..c30d88390 Binary files /dev/null and b/module3/projects/viewing_party_solo/assets/vpl_landing.png differ diff --git a/module3/projects/viewing_party_solo/assets/vpl_movie_search_index.png b/module3/projects/viewing_party_solo/assets/vpl_movie_search_index.png new file mode 100644 index 000000000..d2c1f507a Binary files /dev/null and b/module3/projects/viewing_party_solo/assets/vpl_movie_search_index.png differ diff --git a/module3/projects/viewing_party_solo/assets/vpl_movie_show.png b/module3/projects/viewing_party_solo/assets/vpl_movie_show.png new file mode 100644 index 000000000..145a9f94a Binary files /dev/null and b/module3/projects/viewing_party_solo/assets/vpl_movie_show.png differ diff --git a/module3/projects/viewing_party_solo/assets/vpl_movie_top40_index.png b/module3/projects/viewing_party_solo/assets/vpl_movie_top40_index.png new file mode 100644 index 000000000..3aca1cc30 Binary files /dev/null and b/module3/projects/viewing_party_solo/assets/vpl_movie_top40_index.png differ diff --git a/module3/projects/viewing_party_solo/assets/vpl_new_viewing_party.png b/module3/projects/viewing_party_solo/assets/vpl_new_viewing_party.png new file mode 100644 index 000000000..dc1d4c497 Binary files /dev/null and b/module3/projects/viewing_party_solo/assets/vpl_new_viewing_party.png differ diff --git a/module3/projects/viewing_party_solo/assets/vpl_registration.png b/module3/projects/viewing_party_solo/assets/vpl_registration.png new file mode 100644 index 000000000..60f8c5e21 Binary files /dev/null and b/module3/projects/viewing_party_solo/assets/vpl_registration.png differ diff --git a/module3/projects/viewing_party_solo/evaluation.md b/module3/projects/viewing_party_solo/evaluation.md new file mode 100644 index 000000000..3e10ef8a0 --- /dev/null +++ b/module3/projects/viewing_party_solo/evaluation.md @@ -0,0 +1,20 @@ +--- +layout: page +title: Viewing Party Solo - Evaluation +--- +_[Back to Project Home](./index)_ + +The 'eval' for this project is going to be a bit different than other projects in the past. First, you should score yourself for this project. To do that, please fill out and submit [this form](#) individually. + +## Feedback Session Format + +Instead of a traditional eval, you will be meeting in small groups to get feedback from your peers as well as an instructor. The format of this feedback session will be: + +1. **Feedback Request:** +Choose at least one part of your project that you’d like specific feedback on. Everyone will be asked to bring this to the feedback session, and you will be able to get feedback from your instructor as well as your peers in the feedback group. + +2. **Behavioral Question:** +After you're done getting feedback on your code, your instructor will pull up the [Wheel of Behavioral Interview Questions](https://spinthewheel.io//en/wheels/oF5ZfO1oCmBmrZCe45Jecz0xJmU9MQ==), and spin it to select a question for you to answer. This is meant to emulate an interview experience. So, as funny as it may feel, answer it as if you were talking to an interviewer. After answering, your instructor (and any cohort-mates!) will give you feedback on your answer. Remember, this is a safe place to practice! + + +_[Rubric information](./rubric)_ \ No newline at end of file diff --git a/module3/projects/viewing_party_solo/index.md b/module3/projects/viewing_party_solo/index.md new file mode 100644 index 000000000..0f1a0fa46 --- /dev/null +++ b/module3/projects/viewing_party_solo/index.md @@ -0,0 +1,47 @@ +--- +title: Viewing Party Solo +length: 1 week +tags: API consumption, solo project +type: project +--- + +## Project Description + +For this project, you will be finishing an application that allows users to explore movies and create a Viewing Party Event that invites users and keeps track of a host. Mainly, your job is to connect with an external API and collect relevant information on each movie, its cast, and other information, to display it on each Viewing Party page. + +Since this project has already been started by another developer, this is considered a *brownfield* project - this will likely echo your experience on-the-job: picking up where another developer left off (e.g. a "legacy" project), and thereby inheriting some of their code's quirks and foibles. It is not your job to fix those issues, rather focus on what **this** project's deliverables are instead of fixing old stuff. + +## Learning Goals + +### Explicit +Below are technical goals that you should be applying in this project.
+The priority of these goals are demonstrated using a star grading system.
+By the end of this project:
+ Student should have a functional understanding of the concept ⭐ ⭐ ⭐
+ Student should have a familiar understanding, but may still have questions ⭐ ⭐
+ Student should know of the concept, but need further resources to implement ⭐ + +* Consume JSON APIs that require authentication ⭐ ⭐ ⭐ +* Test consumption of APIs (facades, services, poros) ⭐ ⭐ ⭐ +* Organize and refactor new code to be more maintainable ⭐ ⭐ + +_Note: See [Learning Goals](../../misc/learning_goals) to see at what level these skills need to be by week 6 of this inning._ + +### Implicit +Below are skills that are more general/necessary on the job that are practiced by completing the goals above. + +* Reading Documentation +* Implementing concepts that are not explicitly taught +* Practice individual research (articles, videos, mentors) +* Prioritizing goals/user stories +* Time management + +## Project Requirements + +Project requirements can be found [here](./requirements). + +## Evaluation + +Instead of a typical evaluation session with an instructor, you will be grouped together with 2-3 other students and will display your application & walk through your solution one by one. Your cohort-mates as well as your instructor will provide feedback and ask questions about your code during this [evaluation/feedback session](./evaluation). + +Your project will be evaluated based on [this rubric](./rubric). diff --git a/module3/projects/viewing_party_solo/requirements.md b/module3/projects/viewing_party_solo/requirements.md new file mode 100644 index 000000000..6d1b25ef8 --- /dev/null +++ b/module3/projects/viewing_party_solo/requirements.md @@ -0,0 +1,196 @@ +--- +title: Viewing Party Solo Requirements +length: 1 week +type: project +--- + + + +_[Back to Viewing Party Home](./index)_ + +### Requirements Overview + +- Consume [The Movie DB API](https://developers.themoviedb.org/3/getting-started/introduction) + - NOTE: You must first register an account with this service and request an API key. + - You must also use the **Faraday** gem to consume this API. +- Test consumption of your API, making sure to use **Webmock** (and/or a tool like VCR) to stub external HTTP requests. + +### Setup +To start, fork from [this base repo](https://github.com/turingschool-examples/viewing_party_solo_7). Follow the setup instructions in that project's README. + +Wireframes found [here](./wireframes) can be used as an additional reference for the front-end. + +--- + +## Project Specs + +

1. Discover Movies: Search by Title

+``` +As a user, +When I visit the '/users/:id/discover' path (where :id is the id of a valid user), +I should see +- a Button to Discover Top Rated Movies +- a text field to enter keyword(s) to search by movie title +- a Button to Search by Movie Title +``` + +**Notes:** + +When the user clicks on the Top Rated Movies OR the search button, they should be taken to the movies results page (more details of this on the `2. Movies Results Page` story). + +The movies will be retrieved by consuming [The MovieDB API](https://developers.themoviedb.org/3/getting-started/introduction). + +
+
+ +

2. Movie Results Page

+ +``` +When I visit the discover movies page ('/users/:id/discover'), +and click on either the Discover Top Rated Movies button or fill out the movie title search and click the Search button, +I should be taken to the movies results page (`users/:user_id/movies`) where I see: + +- Title (As a Link to the Movie Details page (see story #3)) +- Vote Average of the movie + +I should also see a button to return to the Discover Page. +``` + +**Notes:** + +* There should only be a maximum of 20 results. The above details should be listed for each movie. +
+
+ +

3. Movie Details Page

+ +``` +As a user, +When I visit a movie's detail page (`/users/:user_id/movies/:movie_id`) where :id is a valid user id, +I should see +- a button to Create a Viewing Party +- a button to return to the Discover Page + +I should also see the following information about the movie: + +- Movie Title +- Vote Average of the movie +- Runtime in hours & minutes +- Genre(s) associated to movie +- Summary description +- List the first 10 cast members (characters & actress/actors) +- Count of total reviews +- Each review's author and information + +``` + +**Notes** +* The above information should come from 3 different endpoints from [The Movie DB API](https://developers.themoviedb.org/3/getting-started/introduction). +* The "Create a Viewing Party" button should take the user to the "New Viewing Party" page (`/users/:user_id/movies/:movie_id/viewing_party/new`) - see story #4. + +
+
+ +

4. New Viewing Party Page

+ +``` +When I visit the new viewing party page ('/users/:user_id/movies/:movie_id/viewing_party/new', where :user_id is a valid user's id and :movie_id is a valid Movie id from the API), +I should see the name of the movie title rendered above a form with the following fields: + +- Duration of Party with a default value of movie runtime in minutes; a viewing party should NOT be created if set to a value less than the duration of the movie +- When: field to select date +- Start Time: field to select time +- Checkboxes next to each existing user in the system +- Button to create a party +``` +**Notes:** +* When the party is created, the user should be redirected back to the dashboard where the new event is shown. +* The user who created the event should be designated the **host**. There should only ever be 1 host of the party. *(Hint: check your `schema.rb`)* +* The event should also be listed on any other user's dashboards that were also invited to the party. +* Optionally, you can create a [custom validation](https://guides.rubyonrails.org/active_record_validations.html#custom-methods) to help with the duration attribute. + +
+
+ +

5. Where to Watch

+``` +As a user, +When I visit a Viewing Party's show page (`/users/:user_id/movies/:movie_id/viewing_party/:id`), +I should see +- logos of video providers for where to buy the movie (e.g. Apple TV, Vudu, etc.) +- logos of video providers for where to rent the movie (e.g. Amazon Video, DIRECTV, etc.) +And I should see a data attribution for the JustWatch platform that reads: +"Buy/Rent data provided by JustWatch", +as per TMDB's instructions. +``` + +**Notes** +* The logos used should be provided by the TMDB Watch Providers endpoint. + +
+
+ +

6. Similar Movies

+``` +As a user, +When I visit a Movie Details page (`/users/:user_id/movies/:movie_id`), +I see a link for "Get Similar Movies" +When I click that link +I am taken to the Similar Movies page (`/users/:user_id/movies/:movie_id/similar`) +Where I see a list of movies that are similar to the one provided by :movie_id, +which includes the similar movies': +- Title +- Overview +- Release Date +- Poster image +- Vote Average +``` +
+ +

7. Add Movie Info to User Dashboard

+ +``` +As a user, +When I visit a user dashboard ('/user/:user_id'), +I should see the viewing parties that the user has been invited to with the following details: + +- Movie Image +- Movie Title, which links to the movie show page +- Date and Time of Event +- who is hosting the event +- list of users invited, with my name in bold + +I should also see the viewing parties that the user has created (hosting) with the following details: + +- Movie Image +- Movie Title, which links to the movie show page +- Date and Time of Event +- That I am the host of the party +- List of friends invited to the viewing party +``` + +**Notes:** +* Some of the information required in this user story is already on the page; you are allowed and expected to change any and all formatting/code required to complete the story. + + +
+ +
+
+ +## Extension Ideas + + +1. **Provide genres for each movie:** Each `movie` object that is returned from the TMDB api has a `"genre_ids"` key whose value is an array of IDs that correspond to a genre. Wherever the API is able to provide this data, you should provide the appropriate `name` for that genre, based on the TMDB "Genres: Movie List" API. + - (Consider - is it possible to store this data? Do you have to make an API call *every* time a Movie endpoint is called?) + +1. Additional API consumption (find another API you want to consume that could provide more data on one or more pages) +2. Add functionality such that a user must _accept_ an invite to a movie party. +3. Implement basic authentication for a user. + * require a password field to user registration, and create log-in/log-out functionality + * utilize sessions/cookies to remember a logged in user +4. Implement low-level server-side caching for API calls. diff --git a/module3/projects/viewing_party_solo/rubric.md b/module3/projects/viewing_party_solo/rubric.md new file mode 100644 index 000000000..3da680a75 --- /dev/null +++ b/module3/projects/viewing_party_solo/rubric.md @@ -0,0 +1,33 @@ +--- +layout: page +title: Viewing Party Solo - Rubric +--- +_[Back to Project Home](./index)_ + +### Feature Delivery + +- **Exceeds Expectations:** All core requirements are complete and at least one extension. +- **Meets Expectations:** All core requirements are complete. +- **Approaching Expectations:** All core requirements are complete but not functioning exactly as intended. +- **Below Expectations:** Core requirements are incomplete or non-functional. + +### Testing + +* **Exceeds Expectations:** Project achieves 100% test coverage and includes below expectations. +* **Meets Expectations:** Project achieves 90% or greater test coverage. In addition to "happy path", project also includes "sad path"/edge case testing. Feature Tests stub external HTTP requests. +* **Approaching Expectations:** Project achieves 80-90% test coverage. Project may not include "sad path" or edge case testing. +* **Below Expectations:** Project does not achieve 80% test coverage. + +### Code Quality + +- **Exceeds Expectations:** Student can demonstrate how API consumption portions of the project demonstrate all of the four pillars listed below. Student can identify areas where code can be refactored and how they may have created technical debt. Student has refactored into facade and service design pattern. +- **Meets Expectations:** Student can demonstrate how API consumption portions of the project demonstrate 2 of pillars listed below. Student can identify areas where code can be refactored. Student has refactored into facade and service design pattern. +- **Approaching Expectations:** Project demonstrates some gaps in code quality and/or application of MVC principles. Student can demonstrate how API consumption portions of the project demonstrate 2 of pillars listed below. +- **Below Expectations:** Project demonstrates poor factoring and/or understanding of MVC. Student can demonstrate how API consumption portions of the project demonstrate 1 of the pillars listed below. + +**4 Pillars of OO** + +- [ ] Project uses polymorphism +- [ ] Project uses encapsulation +- [ ] Project uses abstraction +- [ ] Project uses inheritance diff --git a/module3/projects/viewing_party_solo/wireframes.md b/module3/projects/viewing_party_solo/wireframes.md new file mode 100644 index 000000000..fafc3b494 --- /dev/null +++ b/module3/projects/viewing_party_solo/wireframes.md @@ -0,0 +1,44 @@ +--- +title: Viewing Party Solo - Wireframes +length: 2 weeks +type: project +--- + +*[Back to Requirements](./requirements)* + +## These wireframes are GUIDELINES + +Remember: the existing interface may already look different from these wireframes. Wireframes are *NOT* meant to be followed 1:1; they are a guide to help visualize the flow of the application from the front-end perspective. + +### Landing Page + +![landing wireframe](./assets/vpl_landing.png) + +### User Registration + +![registration wireframe](./assets/vpl_registration.png) + +### Dashboard + +![dashboard wireframe](./assets/vpl_dashboard.png) + +### Discover Movies + +![discover wireframe](./assets/vpl_discover.png) + +### Movies Results +_Displaying results from top rated search_ +![top rated results wireframe](./assets/vpl_movie_top40_index.png) + +_Displaying results from keyword title search_ +![movie title results wireframe](./assets/vpl_movie_search_index.png) + +### Movie Details + +![movie details wireframe](./assets/vpl_movie_show.png) + +### Create Viewing Party + +Note that the URL here does not include query parameters! + +![create viewing party wireframe](./assets/vpl_new_viewing_party.png)