Tutorial2 - A simple web server, part 2
- Complete part1 of the tutorial.
- A basic understanding of web servers, HTTP etc.
Part2 - Creating a web service.
In this final part, we will create a web server and invoke the JSON data filtering logic we built during the previous part.
Step1 - Create a server flow - Understanding triggers
In this step, we will create a web server and send a simple "hello world"
The above animation shows how to create an HTTP server using core/http package.
We will start by creating a new flow. Call it as server.flw. Next, we will use the
core/http package to create a web server that will accept requests on the configured port. Click open the
core/http package in the packages panel and drag the
httpServer module into the canvas. Click OK in the warning dialog and
httpServer is now the starting step.
httpServer is a special type of module called as a trigger module. A trigger module will always be the first step in a flow. Such a flow, called as trigger flows, cannot be invoked by other flows, instead, they will trigger new instances on their own. One example of a trigger module is the timer module, which will repeatedly trigger a new instance after the configured time interval.
httpServer module will trigger a new instance when a request hits the configured port and/or the route(s). Let's begin by updating the port parameter in
httpServer. For the tutorial, we will use a port value of 8005. Leave the rest of the properties as it is.
Every HTTP request should be terminated with a response. To send a response back, we will drag the
httpResponse module from the
core/http package place it as the outgoing step of
httpServer. Click open the
httpResponse's input tab and set the
content property as "Hello world".
That's it. Start the flow as usual and a web server would be running on your localhost on the given port. Navigate to URL http://localhost:8005/ and you should see a "Hello world" printed in the browser window.
Step2 - Configuring the server
In this step, we will learn how to setup multiple routes in the
The above animation shows configuring routes in the httpServer module
Routes are special regular expressions that specify the pattern of requests that should be accepted by the server. To add a route, click on the routes array in
httpServer's input. Give a value "/" in the pattern field and "home" in the label field. Leave other fields as default. If you add a route,
httpServer will only listen for requests matching the given pattern.
We will add another route with a pattern "/find" and name it as "find".
Step3 - Create conditional transitions for each route
In this step, we will add conditional transitions to handle each route separately.
The above animation shows adding multiple transitions for each route.
As you noticed, when you add a route, the output schema of
httpServer automatically gets updated to include the given route as a boolean flag. During runtime, when the request is triggered for this route, the flag will be set. This can be used in any expressions including conditions for transitions. We can use a feature called as the conditional transition to channel the data flow to separate branches for each route.
To add a conditional transition, click on the transition from
httpResponse. In the configuration panel, select the type dropdown and choose the option - "Conditional - The transition will happen only... ". After choosing conditional options, a field named Condition will appear below that. Focus on the expression field for Condition and the regular expression drop down will pop up. Select Data->httpServer->routes->home from the drop down. Now the transition will happen only if the condition evaluates to true.
To handle the second route, add another
httpResponse from the
core/http package. Rename the step to
findResponse. Set its
content field to value "You requested /find". Now add a transition from
findResponse. Repeat the transition condition, this time choose the output variable -
If you execute the flow you can see that the requests are handled separately.
Step4 - Capturing HTTP query parameters
In this step, we will see how we can capture parameters from HTTP requests.
The above animation shows using query parameters.
httpServer, like any step, provides an output as defined by the output schema. In this step, we are interested in a particular one -
httpServer.output.query. Since the query parameter in the HTTP requests are dynamic, it is not available directly in the autocomplete drop down. Instead, the query object is defined as an object with extendable properties. That means you get to type whatever additional field name you expect as the HTTP query parameters.
For this tutorial, we will accept a query parameter named 'color'. Click open
findResponse and set the value of the
content field as shown below.
concat("You requested /find with color", httpServer.output.query.color)
Click run and enter a URL like
http://localhost:8005/?color=red and you should see the color printed back in the response.
Step5 - Calling a sub flow and using the return value
In this step, we will pass the query parameter to the sub flow and pipe its results back to the browser.
The above animation shows invoking the read.flw as a sub flow and piping the result back to the response.
First, we will invoke the flow read.flw created in the previous part. There are two ways to do it - Using the
core/executeFlow and passing the sub flow's path or simply drag and drop the flow file from the project tree. It will automatically create the
executeFlow module and set the path automatically.
As you can notice, the when a sub flow is called, the executeFlow module will automatically ask for the input based on the sub flow's input schema and the output of the step maps the output of the sub flow. This allows us to map the output of the sub flow in the subsequent steps inside the current flow.
The next step is to pass the query parameter color into the sub flow's input. We simply map the expression
httpServer.output.query.color into the input field color of the sub flow.
Next, we will map the output of the
read step to the content property in
Since the output of the
read step is an object, we need to convert it into a string. We can use the built-in method
stringify under JSON namespace to do that. The final expression would look like:
Pipe the output from the
read to the http response
Step6 - Starting trigger flows - Execute as project
We have covered how trigger flow works during the tutorial. Let's see how to execute trigger flows in different ways.
Start like regular flows.
Triggers can be started like regular flows. From the designer, you can simply click the Debug or the Run button. The command line version is also similar to running regular flows, except that the program will not end and return a result like a regular flow.
Start as the whole project.
If there are triggers in the project, the project can be started as a whole. To do that, Go to the main menu, Select Debug->Debug Project... The designer will try to start the whole project by scanning the given directory for any triggers and iff a trigger found, it is started automatically.
Command line version:
If you pass a folder instead of a flow file, the engine will start the whole project by starting all the trigger flows at once. This is useful for large projects with multiple background jobs and web servers.
codeflow run <project-folder>
It will start all the trigger flows and keep running until the lifetime of the triggers.
Congrats on completing the tutorial. In this section, we have covered the following concepts:
- Trigger modules.
- Creating a simple web server using
- Configuring paths.
- Conditional transitions.
- Calling sub flows.
- Executing a whole project.
We have only scratched the surface with the above basic tutorials. You can learn more about Codeflow in subsequent sections.