Skip to content

Commit

Permalink
feat(backend): add NATS (#19)
Browse files Browse the repository at this point in the history
* feat(backend): add nats

* fix: reconfigure Gradle

* fix(backend): add common modules in Dockerfile
  • Loading branch information
Kuruyia authored Dec 1, 2023
1 parent 4678367 commit 339b919
Show file tree
Hide file tree
Showing 29 changed files with 422 additions and 111 deletions.
2 changes: 2 additions & 0 deletions backend/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ ARG SERVICE_NAME
WORKDIR /app

COPY ./$SERVICE_NAME ./$SERVICE_NAME
COPY ./common ./common
COPY ./protobuf ./protobuf
COPY ./gradle ./gradle
COPY ./gradle.properties .
COPY ./gradlew .
Expand Down
88 changes: 0 additions & 88 deletions backend/api_gateway/HELP.md

This file was deleted.

13 changes: 8 additions & 5 deletions backend/api_gateway/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,14 @@ repositories {
}

dependencies {
implementation("org.springframework.boot:spring-boot-starter-actuator:3.1.5")
implementation("org.springframework.boot:spring-boot-starter-oauth2-resource-server:3.1.5")
implementation("org.springframework.boot:spring-boot-starter-security:3.1.5")
implementation("org.springframework.boot:spring-boot-starter-validation:3.1.5")
implementation("org.springframework.boot:spring-boot-starter-web:3.1.5")
implementation(project(":common"))
implementation(project(":protobuf"))
implementation("org.springframework.boot:spring-boot-starter-actuator")
implementation("org.springframework.boot:spring-boot-starter-oauth2-resource-server")
implementation("org.springframework.boot:spring-boot-starter-security")
implementation("org.springframework.boot:spring-boot-starter-validation")
implementation("org.springframework.boot:spring-boot-starter-web")
implementation("io.nats:jnats:2.17.1")
developmentOnly("org.springframework.boot:spring-boot-devtools")
testImplementation("org.springframework.boot:spring-boot-starter-test")
testImplementation("org.springframework.boot:spring-boot-testcontainers")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package com.linkedout.backend
import org.springframework.boot.SpringApplication
import org.springframework.boot.autoconfigure.SpringBootApplication

@SpringBootApplication
@SpringBootApplication(scanBasePackages = ["com.linkedout"])
open class ApiGatewayApplication

fun main(args: Array<String>) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.linkedout.backend.controller

import com.linkedout.backend.model.Job
import com.linkedout.backend.service.JobService
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RestController

@RestController
@RequestMapping("/api/v1/jobs")
open class JobsController(private val jobService: JobService) {
@GetMapping
open fun getJobs(): List<Job> {
return jobService.findAll()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.linkedout.backend.model

data class Job(
val id: String,
val title: String,
val category: String
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package com.linkedout.backend.service

import com.linkedout.backend.model.Job
import com.linkedout.common.service.NatsService
import com.linkedout.common.utils.RequestResponseFactory
import org.springframework.beans.factory.annotation.Value
import org.springframework.stereotype.Service

@Service
class JobService(private val natsService: NatsService, @Value("\${app.services.jobs.subjects.findAll}") private val findAllSubject: String) {
fun findAll(): List<Job> {
// Request jobs from the jobs service
val response = natsService.requestWithReply(findAllSubject, RequestResponseFactory.newRequest().build())

// Handle the response
if (!response.hasGetJobsResponse()) {
throw Exception("Invalid response")
}

val getJobsResponse = response.getGetJobsResponse()

return getJobsResponse.jobsList
.map { job ->
Job(job.id, job.title, job.category)
}
}
}
11 changes: 11 additions & 0 deletions backend/api_gateway/src/main/resources/application.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,14 @@ spring:

server:
port: 9090

nats:
timeout: 1000
spring:
server: nats://localhost:4222

app:
services:
jobs:
subjects:
findAll: jobs.findAll
47 changes: 47 additions & 0 deletions backend/common/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
import org.springframework.boot.gradle.tasks.bundling.BootJar

plugins {
`java-library`
id("org.springframework.boot")
id("io.spring.dependency-management")
id("org.jlleitschuh.gradle.ktlint")
kotlin("jvm")
kotlin("plugin.spring")
kotlin("plugin.jpa")
}

group = "com.linkedout"
version = "1.0.0-SNAPSHOT"

java {
sourceCompatibility = JavaVersion.VERSION_17
}

repositories {
mavenCentral()
}

dependencies {
implementation(project(":protobuf"))
implementation("org.springframework.boot:spring-boot-starter")
implementation("org.springframework:spring-messaging")
implementation("io.nats:jnats:2.17.1")
implementation("com.google.protobuf:protobuf-kotlin:3.25.0")
testImplementation("org.springframework.boot:spring-boot-starter-test")
}

tasks.withType<KotlinCompile> {
kotlinOptions {
freeCompilerArgs += "-Xjsr305=strict"
jvmTarget = "17"
}
}

tasks.withType<Test> {
useJUnitPlatform()
}

tasks.getByName<BootJar>("bootJar") {
enabled = false
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package com.linkedout.common.service

import com.linkedout.proto.RequestOuterClass.Request
import com.linkedout.proto.ResponseOuterClass.Response
import io.nats.client.Connection
import io.nats.client.Nats
import org.springframework.beans.factory.annotation.Value
import org.springframework.context.annotation.Lazy
import org.springframework.stereotype.Service
import java.time.Duration

@Service
@Lazy
class NatsService(@Value("\${nats.spring.server}") private val natsUrl: String, @Value("\${nats.timeout}") private val natsTimeout: Long) {
val nc: Connection = Nats.connect(natsUrl)
val timeout: Duration = Duration.ofMillis(natsTimeout)

fun requestWithReply(subject: String, request: Request): Response {
val rawResponse = nc.request(subject, request.toByteArray(), timeout)
val response = Response.parseFrom(rawResponse.data)

if (!response.success) {
throw Exception(response.errorMessage)
}

return response
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.linkedout.common.stream.converter

import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.messaging.converter.MessageConverter

@Configuration
class ConverterConfiguration {
@Bean
fun requestConverter(): MessageConverter {
return RequestConverter()
}

@Bean
fun responseConverter(): MessageConverter {
return ResponseConverter()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.linkedout.common.stream.converter

import com.linkedout.proto.RequestOuterClass
import org.springframework.messaging.Message
import org.springframework.messaging.converter.AbstractMessageConverter
import org.springframework.util.MimeType

class RequestConverter : AbstractMessageConverter(MimeType("application", "vnd.linkedout.proto-request")) {
override fun supports(clazz: Class<*>): Boolean {
return RequestOuterClass.Request::class.java == clazz
}

override fun convertFromInternal(message: Message<*>, targetClass: Class<*>, conversionHint: Any?): Any? {
val payload = message.payload
return payload as? RequestOuterClass.Request ?: RequestOuterClass.Request.parseFrom(payload as ByteArray)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.linkedout.common.stream.converter

import com.linkedout.proto.ResponseOuterClass
import org.springframework.messaging.MessageHeaders
import org.springframework.messaging.converter.AbstractMessageConverter
import org.springframework.util.MimeType

class ResponseConverter : AbstractMessageConverter(MimeType("application", "vnd.linkedout.proto-response")) {
override fun supports(clazz: Class<*>): Boolean {
return ResponseOuterClass.Response::class.java == clazz
}

override fun convertToInternal(payload: Any, headers: MessageHeaders?, conversionHint: Any?): Any? {
return (payload as ResponseOuterClass.Response).toByteArray()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.linkedout.common.utils

import com.linkedout.proto.RequestOuterClass
import com.linkedout.proto.ResponseOuterClass
import java.util.UUID

class RequestResponseFactory private constructor() {
companion object {
fun newRequest(): RequestOuterClass.Request.Builder {
return RequestOuterClass.Request.newBuilder()
.setRequestId(UUID.randomUUID().toString())
}

fun newSuccessfulResponse(): ResponseOuterClass.Response.Builder {
return ResponseOuterClass.Response.newBuilder()
.setSuccess(true)
}

fun newFailedResponse(message: String): ResponseOuterClass.Response.Builder {
return ResponseOuterClass.Response.newBuilder()
.setSuccess(false)
.setErrorMessage(message)
}
}
}
19 changes: 13 additions & 6 deletions backend/jobs/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -21,19 +21,26 @@ repositories {
}

dependencies {
implementation("org.springframework.boot:spring-boot-starter-actuator:3.1.5")
implementation("org.springframework.boot:spring-boot-starter-data-r2dbc:3.1.5")
implementation("org.springframework.boot:spring-boot-starter-validation:3.1.5")
implementation("org.springframework.boot:spring-boot-starter-webflux:3.1.5")
implementation("org.springframework.boot:spring-boot-starter-web:3.1.5")
implementation("org.springframework:spring-jdbc:6.0.13")
implementation(project(":common"))
implementation(project(":protobuf"))
implementation("org.springframework.boot:spring-boot-starter-actuator")
implementation("org.springframework.boot:spring-boot-starter-data-r2dbc")
implementation("org.springframework.boot:spring-boot-starter-validation")
implementation("org.springframework.boot:spring-boot-starter-webflux")
implementation("org.springframework.boot:spring-boot-starter-web")
implementation("org.springframework:spring-jdbc")
implementation("org.springframework.cloud:spring-cloud-stream:4.0.4")
implementation("io.nats:jnats:2.17.1")
implementation("io.nats:nats-spring:0.5.6")
implementation("io.nats:nats-spring-cloud-stream-binder:0.5.3")
implementation("org.flywaydb:flyway-core:9.22.3")
implementation("org.postgresql:r2dbc-postgresql:1.0.2.RELEASE")
implementation("jakarta.validation:jakarta.validation-api:3.0.2")
implementation("org.jetbrains.kotlin:kotlin-reflect:1.9.20")
developmentOnly("org.springframework.boot:spring-boot-devtools")
runtimeOnly("org.postgresql:postgresql")
testImplementation("org.springframework.boot:spring-boot-starter-test")
testImplementation("org.springframework.cloud:spring-cloud-stream-test-binder:4.0.4")
}

tasks.withType<KotlinCompile> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package com.linkedout.jobs
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication

@SpringBootApplication
@SpringBootApplication(scanBasePackages = ["com.linkedout"])
class JobsApplication

fun main(args: Array<String>) {
Expand Down
Loading

0 comments on commit 339b919

Please sign in to comment.