Upgrade to Pro — share decks privately, control downloads, hide ads and more …

LIFFの説明 & Backendの話 / Introduction of LIFF and its backend

LIFFの説明 & Backendの話 / Introduction of LIFF and its backend

2019/7/25に行われたLINE Developer Meetup #56 in KYOTOでの登壇資料です
https://line.connpass.com/event/139283/

53850955f15249a1a9dc49df6113e400?s=128

LINE Developers
PRO

July 25, 2019
Tweet

Transcript

  1. LIFFの説明 & Backendの話 LINE Developer Meetup #56 Kyoto Adam Millerchip

    サーバー開発チーム
  2. ⾃自⼰己紹介 イギリス出身 
 ノーサンプトン市⽣生まれ エディンバラ⼤大学
 Software Engineering 2014年年ワーホリとして来⽇日
 LINE Fukuoka⼊入社


    主にCreators Market
 少しLINE STORE 2018年年2⽉月、LINE Kyoto転勤勤
 Clova CEK SDK (Elixir版)
 LIFF https://www.instagram.com/handluggageonly/
  3. 以前のMeetup 2017年年07 #18 福岡
 アプリで簡単にスタンプを販売で きるためのAPI開発 
 2018年年08 京都 ElixirでClovaのスキルを開発して

    みる 採⽤用の⽇日など
  4. LIFFって何?

  5. LIFF LINE Front-end Framework のBack-end

  6. LIFF 1. Use only static resources (HTML, JS, CSS…) Backend不不要

    2. Open your website inside LINE chat 3. Make REST API calls on behalf of the user • Including send messages as user
  7. Demo https://github.com/adamu/line_dm_liff

  8. Let’s try • https://developers.line.biz/ • Adam’s Demo: https://github.com/adamu/line_dm_liff • Official

    Starter: https://github.com/line/line-liff-starter
  9. How does it work? LIFF Thrift API liff id line

    access token Thrift API line access token user id Talk Server REST API user id client id scope rest access token Login Server uri liff id client_id login scopes view metadata
  10. How does it work? LIFF Thrift API liff id line

    access token Thrift API line access token user id Talk Server REST API user id client id scope rest access token Login Server uri liff id client_id login scopes view metadata OAuth2 Browser App Server
  11. How does it work? LIFF url view metatada rest access

    token Thrift API liff id line access token Thrift API line access token user id Talk Server REST API user id client id scope rest access token Login Server uri liff id client_id login scopes view metadata
  12. How does it work? LIFF Talk Server uri liff id

    client_id login scopes view metadata url view metatada rest access token Thrift API liff id line access token REST API user id client id scope rest access token Thrift API line access token user id Login Server https://example.com#access_token=foobarhoge
  13. No consent? LIFF consent required REST API user id client

    id scope consent required Thrift API liff id line access token Login Server
  14. Revoke LIFF Thrift API rest access token REST API rest

    access token Login Server line access token
  15. Kotlin • Originally Java • Now 60% Kotlin, 35% Java

    • All tests are Kotlin • All new files are Kotlin • Convert other files when possible
  16. data class User( val userId: String ) ? @Data class

    User { private String userId; } data class User( val userId: String? = null )
  17. ? Foo foo = Optional.ofNullable(app.getFoo()).orElse(Foo.DEFAULT); val foo = Optional.ofNullable(app.foo).orElse(Foo.DEFAULT) val

    foo = app.foo ?: Foo.DEFAULT
  18. Extensions? data class User( val userId: Optional<String>? ) val userId

    : String? = user.userId?.orElse(null) fun <T> Optional<T>.unwrap(): T? = orElse(null) val userId : String? = user.userId?.unwrap()
  19. Extensions val foo = restTemplate.getForObject<Foo>(url) restTemplate.getForObject( url, Foo::class.java ) fun

    getFoo(uri: URI) : Foo? = restTemplate.getForObject(uri)
  20. public static String getTokenHash(@Nullable String token) { if (token ==

    null) { return null; } try { val messageDigest = MessageDigest.getInstance(SHA256); val fullHash = messageDigest.digest(token.getBytes(StandardCharsets.UTF_8)); return Base64URL.encode(Arrays.copyOf(fullHash, fullHash.length / 2)).toString(); } catch (NoSuchAlgorithmException e) { throw new IllegalStateException("MessageDigest instantiation error", e); } } Extensions (chaining)
  21. public static String getTokenHash(@Nullable String token) { if (token ==

    null) { return null; } try { val messageDigest = MessageDigest.getInstance(SHA256); val fullHash = messageDigest.digest(token.getBytes(StandardCharsets.UTF_8)); return Base64URL.encode(Arrays.copyOf(fullHash, fullHash.length / 2)).toString(); } catch (NoSuchAlgorithmException e) { throw new IllegalStateException("MessageDigest instantiation error", e); } } Extensions (chaining) fun getTokenHash(token: String?): String? = token ?.toByteArray(StandardCharsets.UTF_8) ?.let { MessageDigest.getInstance("SHA-256").digest(it) } ?.let { Base64URL.encode(it.copyOf(it.size / 2)).toString() }
  22. Extensions (no more streams) int sum = 0; for(String string

    : strings) { sum += Integer.valueOf(string); } List<String> strings = Arrays.asList("1", "2", "3"); int sum = strings.stream().mapToInt(Integer::valueOf).sum(); val sum = strings.map(Integer::valueOf).sum()
  23. Coroutines? • Not using yet • Server makes blocking calls

    • Improvement for the future?
  24. Monitoring / Stats • Aspect Oriented Programming (AOP)
 https://www.eclipse.org/aspectj/

  25. Call Logging @Pointcut("execution (public * com.linecorp.liff.*(..))") public void liffMethods() {

    } @Slf4j @Aspect public static class LiffLoggingAspect { @Around("liffMethods()") public Object logApiCall(ProceedingJoinPoint pjp) { val info = pjp.getInfo…() Object result = pjp.proceed(); log.info("Call {}.{} took:{}us args:[{}] returns:{} ", ...); return result; } }
  26. Log Viewing

  27. Monitoring • IMON • Alerts: Email / Slack / など

    • Statistics
  28. Deployment • Github Enterprise • Maven • Jenkins • PMC

    • Ansible? Circle CI? Drone?
  29. TODO • Convert more to Kotlin + use more Kotlin

    features • Implement New Features • Concurrency / Non-Blocking • Improve Logging / Monitoring • Improved Performance Monitoring • ??
  30. ご静聴ありがとうございました