-
Notifications
You must be signed in to change notification settings - Fork 27
Working with a Headless approach
Puck is pretty flexible, you don't need to use razor views if you don't wan't to. You could instead return JSON of the current page or other queried content.
By default, there is a catch-all endpoint mapped to the HomeController
Index
action. The code for this mapping is in Startup.cs
:
endpoints.MapControllerRoute(
name: "default",
pattern: "{**path}"
,defaults: new { controller = "Home", action = "Index"}
);
HomeController
inherits from puck.core.Controllers.BaseController
and if you look at the Index
action:
public IActionResult Index()
{
return base.Puck();
}
all it does is call the inherited Puck action which will get the current page and render a view. if you wanted to go headless, you could just return the current page as JSON:
public IActionResult Index()
{
var currentPage = QueryHelper<BaseModel>.Current();
return Json(currentPage);
}
this is a simple example but in a real world scenario you'll likey want to use the QueryHelper to get multiple pieces of content and compose them into a ViewModel to return to the client. you'll also likely be calling Puck from another app, something like a single page app which contains your views or a mobile app and in this scenario you can set up your Puck project to allow cross origin requests. then your single page app hosted on a different domain can make requests to Puck and get the JSON responses.
the previous example showed you how to get Puck to return the requested page as JSON. what if you wanted to get back multiple results by search query? to set up a query endpoint, you need a controller which inherits from puck.core.Controllers.BaseController
- you could use HomeController
, for example. then you can create a Query
action:
[Route("Query")]
[HttpPost]
public IActionResult Query([FromBody]List<puck.core.Models.QueryModel> queries) {
return Json(base.Query(queries));
}
you can then post JSON requests to this endpoint, here's an example JSON request body:
[
{
"Type": "Page",
"Query": "NodeName:brexit",
"Skip": 0,
"Take": 100,
"Sorts":"SortOrder:asc"
},
{
"Type": "Page",
"Query": "+Type:Page PuckGeoM:Location.LongLat,-0.1277582,51.5073509,10,asc",
"Skip": 0,
"Take": 100
"Sorts":""
}
]
the above request body specifies two searches. each search consists of a Type
- which is the type parameter that you would normally pass to QueryHelper. the Query
parameter is a Lucene query, read this for reference. use Skip
and Take
for pagination and Sorts
accepts a comma separated string of Field:asc
or Field:desc
, e.g. "SortOrder:desc,NodeName:asc";
the equivalent of QueryHelper's ExplicitType
is specifying the type, like so; "+Type:Page".
the syntax for Geo/Spatial
queries is PuckGeoM:Location.LongLat,-0.1277582,51.5073509,10,asc
when the distance is specified in Miles and PuckGeoK:Location.LongLat,-0.1277582,51.5073509,10,asc
when specified in kilometres. the parameters are passed in comma separated with no spaces, the parameters being the Field Name
,Longitude
,Latitude
,Distance
and finally the Sort
. specify asc
,desc
or null
for Sort
values.
the results for these two queries will be returned in the format List<List<BaseModel>>
where the result contains a list of ViewModels for each query in the request.