I'm attempting to use Vapor3 to perform raw SQL queries. The supplied documentation for this kind of thing is pretty vague on the website unfortunately.
Essentially I want to do something like:
router.get("example") { req -> Future<View> in
let leaf = try request.make(LeafRenderer.self)
// I can't get this next bit to work. Does anyone have any ideas how to do this? I seem to get all sorts of Xcode errors with .mysql, closures etc.
let users = try request.withNewConnection(to: .mysql) { connection -> EventLoopFuture<[User]>
return try connection.raw("select * from users").all(decoding: User.self)
}
var context = [String: String]()
context["user"] = users
return leaf.render("example", context)
}
Any help on want I'm doing wrong here would be greatly appreciated.
Thanks in advance,
Matt
You code was failing because you aren't implementing the closure properly. Your route returns in the let users... closure so the second return is never reached.
This works:
router.get("example")
{
insecure.get("example") {
request -> Future<View> in
return request.withNewConnection(to: .mysql) {
connection in
return connection.raw("select * from User").all(decoding: User.self).flatMap(to:View.self) {
users in
return try request.make(LeafRenderer.self).render("example",["users":users])
}
}
}
}
The changes are:
There's no need to define leaf until you need it.
The definition of users is now inside the closure.
Related
So I have a pretty normal eventListener that listens to the incoming events.
addEventListener("fetch", event => {
event.respondWith(handleRequest(event.request))
})
It goes to the handleRequest, which does certain different tasks depending on the request.url.
async function handleRequest (request) {
var url = new URL(request.url);
if (url.pathname === '[some-domain-name]/[some-link]') {
var jsonResult = handleJSON();
return jsonResult;
} else {
return handleHTML();
}
The handleJSON() and the handleHTML() are two additional functions that I have set up. What I essentially want to do is add one more if condition that has the criteria based on the response from handleJSON(), i.e., if jsonResult = [somevalidvalue] run handleHMTL() else respond with "You haven't accessed /[some-link] yet.
So to summarize, if we go to [some-domain-name] it should respond with the sentence. Then once we access /[some-link] we get some kind of value in jsonResult AFTER WHICH if we go back to [some-domain-name] it should hit with the response from handleHTML(). Also if possible, I'd like to know how can I pass the value from jsonResult in to our handleHTML() function. This is the result in the jsonResult.
const body = JSON.stringify(links, null, 2)
return new Response(body, init)
I'm sorry if the information sounds too long and stretched out. I haven't used Cloudflare's worker before and I've been trying to figure out the little stuff of what goes where and what I can and can't do with it. Thank You!
Your code implies that handleJSON() returns a Response object, since you then return it as the response to the original request. Your question is a little unclear, but it sounds like you are saying that this response contains a JSON body, and you want to inspect that body in your code. So you could do something like:
let jsonResponse = handleJSON();
if (jsonResponse.ok) { // check status code is 200
let jsonValue = await jsonRespnose.json();
if (jsonValue.someFlag) {
return handleHTML();
}
}
Note that calling jsonResponse.json() consumes the response body. Therefore, you can no longer return the response after this point. If you decide you want to return the JSON response to the client after all, you'll need to reconstruct it, like:
jsonResponse = new Respnose(JSON.stringify(jsonValue), jsonResponse);
This recreates the response body, while copying over the status and headers from the original response.
So let's say I've got a massive JSON file, and the general structure is roughly like so:
{
"apples": { complex object },
"oranges": { complex object },
"grapes": { complex object }
}
Is there some way to specifically target an object to return while using express? As in, say, if someone made a simple get request to my server, it'd return specifically the given object(s). I know the syntax and concept is completely wrong in this instance but for lack of a better way to say it, something like...
let testData = 'testdata.json';
app.get('/thing', res => {
res.json(testData.oranges);
}
I know you can return the entire file, but that adds a good amount of loading time in this instance, and is impractical in this particular case.
Or, alternatively - would it be better to have node parse the JSON file and split it into an apples.json, oranges.json, etc files to use? Trying to understand A, the best practice for doing something like this, and B, the most effective way to translate this into a practical application for a medium sized project.
Any thoughts or advice along this line - even if it's a library recommendation - would be greatly appreciated.
It should work if you make a POST request caring the payload of the specific 'thing', and then returning an object based on that thing. Example:
let testData = {
"apples": { complex object },
"oranges": { complex object },
"grapes": { complex object }
};
app.post('/route', (req, res) => {
thing = req.body.thing;
res.json(testData[thing]);
}
This is a GET request for some data and essentially since the JSON file can be used as a key/value store to query for the desired response data.
Assuming the query parameter for specifying the desired key for the object to return is part then the following example would work:
const testData = require('./testdata.json');
app.get('/thing', (req, res) => res.json(testdata[req.query.part]);
Querying for /thing?part=apples would return testdata.apples in the response.
I am now in process of switching to use json view in one of my apps built with Grails 3.3
It all looks pretty simple and here is one of my controllers:
def create(ProjectCommand command) {
if (command.validate()) {
// do something with user
Project project = projectService.create(command, springSecurityService.principal.id as Long)
if (project) {
[status: HttpStatus.CREATED, project: project]
} else {
badRequest("failed to create the project")
}
}
else {
badRequest(command.errors)
}
}
Here, I assumed that the status will be used as a response status code, but it does not.
Is there an easy way to set status code of the response without explicitly going through render?
Hmmm... that was easy.
Apparently, inside the view file itself, there is a way to almost anything.
For this particular case, it is enough to do:
response.status HttpStatus.CREATED
I hope it will be useful to someone
I'm confused on how to query the children of a model object and use it immediately. My Client contains a number of Station children
final class Client: PostgreSQLModel {
var stations: Children<Client, Station> {
return children(\.clientID)
}
}
and then in my controller I have a list of clients that I want to look at and grab their stations.
func clientIndexHandler(_ req: Request) throws -> Future<View> {
return Client.query(on: req).all().flatMap(to: View.self) { clients in
let sorted = clients.sorted { ... }
let content = try sorted.map { client in
let stations = try client.stations
.query(on: req)
.all()
.map(to: [String].self) { stations in
return stations.map { $0.name }
}
// Now I want to use the stations for other stuff.
return ClientIndexContent(client: client, stations: stations, ....)
}
let context = ClientIndexContext(clients: content)
return try req.make(LeafRenderer.self).render("clients/index", context)
}
}
My problem is that stations is an EventLoopFuture<[String]> instead of a [String]. Since I'm using Leaf here I need the actual values from the clients and stations so that I can populate the content to pass into the leaf renderer.
So you have a number of ways of doing it, but basically you need to rethink how you do things in an async world. However, Vapor does provide some nice things to help this. To start with, Leaf can actually handle futures, so if you set your ClientIndexContext to have a property of let stations: Future<[String]>, then you can just access that inside Leaf as normal.
The other option you can do is to call map(to: [String].self) on stations which will get all of the futures for you.
I would like to know, according to a job interview that I have been, how to fetch 2 differents API call - let say movie name and international language support API
how to download 2 of them together to into one table view?
thank you in advance it will help me a lot
It is Simple You have to create request chain and after getting both result reload the tableview
you have create array of dictionary from both service resposnse
For example say first will return just arrayForMovieName:["a","b","c"]
and Second will return just arrayForLanguage:["Hindi","English","etc"]
now merge this two array into your created third array of dictionary like
arrForMovieWithLanguage = [[movie:"a","language":["Hindi","English"]],[movie:"b","language":["English"]]]
Solution :1 Take boolean for both service like
var isLanguageGet:Bool = false
var isMovieGet:Bool = false
wsGetMovie()
{
isMovieGet = true
if isLanguageGet
{ self.tableView.reloadData()
}
}
wsGetLanguage()
{
isLanguageGet = true
if isMovieGet
{ self.tableView.reloadData()
}
}
Solution :2 Make webservice call sync
wsGetMovie()
{
wsGetLanguage()
}
wsGetLanguage()
{
self.tableView.reloadData()
}
You can use closure to wait asynchronously for another API response. i 'm just give you a idea of implementation. after that you can implement as per your requirement.
In my requirement it needs Euro price from first service. and after that another API need that euro price and will return Payment data. So, I achieve this scenario like below.
func getPaymentDetail(euroPrice: Double, completion: #escaping (Result<JSON>) -> Void) {
// Call second API and return result in completion closure.
if response.result.isSuccess {
completion(response.result)
}
// For failure handle here.
}
func getPriceOfEuro(rate: #escaping (Double) -> Void) {
// Here I get Euro price.
}
Then bind them in sequence like below.
getPriceOfEuro(rate: { (price) in
self.getPaymentDetail(euroPrice: price, completion: { (result) in
// Take data from result and reload Table.
})
})