scalaakkaakka-http

Scala Akka HTTP problem adding multiple segment variables to API URL Routes


I am building an API to track student data using Scala, Akka HTTP, and Akka Actors.

But the API Routes below are not giving me the desired result.

The routes littlerock/admins and littlerock/schools/1 work as expected, but the rest show the error The requested resource could not be found.

I want the API to look for example like below.

All district admins - GET: http://localhost:8080/littlerock/admins

A school's details - GET: http://localhost:8080/littlerock/schools/{1}

All a school's students - GET: http://localhost:8080/littlerock/schools/{1}/students

A student's details - GET: http://localhost:8080/littlerock/schools/{1}/students/{1}

All the student's classmates - GET: http://localhost:8080/littlerock/schools/{1}/students/{1}/classmates

A student's classmate details - GET: http://localhost:8080/littlerock/schools/{1}/students/{1}/classmates/{1}

Could you help me fix the issue!

Thanks in advance!

The Routes code looks like below:


  val schoolRoutes: Route =
    pathPrefix("littlerock") {
    concat(

    pathPrefix("admins") {
      concat(
        pathEnd {
          concat(
            get {
              complete("District administrators.")
            })
        })
    },

    pathPrefix("schools") {
      concat(
        path(Segment) { name =>
          concat(
            pathEnd {
            get {
              rejectEmptyResponse {
                  complete("A school's details.")
              }
            }
            },
            path("students") {
              concat(
                pathEnd {
                  get {
                    rejectEmptyResponse {
                      complete("All students")
                    }
                  }
                },
                path(Segment) { name =>
                  concat(
                    pathEnd {
                    get {
                      rejectEmptyResponse {
                        complete("A student's details")
                      }
                    }},
                    path("classmates") {
                      concat(
                        pathEnd {
                          get {
                            rejectEmptyResponse {
                              complete("A student's classmates.")
                            }
                          }
                        },
                        path(Segment) { name =>
                          concat(
                            get {
                              rejectEmptyResponse {
                                complete("A classmate's details.")
                              }
                          })
                        }
                      )
                    }
                  )
                }
              )
            }
          )
      })
    }
  )}


Solution

  • Like @johanandren suggested, I replaced all except the last path with pathPrefix.

    And the code now works!

    The Routes code now looks like below:

    
      val schoolRoutes: Route =
        pathPrefix("littlerock") {
        concat(
    
        pathPrefix("admins") {
          concat(
            pathEnd {
              concat(
                get {
                  complete("District administrators.")
                })
            })
        },
    
        pathPrefix("schools") {
          concat(
            pathPrefix(Segment) { name =>
              concat(
                pathEnd {
                get {
                  rejectEmptyResponse {
                      complete("A school's details.")
                  }
                }
                },
                pathPrefix("students") {
                  concat(
                    pathEnd {
                      get {
                        rejectEmptyResponse {
                          complete("All students")
                        }
                      }
                    },
                    pathPrefix(Segment) { studentName =>
                      concat(
                        pathEnd {
                        get {
                          rejectEmptyResponse {
                            complete("A student's details")
                          }
                        }},
                        pathPrefix("classmates") {
                          concat(
                            pathEnd {
                              get {
                                rejectEmptyResponse {
                                  complete("A student's classmates.")
                                }
                              }
                            },
                            path(Segment) { classmateName =>
                              concat(
                                get {
                                  rejectEmptyResponse {
                                    complete("A classmate's details.")
                                  }
                              })
                            }
                          )
                        }
                      )
                    }
                  )
                }
              )
          })
        }
      )}