Skip to content

Commit

Permalink
feat: adds lesson 16 homework and infrastructure (#360)
Browse files Browse the repository at this point in the history
* chore fixed typo

Signed-off-by: Anthony D. Mays <anthony@morganlatimer.com>

* feat: adds lesson_16 homework framework code

* chore: add Spring Web dep

* feat: implements initial api controller for media items

* chore: rejiggers deps to use Spring config

* chore: lint

* tests: adds controller tests

Signed-off-by: Anthony D. Mays <anthony@morganlatimer.com>

* chore: adds gh actions

Signed-off-by: Anthony D. Mays <anthony@morganlatimer.com>

* chore: resets controller for assignment

Signed-off-by: Anthony D. Mays <anthony@morganlatimer.com>

* docs: adds assignment details

Signed-off-by: Anthony D. Mays <anthony@morganlatimer.com>

* chore: introduces MediaType enum

Signed-off-by: Anthony D. Mays <anthony@morganlatimer.com>

* fix: adds missing import

Signed-off-by: Anthony D. Mays <anthony@morganlatimer.com>

* chore: adds message validation constraints

Signed-off-by: Anthony D. Mays <anthony@morganlatimer.com>

* chore: adds request validation reporting

Signed-off-by: Anthony D. Mays <anthony@morganlatimer.com>

* docs: renamed references section and moved

Signed-off-by: Anthony D. Mays <anthony@morganlatimer.com>

* chore: adds proper id for library guests separate from email.

Signed-off-by: Anthony D. Mays <anthony@morganlatimer.com>

* chore: adds ability to find library guest by email.

Signed-off-by: Anthony D. Mays <anthony@morganlatimer.com>

---------

Signed-off-by: Anthony D. Mays <anthony@morganlatimer.com>
  • Loading branch information
anthonydmays authored Apr 3, 2024
1 parent 317f1da commit 41528e9
Show file tree
Hide file tree
Showing 71 changed files with 3,598 additions and 0 deletions.
33 changes: 33 additions & 0 deletions .github/workflows/check_lesson_16_pr.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
name: Check Lesson 16 Pull Request

on:
pull_request:
branches: [ "main" ]
paths:
- "lesson_16/api/**"

jobs:
build:

runs-on: ubuntu-latest
permissions:
contents: read

steps:
- uses: actions/checkout@v4
- name: Set up JDK 17
uses: actions/setup-java@v4
with:
java-version: '17'
distribution: 'temurin'

# Configure Gradle for optimal use in GiHub Actions, including caching of downloaded dependencies.
# See: https://github.com/gradle/actions/blob/main/setup-gradle/README.md
- name: Setup Gradle
uses: gradle/actions/setup-gradle@417ae3ccd767c252f5661f1ace9f835f9654f2b5 # v3.1.0

- name: Build Lesson 16 with Gradle Wrapper
working-directory: ./lesson_16/api
run: ./gradlew check


5 changes: 5 additions & 0 deletions .github/workflows/check_push.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ on:
- "lesson_13/bank/**"
- "lesson_14/algos/**"
- "lesson_14/db/**"
- "lesson_16/api/**"

jobs:
build:
Expand Down Expand Up @@ -101,6 +102,10 @@ jobs:
working-directory: ./lesson_14/db
run: ./gradlew check

- name: Build Lesson 16 with Gradle Wrapper
working-directory: ./lesson_16/api
run: ./gradlew assemble && ./gradlew spotlessCheck

- name: Build Shared Lib with Gradle Wrapper
working-directory: ./lib/java/codedifferently-instructional
run: ./gradlew check
Expand Down
44 changes: 44 additions & 0 deletions lesson_16/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# Lesson 16

## Homework

* Complete the [Creating the Library API](#create-the-books-api) exercise.

## Creating the Library API

We are continuing to build atop the foundation of our library app. For this assignment, you will help implement the API that will be used by a yet-to-come front-end app.

* You will implement the [MediaItemsController][controller-file] to enable the following API:
* `GET /items` - Retrieves a list of media items
* `POST /items` - Creates a new media item
* `GET /items/:id` - Retrieves a single media item with the given ID.
* `DELETE /items/:id` - Deletes a single media item with the given ID.
* You will also implement a new `PatronsController` that will allow the following interactions:
* `GET /patrons` - Retrieves a list of patrons.
* `POST /patrons` - Creates a new patron.
* `GET /patrons/:id` - Retrieves a single patron with the given ID.
* `DELETE /patrons/:id` - Deletes a single patron with the given ID.
* Study the tests in [MediaItemsControllerTest][controller-test-file] to understand what you should accept and return in the API.
* You should not need to make any code changes outside of the `com.codedifferently.lesson16.web` package.

## Running the API

You can run the server using the usual `./gradlew run` command. If you want to test that the server is running correctly, you can use `curl` like so:

```bash
curl http://localhost:5000/items | json_pp
```

Alternatively, you can test the API using the tool [Postman][postman-link]. I recommend installing this tool to make it easier to test things.

## Additional Resources

* [What are HTTP requests?](https://youtu.be/-Zea7GB2OwA)
* [Build a REST API with Spring and Java Config](https://www.baeldung.com/building-a-restful-web-service-with-spring-and-java-based-configuration)
* [Exploring REST APIs with Spring MVC](https://www.developer.com/java/exploring-rest-apis-with-spring-mvc/)
* [Using Lombok’s @Builder Annotation](https://www.baeldung.com/lombok-builder)
* [Validation in Spring Boot](https://www.baeldung.com/spring-boot-bean-validation)

[controller-file]: ./api//api_app/src/main/java/com/codedifferently/lesson16/web/MediaItemsController.java
[controller-test-file]: ./api/api_app/src/test/java/com/codedifferently/lesson16/web/MediaItemsControllerTest.java
[postman-link]: https://postman.com
9 changes: 9 additions & 0 deletions lesson_16/api/.gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#
# https://help.github.com/articles/dealing-with-line-endings/
#
# Linux start script should use lf
/gradlew text eol=lf

# These are Windows script files and should use crlf
*.bat text eol=crlf

5 changes: 5 additions & 0 deletions lesson_16/api/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Ignore Gradle project-specific cache directory
.gradle

# Ignore Gradle build output directory
build
78 changes: 78 additions & 0 deletions lesson_16/api/api_app/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
plugins {
// Apply the application plugin to add support for building a CLI application in Java.
application
eclipse
id("com.diffplug.spotless") version "6.25.0"
id("org.springframework.boot") version "3.2.2"
id("com.adarshr.test-logger") version "4.0.0"
id("io.freefair.lombok") version "8.6"
}

apply(plugin = "io.spring.dependency-management")

repositories {
// Use Maven Central for resolving dependencies.
mavenCentral()
}

dependencies {
// Use JUnit Jupiter for testing.
testImplementation("com.codedifferently.instructional:instructional-lib")
testImplementation("org.junit.jupiter:junit-jupiter:5.9.1")
testImplementation("org.springframework.boot:spring-boot-starter-test")
testImplementation("org.assertj:assertj-core:3.25.1")
testImplementation("at.favre.lib:bcrypt:0.10.2")
testImplementation("org.springframework.boot:spring-boot-starter-test")

// This dependency is used by the application.
implementation("com.codedifferently.instructional:instructional-lib")
implementation("com.google.guava:guava:31.1-jre")
implementation("com.google.code.gson:gson:2.10.1")
implementation("commons-cli:commons-cli:1.6.0")
implementation("org.springframework.boot:spring-boot-starter")
implementation("org.springframework.boot:spring-boot-starter-data-jpa")
implementation("org.springframework.boot:spring-boot-starter-validation")
implementation("org.springframework.boot:spring-boot-starter-web")
compileOnly("org.springframework.boot:spring-boot-devtools")
implementation("com.opencsv:opencsv:5.9")
implementation("org.apache.commons:commons-csv:1.10.0")
implementation("org.xerial:sqlite-jdbc:3.36.0")
implementation("org.hibernate.orm:hibernate-community-dialects:6.2.7.Final")
}

application {
// Define the main class for the application.
mainClass.set("com.codedifferently.lesson16.Lesson16")
}

tasks.named<JavaExec>("run") {
standardInput = System.`in`
}

tasks.named<Test>("test") {
// Use JUnit Platform for unit tests.
useJUnitPlatform()
}


configure<com.diffplug.gradle.spotless.SpotlessExtension> {

format("misc", {
// define the files to apply `misc` to
target("*.gradle", ".gitattributes", ".gitignore")

// define the steps to apply to those files
trimTrailingWhitespace()
indentWithTabs() // or spaces. Takes an integer argument if you don't like 4
endWithNewline()
})

java {
// don't need to set target, it is inferred from java

// apply a specific flavor of google-java-format
googleJavaFormat()
// fix formatting of type annotations
formatAnnotations()
}
}
2 changes: 2 additions & 0 deletions lesson_16/api/api_app/lombok.config
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# This file is generated by the 'io.freefair.lombok' Gradle plugin
config.stopBubbling = true
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package com.codedifferently.lesson16;

import com.codedifferently.lesson16.cli.LibraryApp;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Configuration;

@Configuration
@SpringBootApplication(scanBasePackages = "com.codedifferently")
public class Lesson16 implements CommandLineRunner {
@Autowired private LibraryApp libraryApp;

public static void main(String[] args) {
var application = new SpringApplication(Lesson16.class);
application.run(args);
}

@Override
public void run(String... args) throws Exception {
// Don't run as an app if we're running as a JUnit test.
if (isJUnitTest()) {
return;
}

libraryApp.run(args);
}

private static boolean isJUnitTest() {
for (StackTraceElement element : Thread.currentThread().getStackTrace()) {
if (element.getClassName().startsWith("org.junit.")) {
return true;
}
}
return false;
}
}
Loading

0 comments on commit 41528e9

Please sign in to comment.