Two services, their application and the program that serves them
The complete source of structure_services.ek9, compiled by the EK9 compiler. Shown on structure.html.
#!ek9 defines module site.structure.services defines component BusinessProcess as abstract process() as abstract -> detail as String <- rtn as String? StandardBusinessProcess extends BusinessProcess override process() -> detail as String <- rtn as String: `{"processed": "${detail}"}` defines function //Every operation below answers through this one response, to keep the example short. jsonResponse() as pure -> json as String <- response as HTTPResponse: (json) with trait of HTTPResponse override content() <- rtn as Bytes: Bytes().withUtf8(json) override status() as pure <- rtn as Integer: 200 override contentType() as pure <- rtn as String: "application/json" override cacheControl() as pure <- rtn as String: "no-cache" override contentLanguage() as pure <- rtn as String: "en" default operator ? defines service Addresses for :/addresses open //A GET (the default verb for a named operation) byId() for :/{address-id} -> addressId as String :=: PATH "address-id" //required because different name acceptLanguage as String :=: HEADER "Accept-Language" <- response as HTTPResponse: jsonResponse(`{"id": "${addressId}", "language": "${acceptLanguage}"}`) listByPostCode() for :/{postCode}/ -> postCode as String //Now assume PATH PARAM because there is a param acceptLanguage as String :=: HEADER "Accept-Language" <- response as HTTPResponse: jsonResponse(`{"postCode": "${postCode}", "language": "${acceptLanguage}"}`) list() for :/ -> postCode as String :=: QUERY "postCode" acceptLanguage as String :=: HEADER "Accept-Language" <- response as HTTPResponse: jsonResponse(`{"query": "${postCode}", "language": "${acceptLanguage}"}`) //A POST adds to the collection operator += for :/ -> request as HTTPRequest :=: REQUEST <- response as HTTPResponse: jsonResponse(request.content().toText("utf-8")) //A DELETE removes from it operator -= for :/{addressId} -> addressId as String <- response as HTTPResponse: jsonResponse(`{"deleted": "${addressId}"}`) //A PUT replaces a resource operator :^: for :/{addressId} -> addressId as String //assume PATH content as String :=: CONTENT <- response as HTTPResponse: jsonResponse(`{"replaced": "${addressId}", "with": ${content}}`) //merge is a PATCH operator :~: for :/{addressId} -> addressId as String //assume PATH content as String :=: CONTENT <- response as HTTPResponse: jsonResponse(`{"merged": "${addressId}", "with": ${content}}`) //Here is customer service (only partial) //But shows verbs 'GET', 'PUT' etc named explicitly Customers for :/customers open //Just get by customer identifier //i.e http(s):somehostorother.com/customers/CUST-ABCD byId() as GET for :/{customerId} -> customerId as String :=: PATH acceptLanguage as String :=: HEADER "Accept-Language" <- response as HTTPResponse: jsonResponse(`{"customer": "${customerId}", "language": "${acceptLanguage}"}`) replace() as PUT for :/{customerId} -> customerId as String :=: PATH content as String :=: CONTENT <- response as HTTPResponse: (customerId, content) with trait of HTTPResponse businessProcess as BusinessProcess! // this gets injected as a component //Now use the business process to build the response. override content() <- rtn as Bytes: Bytes().withUtf8(businessProcess.process(`${customerId} ${content}`)) override status() as pure <- rtn as Integer: 200 override contentType() as pure <- rtn as String: "application/json" override cacheControl() as pure <- rtn as String: "no-store" override contentLanguage() as pure <- rtn as String: "en" default operator ? //Application that exposes the web services to be made available. defines application CustomerAccess //Register the business component register StandardBusinessProcess() as BusinessProcess //Now register the services to be made available. register Customers() register Addresses() //A program that starts up the REST server with the configuration above defines program RestWebApp() with application of CustomerAccess stdout <- Stdout() stdout.println("Now starting REST Services") //Serve on socket port 9092, until the server is stopped. try -> server <- HTTP(NetworkProperties(9092)) server.serve()