Make Javascript tutorial compile.

This commit is contained in:
Julian K. Arni 2016-05-12 13:20:02 +02:00
parent 9e71fde756
commit 7aa550aa05
3 changed files with 105 additions and 82 deletions

View file

@ -154,33 +154,33 @@ javascript with just a simple function call to `jsForAPI` from
`Servant.JS`. `Servant.JS`.
``` haskell ``` haskell
apiJS :: Text apiJS1 :: Text
apiJS = jsForAPI api jquery apiJS1 = jsForAPI api jquery
``` ```
This `Text` contains 2 Javascript functions, 'getPoint' and 'getBooks': This `Text` contains 2 Javascript functions, 'getPoint' and 'getBooks':
``` javascript ``` javascript
var getPoint = function (onSuccess, onError)
{
$.ajax(
{ url: '/point'
, success: onSuccess
, error: onError
, method: 'GET'
});
};
var getPoint = function(onSuccess, onError)
{
$.ajax(
{ url: '/point'
, success: onSuccess
, error: onError
, type: 'GET'
});
}
var getBooks = function (q, onSuccess, onError) var getBooks = function(q, onSuccess, onError)
{ {
$.ajax( $.ajax(
{ url: '/books' + '?q=' + encodeURIComponent(q) { url: '/books' + '?q=' + encodeURIComponent(q)
, success: onSuccess , success: onSuccess
, error: onError , error: onError
, method: 'GET' , type: 'GET'
}); });
}; }
``` ```
We created a directory `static` that contains two static files: `index.html`, We created a directory `static` that contains two static files: `index.html`,
@ -192,7 +192,7 @@ write the generated javascript into a file:
``` haskell ``` haskell
writeJSFiles :: IO () writeJSFiles :: IO ()
writeJSFiles = do writeJSFiles = do
T.writeFile "static/api.js" apiJS T.writeFile "static/api.js" apiJS1
jq <- T.readFile =<< Language.Javascript.JQuery.file jq <- T.readFile =<< Language.Javascript.JQuery.file
T.writeFile "static/jq.js" jq T.writeFile "static/jq.js" jq
``` ```
@ -220,7 +220,7 @@ The `CommonGeneratorOptions` will let you define different behaviors to
change how functions are generated. Here is the definition of currently change how functions are generated. Here is the definition of currently
available options: available options:
```haskell ```haskell ignore
data CommonGeneratorOptions = CommonGeneratorOptions data CommonGeneratorOptions = CommonGeneratorOptions
{ {
-- | function generating function names -- | function generating function names
@ -249,8 +249,8 @@ Use the same code as before but simply replace the previous `apiJS` with
the following one: the following one:
``` haskell ``` haskell
apiJS :: String apiJS2 :: Text
apiJS = jsForAPI api vanillaJS apiJS2 = jsForAPI api vanillaJS
``` ```
The rest is *completely* unchanged. The rest is *completely* unchanged.
@ -259,41 +259,50 @@ The output file is a bit different, but it has the same parameters,
``` javascript ``` javascript
var getPoint = function (onSuccess, onError)
var getPoint = function(onSuccess, onError)
{ {
var xhr = new XMLHttpRequest(); var xhr = new XMLHttpRequest();
xhr.open('GET', '/point', true); xhr.open('GET', '/point', true);
xhr.setRequestHeader(\"Accept\",\"application/json\");
xhr.onreadystatechange = function (e) { xhr.onreadystatechange = function (e) {
if (xhr.readyState == 4) { if (xhr.readyState == 4) {
if (xhr.status == 204 || xhr.status == 205) {
onSuccess();
} else if (xhr.status >= 200 && xhr.status < 300) {
var value = JSON.parse(xhr.responseText); var value = JSON.parse(xhr.responseText);
if (xhr.status == 200 || xhr.status == 201) { onSuccess(value);
onSuccess(value); } else {
} else { var value = JSON.parse(xhr.responseText);
onError(value); onError(value);
} }
}
} }
xhr.send(null); }
}; xhr.send(null);
}
var getBooks = function (q, onSuccess, onError) var getBooks = function(q, onSuccess, onError)
{ {
var xhr = new XMLHttpRequest(); var xhr = new XMLHttpRequest();
xhr.open('GET', '/books' + '?q=' + encodeURIComponent(q), true); xhr.open('GET', '/books' + '?q=' + encodeURIComponent(q), true);
xhr.setRequestHeader(\"Accept\",\"application/json\");
xhr.onreadystatechange = function (e) { xhr.onreadystatechange = function (e) {
if (xhr.readyState == 4) { if (xhr.readyState == 4) {
if (xhr.status == 204 || xhr.status == 205) {
onSuccess();
} else if (xhr.status >= 200 && xhr.status < 300) {
var value = JSON.parse(xhr.responseText); var value = JSON.parse(xhr.responseText);
if (xhr.status == 200 || xhr.status == 201) { onSuccess(value);
onSuccess(value); } else {
} else { var value = JSON.parse(xhr.responseText);
onError(value); onError(value);
} }
}
} }
xhr.send(null); }
}; xhr.send(null);
}
``` ```
And that's all, your web service can of course be accessible from those And that's all, your web service can of course be accessible from those
@ -309,8 +318,8 @@ Use the same code as before but simply replace the previous `apiJS` with
the following one: the following one:
``` haskell ``` haskell
apiJS :: String apiJS3 :: Text
apiJS = jsForAPI api $ axios defAxiosOptions apiJS3 = jsForAPI api $ axios defAxiosOptions
``` ```
The rest is *completely* unchanged. The rest is *completely* unchanged.
@ -319,19 +328,23 @@ The output file is a bit different,
``` javascript ``` javascript
var getPoint = function ()
{
return axios({ url: '/point'
, method: 'get'
});
};
var getBooks = function (q) var getPoint = function()
{ {
return axios({ url: '/books' + '?q=' + encodeURIComponent(q) return axios({ url: '/point'
, method: 'get' , method: 'get'
}); });
}; }
var getBooks = function(q)
{
return axios({ url: '/books' + '?q=' + encodeURIComponent(q)
, method: 'get'
});
}
``` ```
**Caution:** In order to support the promise style of the API, there are no onSuccess **Caution:** In order to support the promise style of the API, there are no onSuccess
@ -366,8 +379,8 @@ generate top level functions.
The difference is that `angular` Generator always takes an argument. The difference is that `angular` Generator always takes an argument.
``` haskell ``` haskell
apiJS :: String apiJS4 :: Text
apiJS = jsForAPI api $ angular defAngularOptions apiJS4 = jsForAPI api $ angular defAngularOptions
``` ```
The generated code will be a bit different than previous generators. An extra The generated code will be a bit different than previous generators. An extra
@ -379,21 +392,25 @@ nor onError callback functions.
``` javascript ``` javascript
var getPoint = function($http) var getPoint = function($http)
{ {
return $http( return $http(
{ url: '/counter' { url: '/point'
, method: 'GET' , method: 'GET'
}); });
} }
var getBooks = function($http, q) var getBooks = function($http, q)
{ {
return $http( return $http(
{ url: '/books' + '?q=' + encodeURIComponent(q), true); { url: '/books' + '?q=' + encodeURIComponent(q)
, method: 'GET' , method: 'GET'
}); });
} }
``` ```
You can then build your controllers easily You can then build your controllers easily
@ -440,8 +457,8 @@ app.service('MyService', function($http) {
To do so, you just have to use an alternate generator. To do so, you just have to use an alternate generator.
``` haskell ``` haskell
apiJS :: String apiJS5 :: Text
apiJS = jsForAPI api $ angularService defAngularOptions apiJS5 = jsForAPI api $ angularService defAngularOptions
``` ```
Again, it is possible to customize some portions with the options. Again, it is possible to customize some portions with the options.
@ -468,32 +485,34 @@ Servant comes with three name builders included:
Keeping the JQuery as an example, let's see the impact: Keeping the JQuery as an example, let's see the impact:
``` haskell ``` haskell
apiJS :: String apiJS6 :: Text
apiJS = jsForAPI api $ jqueryWith defCommonGeneratorOptions { functionNameBuilder= snakeCase } apiJS6 = jsForAPI api $ jqueryWith defCommonGeneratorOptions { functionNameBuilder= snakeCase }
``` ```
This `String` contains 2 Javascript functions: This `Text` contains 2 Javascript functions:
``` javascript ``` javascript
var getPoint = function (onSuccess, onError)
var get_point = function(onSuccess, onError)
{ {
$.ajax( $.ajax(
{ url: '/point' { url: '/point'
, success: onSuccess , success: onSuccess
, error: onError , error: onError
, method: 'GET' , type: 'GET'
}); });
}; }
var getBooks = function (q, onSuccess, onError) var get_books = function(q, onSuccess, onError)
{ {
$.ajax( $.ajax(
{ url: '/books' + '?q=' + encodeURIComponent(q) { url: '/books' + '?q=' + encodeURIComponent(q)
, success: onSuccess , success: onSuccess
, error: onError , error: onError
, method: 'GET' , type: 'GET'
}); });
}; }
``` ```

View file

@ -15,7 +15,10 @@ spec = do
describe "apiJS" $ do describe "apiJS" $ do
it "is contained verbatim in Javascript.lhs" $ do it "is contained verbatim in Javascript.lhs" $ do
code <- readFile "Javascript.lhs" code <- readFile "Javascript.lhs"
cs apiJS `shouldSatisfy` (`isInfixOf` code) cs apiJS1 `shouldSatisfy` (`isInfixOf` code)
cs apiJS3 `shouldSatisfy` (`isInfixOf` code)
cs apiJS4 `shouldSatisfy` (`isInfixOf` code)
cs apiJS6 `shouldSatisfy` (`isInfixOf` code)
describe "writeJSFiles" $ do describe "writeJSFiles" $ do
it "[not a test] write apiJS to static/api.js" $ do it "[not a test] write apiJS to static/api.js" $ do
@ -24,7 +27,7 @@ spec = do
describe "app" $ with (return app) $ do describe "app" $ with (return app) $ do
context "/api.js" $ do context "/api.js" $ do
it "delivers apiJS" $ do it "delivers apiJS" $ do
get "/api.js" `shouldRespondWith` (fromString (cs apiJS)) get "/api.js" `shouldRespondWith` (fromString (cs apiJS1))
context "/" $ do context "/" $ do
it "delivers something" $ do it "delivers something" $ do

View file

@ -112,6 +112,7 @@ module Servant.JS
, javascript , javascript
, NoTypes , NoTypes
, GenerateList(..) , GenerateList(..)
, FunctionName(..)
) where ) where
import Prelude hiding (writeFile) import Prelude hiding (writeFile)